home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Common / DXUTgui.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  266.5 KB  |  7,864 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: DXUTgui.cpp
  3. //
  4. // Desc: 
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9.  
  10. #ifndef WM_XBUTTONDOWN
  11. #define WM_XBUTTONDOWN 0x020B // (not always defined)
  12. #endif
  13. #ifndef WM_XBUTTONUP
  14. #define WM_XBUTTONUP 0x020C // (not always defined)
  15. #endif
  16. #ifndef WM_MOUSEWHEEL
  17. #define WM_MOUSEWHEEL 0x020A // (not always defined)
  18. #endif
  19. #ifndef WHEEL_DELTA
  20. #define WHEEL_DELTA 120 // (not always defined)
  21. #endif
  22.  
  23. // Minimum scroll bar thumb size
  24. #define SCROLLBAR_MINTHUMBSIZE 8
  25.  
  26. // Delay and repeat period when clicking on the scroll bar arrows
  27. #define SCROLLBAR_ARROWCLICK_DELAY  0.33
  28. #define SCROLLBAR_ARROWCLICK_REPEAT 0.05
  29.  
  30.  
  31. // DXUT_MAX_EDITBOXLENGTH is the maximum string length allowed in edit boxes,
  32. // including the NULL terminator.
  33. // 
  34. // Uniscribe does not support strings having bigger-than-16-bits length.
  35. // This means that the string must be less than 65536 characters long,
  36. // including the NULL terminator.
  37. #define DXUT_MAX_EDITBOXLENGTH 0xFFFF
  38.  
  39.  
  40. //--------------------------------------------------------------------------------------
  41. // Global/Static Members
  42. //--------------------------------------------------------------------------------------
  43. CDXUTDialogResourceManager* DXUTGetGlobalDialogResourceManager()
  44. {
  45.     // Using an accessor function gives control of the construction order
  46.     static CDXUTDialogResourceManager manager;
  47.     return &manager;
  48. }
  49.  
  50. double        CDXUTDialog::s_fTimeRefresh = 0.0f;
  51. CDXUTControl* CDXUTDialog::s_pControlFocus = NULL;        // The control which has focus
  52. CDXUTControl* CDXUTDialog::s_pControlPressed = NULL;      // The control currently pressed
  53.  
  54.  
  55. struct DXUT_SCREEN_VERTEX
  56. {
  57.     float x, y, z, h;
  58.     D3DCOLOR color;
  59.     float tu, tv;
  60.  
  61.     static DWORD FVF;
  62. };
  63. DWORD DXUT_SCREEN_VERTEX::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;
  64.  
  65.  
  66. inline int RectWidth( RECT &rc ) { return ( (rc).right - (rc).left ); }
  67. inline int RectHeight( RECT &rc ) { return ( (rc).bottom - (rc).top ); }
  68.  
  69.  
  70. //--------------------------------------------------------------------------------------
  71. // CDXUTDialog class
  72. //--------------------------------------------------------------------------------------
  73.  
  74. //--------------------------------------------------------------------------------------
  75. CDXUTDialog::CDXUTDialog()
  76. {
  77.     m_x = 0;
  78.     m_y = 0;
  79.     m_width = 0;
  80.     m_height = 0;
  81.  
  82.     m_bCaption = false;
  83.     m_bMinimized = false;
  84.     m_wszCaption[0] = L'\0';
  85.     m_nCaptionHeight = 18;
  86.  
  87.     m_colorTopLeft = 0;
  88.     m_colorTopRight = 0;
  89.     m_colorBottomLeft = 0;
  90.     m_colorBottomRight = 0;
  91.  
  92.     m_pCallbackEvent = NULL;
  93.  
  94.     m_fTimeLastRefresh = 0;
  95.  
  96.     m_pControlMouseOver = NULL;
  97.  
  98.     m_pNextDialog = this;
  99.     m_pPrevDialog = this;
  100.  
  101.     m_nDefaultControlID = 0xffff;
  102.     m_bNonUserEvents = false;
  103.     m_bKeyboardInput = false;
  104.     m_bMouseInput = true;
  105.  
  106.     InitDefaultElements();
  107. }
  108.  
  109.  
  110. //--------------------------------------------------------------------------------------
  111. CDXUTDialog::~CDXUTDialog()
  112. {
  113.     int i=0;
  114.  
  115.     RemoveAllControls();
  116.  
  117.     m_Fonts.RemoveAll();
  118.     m_Textures.RemoveAll();
  119.  
  120.     for( i=0; i < m_DefaultElements.GetSize(); i++ )
  121.     {
  122.         DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i );
  123.         SAFE_DELETE( pElementHolder );
  124.     }
  125.  
  126.     m_DefaultElements.RemoveAll();
  127. }
  128.  
  129.  
  130. //--------------------------------------------------------------------------------------
  131. void CDXUTDialog::RemoveControl( int ID )
  132. {
  133.     for( int i=0; i < m_Controls.GetSize(); i++ )
  134.     {
  135.         CDXUTControl* pControl = m_Controls.GetAt( i );
  136.         if( pControl->GetID() == ID )
  137.         {
  138.             // Clean focus first
  139.             ClearFocus();
  140.  
  141.             // Clear references to this control
  142.             if( s_pControlFocus == pControl )
  143.                 s_pControlFocus = NULL;
  144.             if( s_pControlPressed == pControl )
  145.                 s_pControlPressed = NULL;
  146.             if( m_pControlMouseOver == pControl )
  147.                 m_pControlMouseOver = NULL;
  148.  
  149.             SAFE_DELETE( pControl );
  150.             m_Controls.Remove( i );
  151.  
  152.             return;
  153.         }
  154.     }
  155. }
  156.  
  157.  
  158. //--------------------------------------------------------------------------------------
  159. void CDXUTDialog::RemoveAllControls()
  160. {
  161.     if( s_pControlFocus && s_pControlFocus->m_pDialog == this )
  162.         s_pControlFocus = NULL;
  163.     if( s_pControlPressed && s_pControlPressed->m_pDialog == this )
  164.         s_pControlPressed = NULL;
  165.     m_pControlMouseOver = NULL;
  166.  
  167.     for( int i=0; i < m_Controls.GetSize(); i++ )
  168.     {
  169.         CDXUTControl* pControl = m_Controls.GetAt( i );
  170.         SAFE_DELETE( pControl );
  171.     }
  172.  
  173.     m_Controls.RemoveAll();
  174. }
  175.  
  176.  
  177. //--------------------------------------------------------------------------------------
  178. CDXUTDialogResourceManager::CDXUTDialogResourceManager()
  179. {
  180.     m_pd3dDevice = NULL;
  181.     m_pStateBlock = NULL;
  182.     m_pSprite = NULL;
  183. }
  184.  
  185.  
  186. //--------------------------------------------------------------------------------------
  187. CDXUTDialogResourceManager::~CDXUTDialogResourceManager()
  188. {
  189.     int i;
  190.     for( i=0; i < m_FontCache.GetSize(); i++ )
  191.     {
  192.         DXUTFontNode* pFontNode = m_FontCache.GetAt( i );
  193.         SAFE_DELETE( pFontNode );
  194.     }
  195.     m_FontCache.RemoveAll();   
  196.  
  197.     for( i=0; i < m_TextureCache.GetSize(); i++ )
  198.     {
  199.         DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i );
  200.         SAFE_DELETE( pTextureNode );
  201.     }
  202.     m_TextureCache.RemoveAll();   
  203. }
  204.  
  205.  
  206. //--------------------------------------------------------------------------------------
  207. HRESULT CDXUTDialogResourceManager::OnCreateDevice( LPDIRECT3DDEVICE9 pd3dDevice )
  208. {
  209.     HRESULT hr = S_OK;
  210.     int i=0;
  211.  
  212.     m_pd3dDevice = pd3dDevice;
  213.     
  214.     for( i=0; i < m_FontCache.GetSize(); i++ )
  215.     {
  216.         hr = CreateFont( i );
  217.         if( FAILED(hr) )
  218.             return hr;
  219.     }
  220.     
  221.     for( i=0; i < m_TextureCache.GetSize(); i++ )
  222.     {
  223.         hr = CreateTexture( i );
  224.         if( FAILED(hr) )
  225.             return hr;
  226.     }
  227.  
  228.     hr = D3DXCreateSprite( pd3dDevice, &m_pSprite );
  229.     if( FAILED(hr) )
  230.         return DXUT_ERR( L"D3DXCreateSprite", hr );
  231.  
  232.     // Call CDXUTIMEEditBox's StaticOnCreateDevice()
  233.     // to initialize certain window-dependent data.
  234.     CDXUTIMEEditBox::StaticOnCreateDevice();
  235.  
  236.     return S_OK;
  237. }
  238.  
  239.  
  240. //--------------------------------------------------------------------------------------
  241. HRESULT CDXUTDialogResourceManager::OnResetDevice()
  242. {
  243.     HRESULT hr = S_OK;
  244.  
  245.     for( int i=0; i < m_FontCache.GetSize(); i++ )
  246.     {
  247.         DXUTFontNode* pFontNode = m_FontCache.GetAt( i );
  248.  
  249.         if( pFontNode->pFont )
  250.             pFontNode->pFont->OnResetDevice();
  251.     }
  252.  
  253.     if( m_pSprite )
  254.         m_pSprite->OnResetDevice();
  255.  
  256.     IDirect3DDevice9* pd3dDevice = DXUTGetD3DDevice();
  257.  
  258.     V_RETURN( pd3dDevice->CreateStateBlock( D3DSBT_ALL, &m_pStateBlock ) );
  259.  
  260.     return S_OK;
  261. }
  262.  
  263.  
  264. //--------------------------------------------------------------------------------------
  265. void CDXUTDialogResourceManager::OnLostDevice()
  266. {
  267.     for( int i=0; i < m_FontCache.GetSize(); i++ )
  268.     {
  269.         DXUTFontNode* pFontNode = m_FontCache.GetAt( i );
  270.  
  271.         if( pFontNode->pFont )
  272.             pFontNode->pFont->OnLostDevice();
  273.     }
  274.  
  275.     if( m_pSprite )
  276.         m_pSprite->OnLostDevice();
  277.  
  278.     SAFE_RELEASE( m_pStateBlock  );
  279. }
  280.  
  281.     
  282. //--------------------------------------------------------------------------------------
  283. void CDXUTDialogResourceManager::OnDestroyDevice()
  284. {
  285.     int i=0; 
  286.  
  287.     m_pd3dDevice = NULL;
  288.  
  289.     // Release the resources but don't clear the cache, as these will need to be
  290.     // recreated if the device is recreated
  291.     for( i=0; i < m_FontCache.GetSize(); i++ )
  292.     {
  293.         DXUTFontNode* pFontNode = m_FontCache.GetAt( i );
  294.         SAFE_RELEASE( pFontNode->pFont );
  295.     }
  296.     
  297.     for( i=0; i < m_TextureCache.GetSize(); i++ )
  298.     {
  299.         DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i );
  300.         SAFE_RELEASE( pTextureNode->pTexture );
  301.     }
  302.  
  303.     SAFE_RELEASE( m_pSprite );
  304. }
  305.  
  306.  
  307. //--------------------------------------------------------------------------------------
  308. void CDXUTDialog::Refresh()
  309. {
  310.     if( s_pControlFocus )
  311.         s_pControlFocus->OnFocusOut();
  312.  
  313.     if( m_pControlMouseOver )
  314.         m_pControlMouseOver->OnMouseLeave();
  315.  
  316.     s_pControlFocus = NULL;
  317.     s_pControlPressed = NULL;
  318.     m_pControlMouseOver = NULL;
  319.  
  320.     for( int i=0; i < m_Controls.GetSize(); i++ )
  321.     {
  322.         CDXUTControl* pControl = m_Controls.GetAt(i);
  323.         pControl->Refresh();
  324.     }
  325.  
  326.     if( m_bKeyboardInput )
  327.         FocusDefaultControl();
  328. }
  329.  
  330.  
  331. //--------------------------------------------------------------------------------------
  332. HRESULT CDXUTDialog::OnRender( float fElapsedTime )
  333. {   
  334.     // See if the dialog needs to be refreshed
  335.     if( m_fTimeLastRefresh < s_fTimeRefresh )
  336.     {
  337.         m_fTimeLastRefresh = DXUTGetTime();
  338.         Refresh();
  339.     }
  340.  
  341.     DXUT_SCREEN_VERTEX vertices[4] =
  342.     {
  343.         (float)m_x,           (float)m_y,            0.5f, 1.0f, m_colorTopLeft, 0.0f, 0.5f, 
  344.         (float)m_x + m_width, (float)m_y,            0.5f, 1.0f, m_colorTopRight, 1.0f, 0.5f,
  345.         (float)m_x + m_width, (float)m_y + m_height, 0.5f, 1.0f, m_colorBottomRight, 1.0f, 1.0f, 
  346.         (float)m_x,           (float)m_y + m_height, 0.5f, 1.0f, m_colorBottomLeft, 0.0f, 1.0f, 
  347.     };
  348.  
  349.     IDirect3DDevice9* pd3dDevice = DXUTGetGlobalDialogResourceManager()->GetD3DDevice();     
  350.  
  351.     // Set up a state block here and restore it when finished drawing all the controls
  352.     DXUTGetGlobalDialogResourceManager()->m_pStateBlock->Capture();
  353.  
  354.     pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  355.     pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  356.     pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  357.     pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
  358.  
  359.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
  360.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  361.  
  362.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
  363.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
  364.  
  365.     pd3dDevice->SetVertexShader( NULL );
  366.     pd3dDevice->SetPixelShader( NULL );
  367.  
  368.     //pd3dDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0, 1.0f, 0 );
  369.     pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
  370.  
  371.     if( !m_bMinimized )
  372.     {
  373.         pd3dDevice->SetFVF( DXUT_SCREEN_VERTEX::FVF );
  374.         pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, vertices, sizeof(DXUT_SCREEN_VERTEX) );
  375.     }
  376.  
  377.  
  378.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  379.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  380.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  381.     
  382.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  383.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  384.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  385.  
  386.     pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  387.  
  388.     DXUTTextureNode* pTextureNode = GetTexture( 0 );
  389.     pd3dDevice->SetTexture( 0, pTextureNode->pTexture );
  390.  
  391.     DXUTGetGlobalDialogResourceManager()->m_pSprite->Begin( D3DXSPRITE_DONOTSAVESTATE );
  392.  
  393.     // Render the caption if it's enabled.
  394.     if( m_bCaption )
  395.     {
  396.         // DrawSprite will offset the rect down by
  397.         // m_nCaptionHeight, so adjust the rect higher
  398.         // here to negate the effect.
  399.         RECT rc = { 0, -m_nCaptionHeight, m_width, 0 };
  400.         DrawSprite( &m_CapElement, &rc );
  401.         rc.left += 5; // Make a left margin
  402.         WCHAR wszOutput[256];
  403.         wcsncpy( wszOutput, m_wszCaption, 256 );
  404.         wszOutput[255] = 0;
  405.         if( m_bMinimized )
  406.             wcsncat( wszOutput, L" (Minimized)", 256 - lstrlenW( wszOutput ) );
  407.         DrawText( wszOutput, &m_CapElement, &rc, true );
  408.     }
  409.  
  410.     // If the dialog is minimized, skip rendering
  411.     // its controls.
  412.     if( !m_bMinimized )
  413.     {
  414.         for( int i=0; i < m_Controls.GetSize(); i++ )
  415.         {
  416.             CDXUTControl* pControl = m_Controls.GetAt(i);   
  417.  
  418.             // Focused control is drawn last
  419.             if( pControl == s_pControlFocus )
  420.                 continue;
  421.  
  422.             pControl->Render( pd3dDevice, fElapsedTime );
  423.         }
  424.  
  425.         if( s_pControlFocus != NULL && s_pControlFocus->m_pDialog == this )
  426.             s_pControlFocus->Render( pd3dDevice, fElapsedTime );
  427.     }
  428.  
  429.     DXUTGetGlobalDialogResourceManager()->m_pSprite->End();
  430.  
  431.     DXUTGetGlobalDialogResourceManager()->m_pStateBlock->Apply();
  432.  
  433.     return S_OK;
  434. }
  435.  
  436.  
  437. //--------------------------------------------------------------------------------------
  438. VOID CDXUTDialog::SendEvent( UINT nEvent, bool bTriggeredByUser, CDXUTControl* pControl )
  439. {
  440.     // If no callback has been registered there's nowhere to send the event to
  441.     if( m_pCallbackEvent == NULL )
  442.         return;
  443.  
  444.     // Discard events triggered programatically if these types of events haven't been
  445.     // enabled
  446.     if( !bTriggeredByUser && !m_bNonUserEvents )
  447.         return;
  448.  
  449.     m_pCallbackEvent( nEvent, pControl->GetID(), pControl );
  450. }
  451.  
  452.  
  453. //--------------------------------------------------------------------------------------
  454. int CDXUTDialogResourceManager::AddFont( LPCWSTR strFaceName, LONG height, LONG weight )
  455. {
  456.     // See if this font already exists
  457.     for( int i=0; i < m_FontCache.GetSize(); i++ )
  458.     {
  459.         DXUTFontNode* pFontNode = m_FontCache.GetAt(i);
  460.         if( 0 == _wcsnicmp( pFontNode->strFace, strFaceName, MAX_PATH-1 ) &&
  461.             pFontNode->nHeight == height &&
  462.             pFontNode->nWeight == weight )
  463.         {
  464.             return i;
  465.         }
  466.     }
  467.  
  468.     // Add a new font and try to create it
  469.     DXUTFontNode* pNewFontNode = new DXUTFontNode();
  470.     if( pNewFontNode == NULL )
  471.         return -1;
  472.  
  473.     ZeroMemory( pNewFontNode, sizeof(DXUTFontNode) );
  474.     wcsncpy( pNewFontNode->strFace, strFaceName, MAX_PATH-1 );
  475.     pNewFontNode->nHeight = height;
  476.     pNewFontNode->nWeight = weight;
  477.     m_FontCache.Add( pNewFontNode );
  478.     
  479.     int iFont = m_FontCache.GetSize()-1;
  480.  
  481.     // If a device is available, try to create immediately
  482.     if( m_pd3dDevice )
  483.         CreateFont( iFont );
  484.  
  485.     return iFont;
  486. }
  487.  
  488.  
  489. //--------------------------------------------------------------------------------------
  490. HRESULT CDXUTDialog::SetFont( UINT index, LPCWSTR strFaceName, LONG height, LONG weight )
  491. {
  492.     // Make sure the list is at least as large as the index being set
  493.     UINT i;
  494.     for( i=m_Fonts.GetSize(); i <= index; i++ )
  495.     {
  496.         m_Fonts.Add( -1 );
  497.     }
  498.  
  499.     int iFont = DXUTGetGlobalDialogResourceManager()->AddFont( strFaceName, height, weight );
  500.     m_Fonts.SetAt( index, iFont );
  501.  
  502.     return S_OK;
  503. }
  504.  
  505.  
  506. //--------------------------------------------------------------------------------------
  507. DXUTFontNode* CDXUTDialog::GetFont( UINT index )
  508. {
  509.     if( NULL == DXUTGetGlobalDialogResourceManager() )
  510.         return NULL;
  511.     return DXUTGetGlobalDialogResourceManager()->GetFontNode( m_Fonts.GetAt( index ) );
  512. }
  513.  
  514.  
  515. //--------------------------------------------------------------------------------------
  516. int CDXUTDialogResourceManager::AddTexture( LPCWSTR strFilename )
  517. {
  518.     // See if this texture already exists
  519.     for( int i=0; i < m_TextureCache.GetSize(); i++ )
  520.     {
  521.         DXUTTextureNode* pTextureNode = m_TextureCache.GetAt(i);
  522.         if( 0 == _wcsnicmp( pTextureNode->strFilename, strFilename, MAX_PATH-1 ) )
  523.         {
  524.             return i;
  525.         }
  526.     }
  527.  
  528.     // Add a new texture and try to create it
  529.     DXUTTextureNode* pNewTextureNode = new DXUTTextureNode();
  530.     if( pNewTextureNode == NULL )
  531.         return -1;
  532.  
  533.     ZeroMemory( pNewTextureNode, sizeof(DXUTTextureNode) );
  534.     wcsncpy( pNewTextureNode->strFilename, strFilename, MAX_PATH-1 );
  535.     m_TextureCache.Add( pNewTextureNode );
  536.     
  537.     int iTexture = m_TextureCache.GetSize()-1;
  538.  
  539.     // If a device is available, try to create immediately
  540.     if( m_pd3dDevice )
  541.         CreateTexture( iTexture );
  542.  
  543.     return iTexture;
  544. }
  545.  
  546.  
  547. //--------------------------------------------------------------------------------------
  548. HRESULT CDXUTDialog::SetTexture( UINT index, LPCWSTR strFilename )
  549. {
  550.     // Make sure the list is at least as large as the index being set
  551.     for( UINT i=m_Textures.GetSize(); i <= index; i++ )
  552.     {
  553.         m_Textures.Add( -1 );
  554.     }
  555.  
  556.     int iTexture = DXUTGetGlobalDialogResourceManager()->AddTexture( strFilename );
  557.  
  558.     m_Textures.SetAt( index, iTexture );
  559.     return S_OK;
  560. }
  561.  
  562.  
  563. //--------------------------------------------------------------------------------------
  564. DXUTTextureNode* CDXUTDialog::GetTexture( UINT index )
  565. {
  566.     if( NULL == DXUTGetGlobalDialogResourceManager() )
  567.         return NULL;
  568.     return DXUTGetGlobalDialogResourceManager()->GetTextureNode( m_Textures.GetAt( index ) );
  569. }
  570.  
  571.  
  572.  
  573. //--------------------------------------------------------------------------------------
  574. bool CDXUTDialog::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  575. {
  576.     bool bHandled = false;
  577.  
  578.     // If caption is enable, check for clicks in the caption area.
  579.     if( m_bCaption )
  580.     {
  581.         static bool bDrag;
  582.  
  583.         if( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK )
  584.         {
  585.             POINT mousePoint = { short(LOWORD(lParam)), short(HIWORD(lParam)) };
  586.  
  587.             if( mousePoint.x >= m_x && mousePoint.x < m_x + m_width &&
  588.                 mousePoint.y >= m_y && mousePoint.y < m_y + m_nCaptionHeight )
  589.             {
  590.                 bDrag = true;
  591.                 SetCapture( DXUTGetHWND() );
  592.                 return true;
  593.             }
  594.         } else
  595.         if( uMsg == WM_LBUTTONUP && bDrag )
  596.         {
  597.             POINT mousePoint = { short(LOWORD(lParam)), short(HIWORD(lParam)) };
  598.  
  599.             if( mousePoint.x >= m_x && mousePoint.x < m_x + m_width &&
  600.                 mousePoint.y >= m_y && mousePoint.y < m_y + m_nCaptionHeight )
  601.             {
  602.                 ReleaseCapture();
  603.                 bDrag = false;
  604.                 m_bMinimized = !m_bMinimized;
  605.                 return true;
  606.             }
  607.         }
  608.     }
  609.  
  610.     // If the dialog is minimized, don't send any messages to controls.
  611.     if( m_bMinimized )
  612.         return false;
  613.  
  614.     // If a control is in focus, it belongs to this dialog, and it's enabled, then give
  615.     // it the first chance at handling the message.
  616.     if( s_pControlFocus && 
  617.         s_pControlFocus->m_pDialog == this && 
  618.         s_pControlFocus->GetEnabled() )
  619.     {
  620.         // If the control MsgProc handles it, then we don't.
  621.         if( s_pControlFocus->MsgProc( uMsg, wParam, lParam ) )
  622.             return true;
  623.     }
  624.  
  625.     switch( uMsg )
  626.     {
  627.         case WM_ACTIVATEAPP:
  628.             // Call OnFocusIn()/OnFocusOut() of the control that currently has the focus
  629.             // as the application is activated/deactivated.  This matches the Windows
  630.             // behavior.
  631.             if( s_pControlFocus && 
  632.                 s_pControlFocus->m_pDialog == this && 
  633.                 s_pControlFocus->GetEnabled() )
  634.             {
  635.                 if( wParam )
  636.                     s_pControlFocus->OnFocusIn();
  637.                 else
  638.                     s_pControlFocus->OnFocusOut();
  639.             }
  640.             break;
  641.  
  642.         // Keyboard messages
  643.         case WM_KEYDOWN:
  644.         case WM_SYSKEYDOWN:
  645.         case WM_KEYUP:
  646.         case WM_SYSKEYUP:
  647.         {
  648.             // If a control is in focus, it belongs to this dialog, and it's enabled, then give
  649.             // it the first chance at handling the message.
  650.             if( s_pControlFocus && 
  651.                 s_pControlFocus->m_pDialog == this && 
  652.                 s_pControlFocus->GetEnabled() )
  653.             {
  654.                 if( s_pControlFocus->HandleKeyboard( uMsg, wParam, lParam ) )
  655.                     return true;
  656.             }
  657.  
  658.             // Not yet handled, see if this matches a control's hotkey
  659.             // Activate the hotkey if the focus doesn't belong to an
  660.             // edit box.
  661.             if( uMsg == WM_KEYUP && ( !s_pControlFocus ||
  662.                                       ( s_pControlFocus->GetType() != DXUT_CONTROL_EDITBOX
  663.                                      && s_pControlFocus->GetType() != DXUT_CONTROL_IMEEDITBOX ) ) )
  664.             {
  665.                 for( int i=0; i < m_Controls.GetSize(); i++ )
  666.                 {
  667.                     CDXUTControl* pControl = m_Controls.GetAt( i );
  668.                     if( pControl->GetHotkey() == wParam )
  669.                     {
  670.                         pControl->OnHotkey();
  671.                         return true;
  672.                     }
  673.                 }
  674.             }
  675.  
  676.             // Not yet handled, check for focus messages
  677.             if( uMsg == WM_KEYDOWN )
  678.             {
  679.                 // If keyboard input is not enabled, this message should be ignored
  680.                 if( !m_bKeyboardInput )
  681.                     return false;
  682.  
  683.                 switch( wParam )
  684.                 {
  685.                     case VK_RIGHT:
  686.                     case VK_DOWN:
  687.                         if( s_pControlFocus != NULL )
  688.                         {
  689.                             OnCycleFocus( true );
  690.                             return true;
  691.                         }
  692.                         break;
  693.  
  694.                     case VK_LEFT:
  695.                     case VK_UP:
  696.                         if( s_pControlFocus != NULL )
  697.                         {
  698.                             OnCycleFocus( false );
  699.                             return true;
  700.                         }
  701.                         break;
  702.  
  703.                     case VK_TAB: 
  704.                         if( s_pControlFocus == NULL )
  705.                         {
  706.                             FocusDefaultControl();
  707.                         }
  708.                         else
  709.                         {
  710.                             bool bShiftDown = ((GetAsyncKeyState( VK_SHIFT ) & 0x8000) != 0);
  711.                             OnCycleFocus( !bShiftDown );
  712.                         }
  713.                         return true;
  714.                 }
  715.             }
  716.  
  717.             break;
  718.         }
  719.  
  720.  
  721.         // Mouse messages
  722.         case WM_MOUSEMOVE:
  723.         case WM_LBUTTONDOWN:
  724.         case WM_LBUTTONUP:
  725.         case WM_MBUTTONDOWN:
  726.         case WM_MBUTTONUP:
  727.         case WM_RBUTTONDOWN:
  728.         case WM_RBUTTONUP:
  729.         case WM_XBUTTONDOWN:
  730.         case WM_XBUTTONUP:
  731.         case WM_LBUTTONDBLCLK:
  732.         case WM_MBUTTONDBLCLK:
  733.         case WM_RBUTTONDBLCLK:
  734.         case WM_XBUTTONDBLCLK:
  735.         case WM_MOUSEWHEEL:
  736.         {
  737.             // If not accepting mouse input, return false to indicate the message should still 
  738.             // be handled by the application (usually to move the camera).
  739.             if( !m_bMouseInput )
  740.                 return false;
  741.  
  742.             POINT mousePoint = { short(LOWORD(lParam)), short(HIWORD(lParam)) };
  743.             mousePoint.x -= m_x;
  744.             mousePoint.y -= m_y;
  745.  
  746.             // If caption is enabled, offset the Y coordinate by the negative of its height.
  747.             if( m_bCaption )
  748.                 mousePoint.y -= m_nCaptionHeight;
  749.  
  750.             // If a control is in focus, it belongs to this dialog, and it's enabled, then give
  751.             // it the first chance at handling the message.
  752.             if( s_pControlFocus && 
  753.                 s_pControlFocus->m_pDialog == this && 
  754.                 s_pControlFocus->GetEnabled() )
  755.             {
  756.                 if( s_pControlFocus->HandleMouse( uMsg, mousePoint, wParam, lParam ) )
  757.                     return true;
  758.             }
  759.  
  760.             // Not yet handled, see if the mouse is over any controls
  761.             CDXUTControl* pControl = GetControlAtPoint( mousePoint );
  762.             if( pControl != NULL && pControl->GetEnabled() )
  763.             {
  764.                 bHandled = pControl->HandleMouse( uMsg, mousePoint, wParam, lParam );
  765.                 if( bHandled )
  766.                     return true;
  767.             }
  768.             else
  769.             {
  770.                 // Mouse not over any controls in this dialog, if there was a control
  771.                 // which had focus it just lost it
  772.                 if( uMsg == WM_LBUTTONDOWN && 
  773.                     s_pControlFocus && 
  774.                     s_pControlFocus->m_pDialog == this )
  775.                 {
  776.                     s_pControlFocus->OnFocusOut();
  777.                     s_pControlFocus = NULL;
  778.                 }
  779.             }
  780.  
  781.             // Still not handled, hand this off to the dialog. Return false to indicate the
  782.             // message should still be handled by the application (usually to move the camera).
  783.             switch( uMsg )
  784.             {
  785.                 case WM_MOUSEMOVE:
  786.                     OnMouseMove( mousePoint );
  787.                     return false;
  788.             }
  789.  
  790.             break;
  791.         }
  792.     }
  793.  
  794.     return false;
  795. }
  796.  
  797. //--------------------------------------------------------------------------------------
  798. CDXUTControl* CDXUTDialog::GetControlAtPoint( POINT pt )
  799. {
  800.     // Search through all child controls for the first one which
  801.     // contains the mouse point
  802.     for( int i=0; i < m_Controls.GetSize(); i++ )
  803.     {
  804.         CDXUTControl* pControl = m_Controls.GetAt(i);
  805.  
  806.         if( pControl == NULL )
  807.         {
  808.             continue;
  809.         }
  810.  
  811.         // We only return the current control if it is visible
  812.         // and enabled.  Because GetControlAtPoint() is used to do mouse
  813.         // hittest, it makes sense to perform this filtering.
  814.         if( pControl->ContainsPoint( pt ) && pControl->GetEnabled() && pControl->GetVisible() )
  815.         {
  816.             return pControl;
  817.         }
  818.     }
  819.  
  820.     return NULL;
  821. }
  822.  
  823.  
  824. //--------------------------------------------------------------------------------------
  825. bool CDXUTDialog::GetControlEnabled( int ID )
  826. {
  827.     CDXUTControl* pControl = GetControl( ID );
  828.     if( pControl == NULL )
  829.         return false;
  830.  
  831.     return pControl->GetEnabled();
  832. }
  833.  
  834.  
  835.  
  836. //--------------------------------------------------------------------------------------
  837. void CDXUTDialog::SetControlEnabled( int ID, bool bEnabled )
  838. {
  839.     CDXUTControl* pControl = GetControl( ID );
  840.     if( pControl == NULL )
  841.         return;
  842.  
  843.     pControl->SetEnabled( bEnabled );
  844. }
  845.  
  846.  
  847. //--------------------------------------------------------------------------------------
  848. void CDXUTDialog::OnMouseUp( POINT pt )
  849. {
  850.     s_pControlPressed = NULL;
  851.     m_pControlMouseOver = NULL;
  852. }
  853.  
  854. //--------------------------------------------------------------------------------------
  855. void CDXUTDialog::OnMouseMove( POINT pt )
  856. {
  857.     // Figure out which control the mouse is over now
  858.     CDXUTControl* pControl = GetControlAtPoint( pt );
  859.  
  860.     // If the mouse is still over the same control, nothing needs to be done
  861.     if( pControl == m_pControlMouseOver )
  862.         return;
  863.  
  864.     // Handle mouse leaving the old control
  865.     if( m_pControlMouseOver )
  866.         m_pControlMouseOver->OnMouseLeave();
  867.  
  868.     // Handle mouse entering the new control
  869.     m_pControlMouseOver = pControl;
  870.     if( pControl != NULL )
  871.         m_pControlMouseOver->OnMouseEnter();
  872. }
  873.  
  874.  
  875. //--------------------------------------------------------------------------------------
  876. HRESULT CDXUTDialog::SetDefaultElement( UINT nControlType, UINT iElement, CDXUTElement* pElement )
  877. {
  878.     // If this Element type already exist in the list, simply update the stored Element
  879.     for( int i=0; i < m_DefaultElements.GetSize(); i++ )
  880.     {
  881.         DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i );
  882.         
  883.         if( pElementHolder->nControlType == nControlType &&
  884.             pElementHolder->iElement == iElement )
  885.         {
  886.             pElementHolder->Element = *pElement;
  887.             return S_OK;
  888.         }
  889.     }
  890.  
  891.     // Otherwise, add a new entry
  892.     DXUTElementHolder* pNewHolder;
  893.     pNewHolder = new DXUTElementHolder;
  894.     if( pNewHolder == NULL )
  895.         return E_OUTOFMEMORY;
  896.  
  897.     pNewHolder->nControlType = nControlType;
  898.     pNewHolder->iElement = iElement;
  899.     pNewHolder->Element = *pElement;
  900.  
  901.     m_DefaultElements.Add( pNewHolder );
  902.     return S_OK;
  903. }
  904.  
  905.  
  906. //--------------------------------------------------------------------------------------
  907. CDXUTElement* CDXUTDialog::GetDefaultElement( UINT nControlType, UINT iElement )
  908. {
  909.     for( int i=0; i < m_DefaultElements.GetSize(); i++ )
  910.     {
  911.         DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i );
  912.         
  913.         if( pElementHolder->nControlType == nControlType &&
  914.             pElementHolder->iElement == iElement )
  915.         {
  916.             return &pElementHolder->Element;
  917.         }
  918.     }
  919.     
  920.     return NULL;
  921. }
  922.  
  923.  
  924.  
  925. //--------------------------------------------------------------------------------------
  926. HRESULT CDXUTDialog::AddStatic( int ID, LPCWSTR strText, int x, int y, int width, int height, bool bIsDefault, CDXUTStatic** ppCreated )
  927. {
  928.     HRESULT hr = S_OK;
  929.  
  930.     CDXUTStatic* pStatic = new CDXUTStatic( this );
  931.  
  932.     if( ppCreated != NULL )
  933.         *ppCreated = pStatic;
  934.  
  935.     if( pStatic == NULL )
  936.         return E_OUTOFMEMORY;
  937.  
  938.     hr = AddControl( pStatic );
  939.     if( FAILED(hr) )
  940.         return hr;
  941.  
  942.     // Set the ID and list index
  943.     pStatic->SetID( ID ); 
  944.     pStatic->SetText( strText );
  945.     pStatic->SetLocation( x, y );
  946.     pStatic->SetSize( width, height );
  947.     pStatic->m_bIsDefault = bIsDefault;
  948.  
  949.     return S_OK;
  950. }
  951.  
  952.  
  953. //--------------------------------------------------------------------------------------
  954. HRESULT CDXUTDialog::AddButton( int ID, LPCWSTR strText, int x, int y, int width, int height, UINT nHotkey, bool bIsDefault, CDXUTButton** ppCreated )
  955. {
  956.     HRESULT hr = S_OK;
  957.  
  958.     CDXUTButton* pButton = new CDXUTButton( this );
  959.  
  960.     if( ppCreated != NULL )
  961.         *ppCreated = pButton;
  962.  
  963.     if( pButton == NULL )
  964.         return E_OUTOFMEMORY;
  965.  
  966.     hr = AddControl( pButton );
  967.     if( FAILED(hr) )
  968.         return hr;
  969.  
  970.     // Set the ID and list index
  971.     pButton->SetID( ID ); 
  972.     pButton->SetText( strText );
  973.     pButton->SetLocation( x, y );
  974.     pButton->SetSize( width, height );
  975.     pButton->SetHotkey( nHotkey );
  976.     pButton->m_bIsDefault = bIsDefault;
  977.  
  978.     return S_OK;
  979. }
  980.  
  981.  
  982. //--------------------------------------------------------------------------------------
  983. HRESULT CDXUTDialog::AddCheckBox( int ID, LPCWSTR strText, int x, int y, int width, int height, bool bChecked, UINT nHotkey, bool bIsDefault, CDXUTCheckBox** ppCreated )
  984. {
  985.     HRESULT hr = S_OK;
  986.  
  987.     CDXUTCheckBox* pCheckBox = new CDXUTCheckBox( this );
  988.  
  989.     if( ppCreated != NULL )
  990.         *ppCreated = pCheckBox;
  991.  
  992.     if( pCheckBox == NULL )
  993.         return E_OUTOFMEMORY;
  994.  
  995.     hr = AddControl( pCheckBox );
  996.     if( FAILED(hr) )
  997.         return hr;
  998.  
  999.     // Set the ID and list index
  1000.     pCheckBox->SetID( ID ); 
  1001.     pCheckBox->SetText( strText );
  1002.     pCheckBox->SetLocation( x, y );
  1003.     pCheckBox->SetSize( width, height );
  1004.     pCheckBox->SetHotkey( nHotkey );
  1005.     pCheckBox->m_bIsDefault = bIsDefault;
  1006.     pCheckBox->SetChecked( bChecked );
  1007.     
  1008.     return S_OK;
  1009. }
  1010.  
  1011.  
  1012.  
  1013. //--------------------------------------------------------------------------------------
  1014. HRESULT CDXUTDialog::AddRadioButton( int ID, UINT nButtonGroup, LPCWSTR strText, int x, int y, int width, int height, bool bChecked, UINT nHotkey, bool bIsDefault, CDXUTRadioButton** ppCreated )
  1015. {
  1016.     HRESULT hr = S_OK;
  1017.  
  1018.     CDXUTRadioButton* pRadioButton = new CDXUTRadioButton( this );
  1019.  
  1020.     if( ppCreated != NULL )
  1021.         *ppCreated = pRadioButton;
  1022.  
  1023.     if( pRadioButton == NULL )
  1024.         return E_OUTOFMEMORY;
  1025.  
  1026.     hr = AddControl( pRadioButton );
  1027.     if( FAILED(hr) )
  1028.         return hr;
  1029.  
  1030.     // Set the ID and list index
  1031.     pRadioButton->SetID( ID ); 
  1032.     pRadioButton->SetText( strText );
  1033.     pRadioButton->SetButtonGroup( nButtonGroup );
  1034.     pRadioButton->SetLocation( x, y );
  1035.     pRadioButton->SetSize( width, height );
  1036.     pRadioButton->SetHotkey( nHotkey );
  1037.     pRadioButton->SetChecked( bChecked );
  1038.     pRadioButton->m_bIsDefault = bIsDefault;
  1039.     pRadioButton->SetChecked( bChecked );
  1040.  
  1041.     return S_OK;
  1042. }
  1043.  
  1044.  
  1045.  
  1046.  
  1047. //--------------------------------------------------------------------------------------
  1048. HRESULT CDXUTDialog::AddComboBox( int ID, int x, int y, int width, int height, UINT nHotkey, bool bIsDefault, CDXUTComboBox** ppCreated )
  1049. {
  1050.     HRESULT hr = S_OK;
  1051.  
  1052.     CDXUTComboBox* pComboBox = new CDXUTComboBox( this );
  1053.  
  1054.     if( ppCreated != NULL )
  1055.         *ppCreated = pComboBox;
  1056.  
  1057.     if( pComboBox == NULL )
  1058.         return E_OUTOFMEMORY;
  1059.  
  1060.     hr = AddControl( pComboBox );
  1061.     if( FAILED(hr) )
  1062.         return hr;
  1063.  
  1064.     // Set the ID and list index
  1065.     pComboBox->SetID( ID ); 
  1066.     pComboBox->SetLocation( x, y );
  1067.     pComboBox->SetSize( width, height );
  1068.     pComboBox->SetHotkey( nHotkey );
  1069.     pComboBox->m_bIsDefault = bIsDefault;
  1070.  
  1071.     return S_OK;
  1072. }
  1073.  
  1074.  
  1075.  
  1076. //--------------------------------------------------------------------------------------
  1077. HRESULT CDXUTDialog::AddSlider( int ID, int x, int y, int width, int height, int min, int max, int value, bool bIsDefault, CDXUTSlider** ppCreated )
  1078. {
  1079.     HRESULT hr = S_OK;
  1080.  
  1081.     CDXUTSlider* pSlider = new CDXUTSlider( this );
  1082.  
  1083.     if( ppCreated != NULL )
  1084.         *ppCreated = pSlider;
  1085.  
  1086.     if( pSlider == NULL )
  1087.         return E_OUTOFMEMORY;
  1088.  
  1089.     hr = AddControl( pSlider );
  1090.     if( FAILED(hr) )
  1091.         return hr;
  1092.  
  1093.     // Set the ID and list index
  1094.     pSlider->SetID( ID ); 
  1095.     pSlider->SetLocation( x, y );
  1096.     pSlider->SetSize( width, height );
  1097.     pSlider->m_bIsDefault = bIsDefault;
  1098.     pSlider->SetRange( min, max );
  1099.     pSlider->SetValue( value );
  1100.  
  1101.     return S_OK;
  1102. }
  1103.  
  1104.  
  1105.  
  1106. //--------------------------------------------------------------------------------------
  1107. HRESULT CDXUTDialog::AddEditBox( int ID, LPCWSTR strText, int x, int y, int width, int height, bool bIsDefault, CDXUTEditBox** ppCreated )
  1108. {
  1109.     HRESULT hr = S_OK;
  1110.  
  1111.     CDXUTEditBox *pEditBox = new CDXUTEditBox( this );
  1112.  
  1113.     if( ppCreated != NULL )
  1114.         *ppCreated = pEditBox;
  1115.  
  1116.     if( pEditBox == NULL )
  1117.         return E_OUTOFMEMORY;
  1118.  
  1119.     hr = AddControl( pEditBox );
  1120.     if( FAILED(hr) )
  1121.         return hr;
  1122.  
  1123.     // Set the ID and position
  1124.     pEditBox->SetID( ID ); 
  1125.     pEditBox->SetLocation( x, y );
  1126.     pEditBox->SetSize( width, height );
  1127.     pEditBox->m_bIsDefault = bIsDefault;
  1128.  
  1129.     if( strText )
  1130.         pEditBox->SetText( strText );
  1131.  
  1132.     return S_OK;
  1133. }
  1134.  
  1135.  
  1136.  
  1137. //--------------------------------------------------------------------------------------
  1138. HRESULT CDXUTDialog::AddIMEEditBox( int ID, LPCWSTR strText, int x, int y, int width, int height, bool bIsDefault, CDXUTIMEEditBox** ppCreated )
  1139. {
  1140.     HRESULT hr = S_OK;
  1141.     CDXUTIMEEditBox *pEditBox = new CDXUTIMEEditBox( this );
  1142.  
  1143.     if( ppCreated != NULL )
  1144.         *ppCreated = pEditBox;
  1145.  
  1146.     if( pEditBox == NULL )
  1147.         return E_OUTOFMEMORY;
  1148.  
  1149.     hr = AddControl( pEditBox );
  1150.     if( FAILED(hr) )
  1151.         return hr;
  1152.  
  1153.     // Set the ID and position
  1154.     pEditBox->SetID( ID ); 
  1155.     pEditBox->SetLocation( x, y );
  1156.     pEditBox->SetSize( width, height );
  1157.     pEditBox->m_bIsDefault = bIsDefault;
  1158.  
  1159.     if( strText )
  1160.         pEditBox->SetText( strText );
  1161.  
  1162.     return S_OK;
  1163. }
  1164.  
  1165.  
  1166.  
  1167. //--------------------------------------------------------------------------------------
  1168. HRESULT CDXUTDialog::AddListBox( int ID, int x, int y, int width, int height, DWORD dwStyle, CDXUTListBox** ppCreated )
  1169. {
  1170.     HRESULT hr = S_OK;
  1171.     CDXUTListBox *pListBox = new CDXUTListBox( this );
  1172.  
  1173.     if( ppCreated != NULL )
  1174.         *ppCreated = pListBox;
  1175.  
  1176.     if( pListBox == NULL )
  1177.         return E_OUTOFMEMORY;
  1178.  
  1179.     hr = AddControl( pListBox );
  1180.     if( FAILED(hr) )
  1181.         return hr;
  1182.  
  1183.     // Set the ID and position
  1184.     pListBox->SetID( ID );
  1185.     pListBox->SetLocation( x, y );
  1186.     pListBox->SetSize( width, height );
  1187.     pListBox->SetStyle( dwStyle );
  1188.  
  1189.     return S_OK;
  1190. }
  1191.  
  1192.  
  1193.  
  1194. //--------------------------------------------------------------------------------------
  1195. HRESULT CDXUTDialog::InitControl( CDXUTControl* pControl )
  1196. {
  1197.     HRESULT hr;
  1198.  
  1199.     if( pControl == NULL )
  1200.         return E_INVALIDARG;
  1201.  
  1202.     pControl->m_Index = m_Controls.GetSize();
  1203.     
  1204.     // Look for a default Element entries
  1205.     for( int i=0; i < m_DefaultElements.GetSize(); i++ )
  1206.     {
  1207.         DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i );
  1208.         if( pElementHolder->nControlType == pControl->GetType() )
  1209.             pControl->SetElement( pElementHolder->iElement, &pElementHolder->Element );
  1210.     }
  1211.  
  1212.     V_RETURN( pControl->OnInit() );
  1213.  
  1214.     return S_OK;
  1215. }
  1216.  
  1217.  
  1218.  
  1219. //--------------------------------------------------------------------------------------
  1220. HRESULT CDXUTDialog::AddControl( CDXUTControl* pControl )
  1221. {
  1222.     HRESULT hr = S_OK;
  1223.  
  1224.     hr = InitControl( pControl );
  1225.     if( FAILED(hr) )
  1226.         return DXTRACE_ERR( L"CDXUTDialog::InitControl", hr );
  1227.  
  1228.     // Add to the list
  1229.     hr = m_Controls.Add( pControl );
  1230.     if( FAILED(hr) )
  1231.     {
  1232.         return DXTRACE_ERR( L"CGrowableArray::Add", hr );
  1233.     }
  1234.  
  1235.     return S_OK;
  1236. }
  1237.  
  1238.  
  1239. //--------------------------------------------------------------------------------------
  1240. CDXUTControl* CDXUTDialog::GetControl( int ID )
  1241. {
  1242.     // Try to find the control with the given ID
  1243.     for( int i=0; i < m_Controls.GetSize(); i++ )
  1244.     {
  1245.         CDXUTControl* pControl = m_Controls.GetAt( i );
  1246.  
  1247.         if( pControl->GetID() == ID )
  1248.         {
  1249.             return pControl;
  1250.         }
  1251.     }
  1252.  
  1253.     // Not found
  1254.     return NULL;
  1255. }
  1256.  
  1257.  
  1258.  
  1259. //--------------------------------------------------------------------------------------
  1260. CDXUTControl* CDXUTDialog::GetControl( int ID, UINT nControlType )
  1261. {
  1262.     // Try to find the control with the given ID
  1263.     for( int i=0; i < m_Controls.GetSize(); i++ )
  1264.     {
  1265.         CDXUTControl* pControl = m_Controls.GetAt( i );
  1266.  
  1267.         if( pControl->GetID() == ID && pControl->GetType() == nControlType )
  1268.         {
  1269.             return pControl;
  1270.         }
  1271.     }
  1272.  
  1273.     // Not found
  1274.     return NULL;
  1275. }
  1276.  
  1277.  
  1278.  
  1279. //--------------------------------------------------------------------------------------
  1280. CDXUTControl* CDXUTDialog::GetNextControl( CDXUTControl* pControl )
  1281. {
  1282.     int index = pControl->m_Index + 1;
  1283.  
  1284.     CDXUTDialog* pDialog = pControl->m_pDialog;
  1285.     
  1286.     // Cycle through dialogs in the loop to find the next control. Note
  1287.     // that if only one control exists in all looped dialogs it will
  1288.     // be the returned 'next' control.
  1289.     while( index >= (int) pDialog->m_Controls.GetSize() )
  1290.     {
  1291.         pDialog = pDialog->m_pNextDialog;
  1292.         index = 0;
  1293.     }
  1294.     
  1295.     return pDialog->m_Controls.GetAt( index );    
  1296. }
  1297.  
  1298. //--------------------------------------------------------------------------------------
  1299. CDXUTControl* CDXUTDialog::GetPrevControl( CDXUTControl* pControl )
  1300. {
  1301.     int index = pControl->m_Index - 1;
  1302.  
  1303.     CDXUTDialog* pDialog = pControl->m_pDialog;
  1304.     
  1305.     // Cycle through dialogs in the loop to find the next control. Note
  1306.     // that if only one control exists in all looped dialogs it will
  1307.     // be the returned 'previous' control.
  1308.     while( index < 0 )
  1309.     {
  1310.         pDialog = pDialog->m_pPrevDialog;
  1311.         if( pDialog == NULL )
  1312.             pDialog = pControl->m_pDialog;
  1313.  
  1314.         index = pDialog->m_Controls.GetSize() - 1;
  1315.     }
  1316.     
  1317.     return pDialog->m_Controls.GetAt( index );    
  1318. }
  1319.  
  1320.  
  1321. //--------------------------------------------------------------------------------------
  1322. void CDXUTDialog::ClearRadioButtonGroup( UINT nButtonGroup )
  1323. {
  1324.     // Find all radio buttons with the given group number
  1325.     for( int i=0; i < m_Controls.GetSize(); i++ )
  1326.     {
  1327.         CDXUTControl* pControl = m_Controls.GetAt( i );
  1328.  
  1329.         if( pControl->GetType() == DXUT_CONTROL_RADIOBUTTON )
  1330.         {
  1331.             CDXUTRadioButton* pRadioButton = (CDXUTRadioButton*) pControl;
  1332.  
  1333.             if( pRadioButton->GetButtonGroup() == nButtonGroup )
  1334.                 pRadioButton->SetChecked( false, false );
  1335.         }
  1336.     }
  1337. }
  1338.  
  1339.  
  1340.  
  1341. //--------------------------------------------------------------------------------------
  1342. void CDXUTDialog::ClearComboBox( int ID )
  1343. {
  1344.     CDXUTComboBox* pComboBox = GetComboBox( ID );
  1345.     if( pComboBox == NULL )
  1346.         return;
  1347.  
  1348.     pComboBox->RemoveAllItems();
  1349. }
  1350.  
  1351.  
  1352.  
  1353.  
  1354. //--------------------------------------------------------------------------------------
  1355. void CDXUTDialog::RequestFocus( CDXUTControl* pControl )
  1356. {
  1357.     if( s_pControlFocus == pControl )
  1358.         return;
  1359.  
  1360.     if( !pControl->CanHaveFocus() )
  1361.         return;
  1362.  
  1363.     if( s_pControlFocus )
  1364.         s_pControlFocus->OnFocusOut();
  1365.  
  1366.     pControl->OnFocusIn();
  1367.     s_pControlFocus = pControl;
  1368. }
  1369.  
  1370.  
  1371. //--------------------------------------------------------------------------------------
  1372. HRESULT CDXUTDialog::DrawRect( RECT* pRect, D3DCOLOR color )
  1373. {
  1374.     RECT rcScreen = *pRect;
  1375.     OffsetRect( &rcScreen, m_x, m_y );
  1376.  
  1377.     // If caption is enabled, offset the Y position by its height.
  1378.     if( m_bCaption )
  1379.         OffsetRect( &rcScreen, 0, m_nCaptionHeight );
  1380.  
  1381.     DXUT_SCREEN_VERTEX vertices[4] =
  1382.     {
  1383.         (float) rcScreen.left -0.5f,  (float) rcScreen.top -0.5f,    0.5f, 1.0f, color, 0, 0,
  1384.         (float) rcScreen.right -0.5f, (float) rcScreen.top -0.5f,    0.5f, 1.0f, color, 0, 0, 
  1385.         (float) rcScreen.right -0.5f, (float) rcScreen.bottom -0.5f, 0.5f, 1.0f, color, 0, 0, 
  1386.         (float) rcScreen.left -0.5f,  (float) rcScreen.bottom -0.5f, 0.5f, 1.0f, color, 0, 0,
  1387.     };
  1388.  
  1389.     IDirect3DDevice9* pd3dDevice = DXUTGetGlobalDialogResourceManager()->GetD3DDevice();
  1390.  
  1391.     // Since we're doing our own drawing here we need to flush the sprites
  1392.     DXUTGetGlobalDialogResourceManager()->m_pSprite->Flush();
  1393.     IDirect3DVertexDeclaration9 *pDecl = NULL;
  1394.     pd3dDevice->GetVertexDeclaration( &pDecl );  // Preserve the sprite's current vertex decl
  1395.     pd3dDevice->SetFVF( DXUT_SCREEN_VERTEX::FVF );
  1396.  
  1397.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
  1398.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
  1399.  
  1400.     pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, vertices, sizeof(DXUT_SCREEN_VERTEX) );
  1401.  
  1402.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  1403.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  1404.  
  1405.     // Restore the vertex decl
  1406.     pd3dDevice->SetVertexDeclaration( pDecl );
  1407.     pDecl->Release();
  1408.  
  1409.     return S_OK;
  1410. }
  1411.  
  1412.  
  1413. //--------------------------------------------------------------------------------------
  1414. HRESULT CDXUTDialog::DrawPolyLine( POINT* apPoints, UINT nNumPoints, D3DCOLOR color )
  1415. {
  1416.     DXUT_SCREEN_VERTEX* vertices = new DXUT_SCREEN_VERTEX[ nNumPoints ];
  1417.     if( vertices == NULL )
  1418.         return E_OUTOFMEMORY;
  1419.  
  1420.     DXUT_SCREEN_VERTEX* pVertex = vertices;
  1421.     POINT* pt = apPoints;
  1422.     for( UINT i=0; i < nNumPoints; i++ )
  1423.     {
  1424.         pVertex->x = m_x + (float) pt->x;
  1425.         pVertex->y = m_y + (float) pt->y;
  1426.         pVertex->z = 0.5f;
  1427.         pVertex->h = 1.0f;
  1428.         pVertex->color = color;
  1429.         pVertex->tu = 0.0f;
  1430.         pVertex->tv = 0.0f;
  1431.  
  1432.         pVertex++;
  1433.         pt++;
  1434.     }
  1435.  
  1436.     IDirect3DDevice9* pd3dDevice = DXUTGetGlobalDialogResourceManager()->GetD3DDevice();
  1437.  
  1438.     // Since we're doing our own drawing here we need to flush the sprites
  1439.     DXUTGetGlobalDialogResourceManager()->m_pSprite->Flush();
  1440.     IDirect3DVertexDeclaration9 *pDecl = NULL;
  1441.     pd3dDevice->GetVertexDeclaration( &pDecl );  // Preserve the sprite's current vertex decl
  1442.     pd3dDevice->SetFVF( DXUT_SCREEN_VERTEX::FVF );
  1443.  
  1444.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
  1445.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
  1446.  
  1447.     pd3dDevice->DrawPrimitiveUP( D3DPT_LINESTRIP, nNumPoints - 1, vertices, sizeof(DXUT_SCREEN_VERTEX) );
  1448.  
  1449.     pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  1450.     pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  1451.  
  1452.     // Restore the vertex decl
  1453.     pd3dDevice->SetVertexDeclaration( pDecl );
  1454.     pDecl->Release();
  1455.  
  1456.     SAFE_DELETE_ARRAY( vertices );
  1457.     return S_OK;
  1458. }
  1459.  
  1460.  
  1461.  
  1462. //--------------------------------------------------------------------------------------
  1463. HRESULT CDXUTDialog::DrawSprite( CDXUTElement* pElement, RECT* prcDest )
  1464. {
  1465.     // No need to draw fully transparent layers
  1466.     if( pElement->TextureColor.Current.a == 0 )
  1467.         return S_OK;
  1468.  
  1469.     RECT rcTexture = pElement->rcTexture;
  1470.     
  1471.     RECT rcScreen = *prcDest;
  1472.     OffsetRect( &rcScreen, m_x, m_y );
  1473.  
  1474.     // If caption is enabled, offset the Y position by its height.
  1475.     if( m_bCaption )
  1476.         OffsetRect( &rcScreen, 0, m_nCaptionHeight );
  1477.  
  1478.     DXUTTextureNode* pTextureNode = GetTexture( pElement->iTexture );
  1479.     
  1480.     float fScaleX = (float) RectWidth( rcScreen ) / RectWidth( rcTexture );
  1481.     float fScaleY = (float) RectHeight( rcScreen ) / RectHeight( rcTexture );
  1482.  
  1483.     D3DXMATRIXA16 matTransform;
  1484.     D3DXMatrixScaling( &matTransform, fScaleX, fScaleY, 1.0f );
  1485.  
  1486.     DXUTGetGlobalDialogResourceManager()->m_pSprite->SetTransform( &matTransform );
  1487.     
  1488.     D3DXVECTOR3 vPos( (float)rcScreen.left, (float)rcScreen.top, 0.0f );
  1489.  
  1490.     vPos.x /= fScaleX;
  1491.     vPos.y /= fScaleY;
  1492.  
  1493.     return DXUTGetGlobalDialogResourceManager()->m_pSprite->Draw( pTextureNode->pTexture, &rcTexture, NULL, &vPos, pElement->TextureColor.Current );
  1494. }
  1495.  
  1496.  
  1497. //--------------------------------------------------------------------------------------
  1498. HRESULT CDXUTDialog::CalcTextRect( LPCWSTR strText, CDXUTElement* pElement, RECT* prcDest, int nCount )
  1499. {
  1500.     HRESULT hr = S_OK;
  1501.  
  1502.     DXUTFontNode* pFontNode = GetFont( pElement->iFont );
  1503.     DWORD dwTextFormat = pElement->dwTextFormat | DT_CALCRECT;
  1504.     // Since we are only computing the rectangle, we don't need a sprite.
  1505.     hr = pFontNode->pFont->DrawText( NULL, strText, nCount, prcDest, dwTextFormat, pElement->FontColor.Current );
  1506.     if( FAILED(hr) )
  1507.         return hr;
  1508.  
  1509.     return S_OK;
  1510. }
  1511.  
  1512.  
  1513. //--------------------------------------------------------------------------------------
  1514. HRESULT CDXUTDialog::DrawText( LPCWSTR strText, CDXUTElement* pElement, RECT* prcDest, bool bShadow, int nCount )
  1515. {
  1516.     HRESULT hr = S_OK;
  1517.  
  1518.     // No need to draw fully transparent layers
  1519.     if( pElement->FontColor.Current.a == 0 )
  1520.         return S_OK;
  1521.  
  1522.     RECT rcScreen = *prcDest;
  1523.     OffsetRect( &rcScreen, m_x, m_y );
  1524.  
  1525.     // If caption is enabled, offset the Y position by its height.
  1526.     if( m_bCaption )
  1527.         OffsetRect( &rcScreen, 0, m_nCaptionHeight );
  1528.  
  1529.     //debug
  1530.     //DrawRect( &rcScreen, D3DCOLOR_ARGB(100, 255, 0, 0) );
  1531.  
  1532.     D3DXMATRIXA16 matTransform;
  1533.     D3DXMatrixIdentity( &matTransform );
  1534.     DXUTGetGlobalDialogResourceManager()->m_pSprite->SetTransform( &matTransform );
  1535.  
  1536.     DXUTFontNode* pFontNode = GetFont( pElement->iFont );
  1537.     
  1538.     if( bShadow )
  1539.     {
  1540.         RECT rcShadow = rcScreen;
  1541.         OffsetRect( &rcShadow, 1, 1 );
  1542.         hr = pFontNode->pFont->DrawText( DXUTGetGlobalDialogResourceManager()->m_pSprite, strText, nCount, &rcShadow, pElement->dwTextFormat, D3DCOLOR_ARGB(DWORD(pElement->FontColor.Current.a * 255), 0, 0, 0) );
  1543.         if( FAILED(hr) )
  1544.             return hr;
  1545.     }
  1546.  
  1547.     hr = pFontNode->pFont->DrawText( DXUTGetGlobalDialogResourceManager()->m_pSprite, strText, nCount, &rcScreen, pElement->dwTextFormat, pElement->FontColor.Current );
  1548.     if( FAILED(hr) )
  1549.         return hr;
  1550.  
  1551.     return S_OK;
  1552. }
  1553.  
  1554.  
  1555. //--------------------------------------------------------------------------------------
  1556. void CDXUTDialog::SetBackgroundColors( D3DCOLOR colorTopLeft, D3DCOLOR colorTopRight, D3DCOLOR colorBottomLeft, D3DCOLOR colorBottomRight )
  1557. {
  1558.     m_colorTopLeft = colorTopLeft;
  1559.     m_colorTopRight = colorTopRight;
  1560.     m_colorBottomLeft = colorBottomLeft;
  1561.     m_colorBottomRight = colorBottomRight;
  1562. }
  1563.  
  1564.  
  1565. //--------------------------------------------------------------------------------------
  1566. void CDXUTDialog::SetNextDialog( CDXUTDialog* pNextDialog )
  1567.     if( pNextDialog == NULL )
  1568.         pNextDialog = this;
  1569.     
  1570.     m_pNextDialog = pNextDialog;
  1571.     m_pNextDialog->m_pPrevDialog = this;
  1572. }
  1573.  
  1574.  
  1575. //--------------------------------------------------------------------------------------
  1576. void CDXUTDialog::ClearFocus()
  1577. {
  1578.     if( s_pControlFocus )
  1579.     {
  1580.         s_pControlFocus->OnFocusOut();
  1581.         s_pControlFocus = NULL;
  1582.     }
  1583.  
  1584.     ReleaseCapture();
  1585. }
  1586.  
  1587.  
  1588. //--------------------------------------------------------------------------------------
  1589. void CDXUTDialog::FocusDefaultControl()
  1590. {
  1591.     // Check for default control in this dialog
  1592.     for( int i=0; i < m_Controls.GetSize(); i++ )
  1593.     {
  1594.         CDXUTControl* pControl = m_Controls.GetAt( i );
  1595.         if( pControl->m_bIsDefault )
  1596.         {
  1597.             // Remove focus from the current control
  1598.             ClearFocus();
  1599.  
  1600.             // Give focus to the default control
  1601.             s_pControlFocus = pControl;
  1602.             s_pControlFocus->OnFocusIn();
  1603.             return;
  1604.         }
  1605.     }
  1606. }
  1607.  
  1608.  
  1609.  
  1610. //--------------------------------------------------------------------------------------
  1611. void CDXUTDialog::OnCycleFocus( bool bForward )
  1612. {
  1613.     // This should only be handled by the dialog which owns the focused control, and 
  1614.     // only if a control currently has focus
  1615.     if( s_pControlFocus == NULL || s_pControlFocus->m_pDialog != this )
  1616.         return;
  1617.  
  1618.     CDXUTControl* pControl = s_pControlFocus;
  1619.     for( int i=0; i < 0xffff; i++ )
  1620.     {
  1621.         pControl = (bForward) ? GetNextControl( pControl ) : GetPrevControl( pControl );
  1622.         
  1623.         // If we've gone in a full circle then focus doesn't change
  1624.         if( pControl == s_pControlFocus )
  1625.             return;
  1626.  
  1627.         // If the dialog accepts keybord input and the control can have focus then
  1628.         // move focus
  1629.         if( pControl->m_pDialog->m_bKeyboardInput && pControl->CanHaveFocus() )
  1630.         {
  1631.             s_pControlFocus->OnFocusOut();
  1632.             s_pControlFocus = pControl;
  1633.             s_pControlFocus->OnFocusIn();
  1634.             return;
  1635.         }
  1636.     }
  1637.  
  1638.     // If we reached this point, the chain of dialogs didn't form a complete loop
  1639.     DXTRACE_ERR( L"CDXUTDialog: Multiple dialogs are improperly chained together", E_FAIL );
  1640. }
  1641.  
  1642.  
  1643. //--------------------------------------------------------------------------------------
  1644. void CDXUTDialog::OnMouseEnter( CDXUTControl* pControl )
  1645. {
  1646.     if( pControl == NULL )
  1647.         return;
  1648.  
  1649.     //pControl->m_bMouseOver = true;
  1650. }
  1651.  
  1652.  
  1653. //--------------------------------------------------------------------------------------
  1654. void CDXUTDialog::OnMouseLeave( CDXUTControl* pControl )
  1655. {
  1656.     if( pControl == NULL )
  1657.         return;
  1658.  
  1659.     //pControl->m_bMouseOver = false;
  1660. }
  1661.  
  1662.  
  1663. //--------------------------------------------------------------------------------------
  1664. HRESULT CDXUTDialogResourceManager::CreateFont( UINT iFont )
  1665. {
  1666.     HRESULT hr = S_OK;
  1667.  
  1668.     DXUTFontNode* pFontNode = m_FontCache.GetAt( iFont );
  1669.  
  1670.     SAFE_RELEASE( pFontNode->pFont );
  1671.     
  1672.     V_RETURN( D3DXCreateFont( m_pd3dDevice, pFontNode->nHeight, 0, pFontNode->nWeight, 1, FALSE, DEFAULT_CHARSET, 
  1673.                               OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  1674.                               pFontNode->strFace, &pFontNode->pFont ) );
  1675.  
  1676.     return S_OK;
  1677. }
  1678.  
  1679. //--------------------------------------------------------------------------------------
  1680. HRESULT CDXUTDialogResourceManager::CreateTexture( UINT iTexture )
  1681. {
  1682.     HRESULT hr = S_OK;
  1683.  
  1684.     DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( iTexture );
  1685.     
  1686.     // Make sure there's a texture to create
  1687.     if( pTextureNode->strFilename[0] == 0 )
  1688.         return S_OK;
  1689.     
  1690.     // Find the texture on the hard drive
  1691.     WCHAR strPath[MAX_PATH];
  1692.     hr = DXUTFindDXSDKMediaFileCch( strPath, MAX_PATH, pTextureNode->strFilename );
  1693.     if( FAILED(hr) )
  1694.     {
  1695.         return DXTRACE_ERR( L"DXUTFindDXSDKMediaFileCch", hr );
  1696.     }
  1697.  
  1698.     // Create texture
  1699.     D3DXIMAGE_INFO info;
  1700.     hr =  D3DXCreateTextureFromFileEx( m_pd3dDevice, strPath, D3DX_DEFAULT, D3DX_DEFAULT, 
  1701.                                        D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, 
  1702.                                        D3DX_DEFAULT, D3DX_DEFAULT, 0, 
  1703.                                        &info, NULL, &pTextureNode->pTexture );
  1704.     if( FAILED(hr) )
  1705.     {
  1706.         return DXTRACE_ERR( L"D3DXCreateTextureFromFileEx", hr );
  1707.     }
  1708.  
  1709.     // Store dimensions
  1710.     pTextureNode->dwWidth = info.Width;
  1711.     pTextureNode->dwHeight = info.Height;
  1712.  
  1713.     return S_OK;
  1714. }
  1715.  
  1716.  
  1717. //--------------------------------------------------------------------------------------
  1718. void CDXUTDialog::InitDefaultElements()
  1719. {
  1720.     SetTexture( 0, L"UI\\DXUTControls.dds" );
  1721.     SetFont( 0, L"Arial", 14, FW_NORMAL );
  1722.     
  1723.     CDXUTElement Element;
  1724.     RECT rcTexture;
  1725.  
  1726.     //-------------------------------------
  1727.     // Element for the caption
  1728.     //-------------------------------------
  1729.     m_CapElement.SetFont( 0 );
  1730.     SetRect( &rcTexture, 17, 269, 241, 287 );
  1731.     m_CapElement.SetTexture( 0, &rcTexture );
  1732.     m_CapElement.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(255, 255, 255, 255);
  1733.     m_CapElement.FontColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(255, 255, 255, 255);
  1734.     m_CapElement.SetFont( 0, D3DCOLOR_ARGB(255, 255, 255, 255), DT_LEFT | DT_VCENTER );
  1735.     // Pre-blend as we don't need to transition the state
  1736.     m_CapElement.TextureColor.Blend( DXUT_STATE_NORMAL, 10.0f );
  1737.     m_CapElement.FontColor.Blend( DXUT_STATE_NORMAL, 10.0f );
  1738.  
  1739.     //-------------------------------------
  1740.     // CDXUTStatic
  1741.     //-------------------------------------
  1742.     Element.SetFont( 0 );
  1743.     Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 200, 200, 200, 200 );
  1744.  
  1745.     // Assign the Element
  1746.     SetDefaultElement( DXUT_CONTROL_STATIC, 0, &Element );
  1747.     
  1748.  
  1749.     //-------------------------------------
  1750.     // CDXUTButton - Button
  1751.     //-------------------------------------
  1752.     SetRect( &rcTexture, 0, 0, 136, 54 );
  1753.     Element.SetTexture( 0, &rcTexture );
  1754.     Element.SetFont( 0 );
  1755.     Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(150, 255, 255, 255);
  1756.     Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB(200, 255, 255, 255);
  1757.     Element.FontColor.States[ DXUT_STATE_MOUSEOVER ] = D3DCOLOR_ARGB(255, 0, 0, 0);
  1758.     
  1759.     // Assign the Element
  1760.     SetDefaultElement( DXUT_CONTROL_BUTTON, 0, &Element );
  1761.     
  1762.  
  1763.     //-------------------------------------
  1764.     // CDXUTButton - Fill layer
  1765.     //-------------------------------------
  1766.     SetRect( &rcTexture, 136, 0, 272, 54 );
  1767.     Element.SetTexture( 0, &rcTexture, D3DCOLOR_ARGB(0, 255, 255, 255) );
  1768.     Element.TextureColor.States[ DXUT_STATE_MOUSEOVER ] = D3DCOLOR_ARGB(160, 255, 255, 255);
  1769.     Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB(60, 0, 0, 0);
  1770.     Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB(30, 255, 255, 255);
  1771.     
  1772.     
  1773.     // Assign the Element
  1774.     SetDefaultElement( DXUT_CONTROL_BUTTON, 1, &Element );
  1775.  
  1776.  
  1777.     //-------------------------------------
  1778.     // CDXUTCheckBox - Box
  1779.     //-------------------------------------
  1780.     SetRect( &rcTexture, 0, 54, 27, 81 );
  1781.     Element.SetTexture( 0, &rcTexture );
  1782.     Element.SetFont( 0, D3DCOLOR_ARGB(255, 255, 255, 255), DT_LEFT | DT_VCENTER );
  1783.     Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 200, 200, 200, 200 );
  1784.     Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(150, 255, 255, 255);
  1785.     Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB(200, 255, 255, 255);
  1786.     Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB(255, 255, 255, 255);
  1787.     
  1788.     // Assign the Element
  1789.     SetDefaultElement( DXUT_CONTROL_CHECKBOX, 0, &Element );
  1790.  
  1791.  
  1792.     //-------------------------------------
  1793.     // CDXUTCheckBox - Check
  1794.     //-------------------------------------
  1795.     SetRect( &rcTexture, 27, 54, 54, 81 );
  1796.     Element.SetTexture( 0, &rcTexture );
  1797.     
  1798.     // Assign the Element
  1799.     SetDefaultElement( DXUT_CONTROL_CHECKBOX, 1, &Element );
  1800.  
  1801.  
  1802.     //-------------------------------------
  1803.     // CDXUTRadioButton - Box
  1804.     //-------------------------------------
  1805.     SetRect( &rcTexture, 54, 54, 81, 81 );
  1806.     Element.SetTexture( 0, &rcTexture );
  1807.     Element.SetFont( 0, D3DCOLOR_ARGB(255, 255, 255, 255), DT_LEFT | DT_VCENTER );
  1808.     Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 200, 200, 200, 200 );
  1809.     Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(150, 255, 255, 255);
  1810.     Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB(200, 255, 255, 255);
  1811.     Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB(255, 255, 255, 255);
  1812.     
  1813.     // Assign the Element
  1814.     SetDefaultElement( DXUT_CONTROL_RADIOBUTTON, 0, &Element );
  1815.  
  1816.  
  1817.     //-------------------------------------
  1818.     // CDXUTRadioButton - Check
  1819.     //-------------------------------------
  1820.     SetRect( &rcTexture, 81, 54, 108, 81 );
  1821.     Element.SetTexture( 0, &rcTexture );
  1822.     
  1823.     // Assign the Element
  1824.     SetDefaultElement( DXUT_CONTROL_RADIOBUTTON, 1, &Element );
  1825.  
  1826.  
  1827.     //-------------------------------------
  1828.     // CDXUTComboBox - Main
  1829.     //-------------------------------------
  1830.     SetRect( &rcTexture, 7, 81, 247, 123 );
  1831.     Element.SetTexture( 0, &rcTexture );
  1832.     Element.SetFont( 0 );
  1833.     Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(150, 200, 200, 200);
  1834.     Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB(170, 230, 230, 230);
  1835.     Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB(70, 200, 200, 200);
  1836.     Element.FontColor.States[ DXUT_STATE_MOUSEOVER ] = D3DCOLOR_ARGB(255, 0, 0, 0);
  1837.     Element.FontColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB(255, 0, 0, 0);
  1838.     Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB(200, 200, 200, 200);
  1839.     
  1840.     
  1841.     // Assign the Element
  1842.     SetDefaultElement( DXUT_CONTROL_COMBOBOX, 0, &Element );
  1843.  
  1844.  
  1845.     //-------------------------------------
  1846.     // CDXUTComboBox - Button
  1847.     //-------------------------------------
  1848.     SetRect( &rcTexture, 272, 0, 325, 49 );
  1849.     Element.SetTexture( 0, &rcTexture );
  1850.     Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(150, 255, 255, 255);
  1851.     Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB(255, 150, 150, 150);
  1852.     Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB(200, 255, 255, 255);
  1853.     Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB(70, 255, 255, 255);
  1854.     
  1855.     // Assign the Element
  1856.     SetDefaultElement( DXUT_CONTROL_COMBOBOX, 1, &Element );
  1857.  
  1858.  
  1859.     //-------------------------------------
  1860.     // CDXUTComboBox - Dropdown
  1861.     //-------------------------------------
  1862.     SetRect( &rcTexture, 7, 123, 241, 265 );
  1863.     Element.SetTexture( 0, &rcTexture );
  1864.     Element.SetFont( 0, D3DCOLOR_ARGB(255, 0, 0, 0), DT_LEFT | DT_TOP );
  1865.     
  1866.     // Assign the Element
  1867.     SetDefaultElement( DXUT_CONTROL_COMBOBOX, 2, &Element );
  1868.  
  1869.  
  1870.     //-------------------------------------
  1871.     // CDXUTComboBox - Selection
  1872.     //-------------------------------------
  1873.     SetRect( &rcTexture, 7, 266, 241, 289 );
  1874.     Element.SetTexture( 0, &rcTexture );
  1875.     Element.SetFont( 0, D3DCOLOR_ARGB(255, 255, 255, 255), DT_LEFT | DT_TOP );
  1876.     
  1877.     // Assign the Element
  1878.     SetDefaultElement( DXUT_CONTROL_COMBOBOX, 3, &Element );
  1879.  
  1880.  
  1881.     //-------------------------------------
  1882.     // CDXUTSlider - Track
  1883.     //-------------------------------------
  1884.     SetRect( &rcTexture, 1, 290, 280, 331 );
  1885.     Element.SetTexture( 0, &rcTexture );
  1886.     Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB(150, 255, 255, 255);
  1887.     Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB(200, 255, 255, 255);
  1888.     Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB(70, 255, 255, 255);
  1889.     
  1890.     // Assign the Element
  1891.     SetDefaultElement( DXUT_CONTROL_SLIDER, 0, &Element );
  1892.  
  1893.     //-------------------------------------
  1894.     // CDXUTSlider - Button
  1895.     //-------------------------------------
  1896.     SetRect( &rcTexture, 248, 55, 289, 96 );
  1897.     Element.SetTexture( 0, &rcTexture );
  1898.  
  1899.     // Assign the Element
  1900.     SetDefaultElement( DXUT_CONTROL_SLIDER, 1, &Element );
  1901.  
  1902.     //-------------------------------------
  1903.     // CDXUTScrollBar - Track
  1904.     //-------------------------------------
  1905.     SetRect( &rcTexture, 243, 144, 265, 155 );
  1906.     Element.SetTexture( 0, &rcTexture );
  1907.     Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB(255, 200, 200, 200);
  1908.     
  1909.     
  1910.     // Assign the Element
  1911.     SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 0, &Element );
  1912.  
  1913.     //-------------------------------------
  1914.     // CDXUTScrollBar - Up Arrow
  1915.     //-------------------------------------
  1916.     SetRect( &rcTexture, 243, 124, 265, 144 );
  1917.     Element.SetTexture( 0, &rcTexture );
  1918.     Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB(255, 200, 200, 200);
  1919.     
  1920.     
  1921.     // Assign the Element
  1922.     SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 1, &Element );
  1923.  
  1924.     //-------------------------------------
  1925.     // CDXUTScrollBar - Down Arrow
  1926.     //-------------------------------------
  1927.     SetRect( &rcTexture, 243, 155, 265, 176 );
  1928.     Element.SetTexture( 0, &rcTexture );
  1929.     Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB(255, 200, 200, 200);
  1930.     
  1931.     
  1932.     // Assign the Element
  1933.     SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 2, &Element );
  1934.  
  1935.     //-------------------------------------
  1936.     // CDXUTScrollBar - Button
  1937.     //-------------------------------------
  1938.     SetRect( &rcTexture, 266, 123, 286, 167 );
  1939.     Element.SetTexture( 0, &rcTexture );
  1940.     
  1941.     // Assign the Element
  1942.     SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 3, &Element );
  1943.  
  1944.  
  1945.     //-------------------------------------
  1946.     // CDXUTEditBox
  1947.     //-------------------------------------
  1948.     // Element assignment:
  1949.     //   0 - text area
  1950.     //   1 - top left border
  1951.     //   2 - top border
  1952.     //   3 - top right border
  1953.     //   4 - left border
  1954.     //   5 - right border
  1955.     //   6 - lower left border
  1956.     //   7 - lower border
  1957.     //   8 - lower right border
  1958.  
  1959.     Element.SetFont( 0, D3DCOLOR_ARGB( 255, 0, 0, 0 ), DT_LEFT | DT_TOP );
  1960.  
  1961.     // Assign the style
  1962.     SetRect( &rcTexture, 14, 90, 241, 113 );
  1963.     Element.SetTexture( 0, &rcTexture );
  1964.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 0, &Element );
  1965.     SetRect( &rcTexture, 8, 82, 14, 90 );
  1966.     Element.SetTexture( 0, &rcTexture );
  1967.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 1, &Element );
  1968.     SetRect( &rcTexture, 14, 82, 241, 90 );
  1969.     Element.SetTexture( 0, &rcTexture );
  1970.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 2, &Element );
  1971.     SetRect( &rcTexture, 241, 82, 246, 90 );
  1972.     Element.SetTexture( 0, &rcTexture );
  1973.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 3, &Element );
  1974.     SetRect( &rcTexture, 8, 90, 14, 113 );
  1975.     Element.SetTexture( 0, &rcTexture );
  1976.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 4, &Element );
  1977.     SetRect( &rcTexture, 241, 90, 246, 113 );
  1978.     Element.SetTexture( 0, &rcTexture );
  1979.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 5, &Element );
  1980.     SetRect( &rcTexture, 8, 113, 14, 121 );
  1981.     Element.SetTexture( 0, &rcTexture );
  1982.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 6, &Element );
  1983.     SetRect( &rcTexture, 14, 113, 241, 121 );
  1984.     Element.SetTexture( 0, &rcTexture );
  1985.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 7, &Element );
  1986.     SetRect( &rcTexture, 241, 113, 246, 121 );
  1987.     Element.SetTexture( 0, &rcTexture );
  1988.     SetDefaultElement( DXUT_CONTROL_EDITBOX, 8, &Element );
  1989.  
  1990.  
  1991.     //-------------------------------------
  1992.     // CDXUTIMEEditBox
  1993.     //-------------------------------------
  1994.  
  1995.     Element.SetFont( 0, D3DCOLOR_ARGB( 255, 0, 0, 0 ), DT_LEFT | DT_TOP );
  1996.  
  1997.     // Assign the style
  1998.     SetRect( &rcTexture, 14, 90, 241, 113 );
  1999.     Element.SetTexture( 0, &rcTexture );
  2000.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 0, &Element );
  2001.     SetRect( &rcTexture, 8, 82, 14, 90 );
  2002.     Element.SetTexture( 0, &rcTexture );
  2003.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 1, &Element );
  2004.     SetRect( &rcTexture, 14, 82, 241, 90 );
  2005.     Element.SetTexture( 0, &rcTexture );
  2006.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 2, &Element );
  2007.     SetRect( &rcTexture, 241, 82, 246, 90 );
  2008.     Element.SetTexture( 0, &rcTexture );
  2009.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 3, &Element );
  2010.     SetRect( &rcTexture, 8, 90, 14, 113 );
  2011.     Element.SetTexture( 0, &rcTexture );
  2012.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 4, &Element );
  2013.     SetRect( &rcTexture, 241, 90, 246, 113 );
  2014.     Element.SetTexture( 0, &rcTexture );
  2015.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 5, &Element );
  2016.     SetRect( &rcTexture, 8, 113, 14, 121 );
  2017.     Element.SetTexture( 0, &rcTexture );
  2018.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 6, &Element );
  2019.     SetRect( &rcTexture, 14, 113, 241, 121 );
  2020.     Element.SetTexture( 0, &rcTexture );
  2021.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 7, &Element );
  2022.     SetRect( &rcTexture, 241, 113, 246, 121 );
  2023.     Element.SetTexture( 0, &rcTexture );
  2024.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 8, &Element );
  2025.     // Element 9 for IME text, and indicator button
  2026.     SetRect( &rcTexture, 0, 0, 136, 54 );
  2027.     Element.SetTexture( 0, &rcTexture );
  2028.     Element.SetFont( 0, D3DCOLOR_ARGB( 255, 0, 0, 0 ), DT_CENTER | DT_VCENTER );
  2029.     SetDefaultElement( DXUT_CONTROL_IMEEDITBOX, 9, &Element );
  2030.  
  2031.     //-------------------------------------
  2032.     // CDXUTListBox - Main
  2033.     //-------------------------------------
  2034.  
  2035.     SetRect( &rcTexture, 13, 124, 241, 265 );
  2036.     Element.SetTexture( 0, &rcTexture );
  2037.     Element.SetFont( 0, D3DCOLOR_ARGB(255, 0, 0, 0), DT_LEFT | DT_TOP );
  2038.  
  2039.     // Assign the Element
  2040.     SetDefaultElement( DXUT_CONTROL_LISTBOX, 0, &Element );
  2041.  
  2042.     //-------------------------------------
  2043.     // CDXUTListBox - Selection
  2044.     //-------------------------------------
  2045.  
  2046.     SetRect( &rcTexture, 17, 269, 241, 287 );
  2047.     Element.SetTexture( 0, &rcTexture );
  2048.     Element.SetFont( 0, D3DCOLOR_ARGB(255, 255, 255, 255), DT_LEFT | DT_TOP );
  2049.  
  2050.     // Assign the Element
  2051.     SetDefaultElement( DXUT_CONTROL_LISTBOX, 1, &Element );
  2052. }
  2053.  
  2054.  
  2055.  
  2056. //--------------------------------------------------------------------------------------
  2057. // CDXUTControl class
  2058. //--------------------------------------------------------------------------------------
  2059.  
  2060. //--------------------------------------------------------------------------------------
  2061. CDXUTControl::CDXUTControl( CDXUTDialog *pDialog )
  2062. {
  2063.     m_Type = DXUT_CONTROL_BUTTON;
  2064.     m_pDialog = pDialog;
  2065.     m_ID = 0;
  2066.     m_Index = 0;
  2067.     m_pUserData = NULL;
  2068.  
  2069.     m_bEnabled = true;
  2070.     m_bVisible = true;
  2071.     m_bMouseOver = false;
  2072.     m_bHasFocus = false;
  2073.     m_bIsDefault = false;
  2074.  
  2075.     m_pDialog = NULL;
  2076.  
  2077.     m_x = 0;
  2078.     m_y = 0;
  2079.     m_width = 0;
  2080.     m_height = 0;
  2081.  
  2082.    ZeroMemory( &m_rcBoundingBox, sizeof( m_rcBoundingBox ) );
  2083. }
  2084.  
  2085.  
  2086. CDXUTControl::~CDXUTControl()
  2087. {
  2088.     for( int i = 0; i < m_Elements.GetSize(); ++i )
  2089.     {
  2090.         delete m_Elements[i];
  2091.     }
  2092.     m_Elements.RemoveAll();
  2093. }
  2094.  
  2095.  
  2096. //--------------------------------------------------------------------------------------
  2097. void CDXUTControl::SetTextColor( D3DCOLOR Color )
  2098. {
  2099.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  2100.  
  2101.     if( pElement )
  2102.         pElement->FontColor.States[DXUT_STATE_NORMAL] = Color;
  2103. }
  2104.  
  2105.  
  2106. //--------------------------------------------------------------------------------------
  2107. HRESULT CDXUTControl::SetElement( UINT iElement, CDXUTElement* pElement )
  2108. {
  2109.     HRESULT hr = S_OK;
  2110.  
  2111.     if( pElement == NULL )
  2112.         return E_INVALIDARG;
  2113.  
  2114.     // Make certain the array is this large
  2115.     for( UINT i=m_Elements.GetSize(); i <= iElement; i++ )
  2116.     {
  2117.         CDXUTElement* pNewElement = new CDXUTElement();
  2118.         if( pNewElement == NULL )
  2119.             return E_OUTOFMEMORY;
  2120.  
  2121.         hr = m_Elements.Add( pNewElement );
  2122.         if( FAILED(hr) )
  2123.             return hr;
  2124.     }
  2125.  
  2126.     // Update the data
  2127.     CDXUTElement* pCurElement = m_Elements.GetAt( iElement );
  2128.     *pCurElement = *pElement;
  2129.     
  2130.     return S_OK;
  2131. }
  2132.  
  2133.  
  2134. //--------------------------------------------------------------------------------------
  2135. void CDXUTControl::Refresh()
  2136. {
  2137.     m_bMouseOver = false;
  2138.     m_bHasFocus = false;
  2139.  
  2140.     for( int i=0; i < m_Elements.GetSize(); i++ )
  2141.     {
  2142.         CDXUTElement* pElement = m_Elements.GetAt( i );
  2143.         pElement->Refresh();
  2144.     }
  2145. }
  2146.  
  2147.  
  2148. //--------------------------------------------------------------------------------------
  2149. void CDXUTControl::UpdateRects()
  2150. {
  2151.     SetRect( &m_rcBoundingBox, m_x, m_y, m_x + m_width, m_y + m_height );
  2152. }
  2153.  
  2154.  
  2155. //--------------------------------------------------------------------------------------
  2156. // CDXUTStatic class
  2157. //--------------------------------------------------------------------------------------
  2158.  
  2159. //--------------------------------------------------------------------------------------
  2160. CDXUTStatic::CDXUTStatic( CDXUTDialog *pDialog )
  2161. {
  2162.     m_Type = DXUT_CONTROL_STATIC;
  2163.     m_pDialog = pDialog;
  2164.  
  2165.     ZeroMemory( &m_strText, sizeof(m_strText) );  
  2166.  
  2167.     for( int i=0; i < m_Elements.GetSize(); i++ )
  2168.     {
  2169.         CDXUTElement* pElement = m_Elements.GetAt( i );
  2170.         SAFE_DELETE( pElement );
  2171.     }
  2172.  
  2173.     m_Elements.RemoveAll();
  2174. }
  2175.  
  2176.  
  2177. //--------------------------------------------------------------------------------------
  2178. void CDXUTStatic::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  2179. {    
  2180.     if( m_bVisible == false )
  2181.         return;
  2182.  
  2183.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  2184.  
  2185.     if( m_bEnabled == false )
  2186.         iState = DXUT_STATE_DISABLED;
  2187.         
  2188.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  2189.  
  2190.     pElement->FontColor.Blend( iState, fElapsedTime );
  2191.     
  2192.     m_pDialog->DrawText( m_strText, pElement, &m_rcBoundingBox, true );
  2193. }
  2194.  
  2195. //--------------------------------------------------------------------------------------
  2196. HRESULT CDXUTStatic::GetTextCopy( LPWSTR strDest, UINT bufferCount )
  2197. {
  2198.     // Validate incoming parameters
  2199.     if( strDest == NULL || bufferCount == 0 )
  2200.     {
  2201.         return E_INVALIDARG;
  2202.     }
  2203.  
  2204.     // Copy the window text
  2205.     wcsncpy( strDest, m_strText, bufferCount );
  2206.     strDest[bufferCount-1] = 0;
  2207.  
  2208.     return S_OK;
  2209. }
  2210.  
  2211.  
  2212. //--------------------------------------------------------------------------------------
  2213. HRESULT CDXUTStatic::SetText( LPCWSTR strText )
  2214. {
  2215.     if( strText == NULL )
  2216.     {
  2217.         m_strText[0] = 0;
  2218.         return S_OK;
  2219.     }
  2220.     
  2221.     wcsncpy( m_strText, strText, MAX_PATH-1 ); 
  2222.     return S_OK;
  2223. }
  2224.  
  2225.  
  2226. //--------------------------------------------------------------------------------------
  2227. // CDXUTButton class
  2228. //--------------------------------------------------------------------------------------
  2229.  
  2230. //--------------------------------------------------------------------------------------
  2231. CDXUTButton::CDXUTButton( CDXUTDialog *pDialog )
  2232. {
  2233.     m_Type = DXUT_CONTROL_BUTTON;
  2234.     m_pDialog = pDialog;
  2235.  
  2236.     m_bPressed = false;
  2237.     m_nHotkey = 0;
  2238. }
  2239.  
  2240. //--------------------------------------------------------------------------------------
  2241. bool CDXUTButton::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  2242. {
  2243.     if( !m_bEnabled || !m_bVisible )
  2244.         return false;
  2245.  
  2246.     switch( uMsg )
  2247.     {
  2248.         case WM_KEYDOWN:
  2249.         {
  2250.             switch( wParam )
  2251.             {
  2252.                 case VK_SPACE:
  2253.                     m_bPressed = true;
  2254.                     return true;
  2255.             }
  2256.         }
  2257.  
  2258.         case WM_KEYUP:
  2259.         {
  2260.             switch( wParam )
  2261.             {
  2262.                 case VK_SPACE:
  2263.                     if( m_bPressed == true )
  2264.                     {
  2265.                         m_bPressed = false;
  2266.                         m_pDialog->SendEvent( EVENT_BUTTON_CLICKED, true, this );
  2267.                     }
  2268.                     return true;
  2269.             }
  2270.         }
  2271.     }
  2272.     return false;
  2273. }
  2274.  
  2275.  
  2276. //--------------------------------------------------------------------------------------
  2277. bool CDXUTButton::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  2278. {
  2279.     if( !m_bEnabled || !m_bVisible )
  2280.         return false;
  2281.  
  2282.     switch( uMsg )
  2283.     {
  2284.         case WM_LBUTTONDOWN:
  2285.         case WM_LBUTTONDBLCLK:
  2286.         {
  2287.             if( ContainsPoint( pt ) )
  2288.             {
  2289.                 // Pressed while inside the control
  2290.                 m_bPressed = true;
  2291.                 SetCapture( DXUTGetHWND() );
  2292.  
  2293.                 if( !m_bHasFocus )
  2294.                     m_pDialog->RequestFocus( this );
  2295.  
  2296.                 return true;
  2297.             }
  2298.  
  2299.             break;
  2300.         }
  2301.  
  2302.         case WM_LBUTTONUP:
  2303.         {
  2304.             if( m_bPressed )
  2305.             {
  2306.                 m_bPressed = false;
  2307.                 ReleaseCapture();
  2308.  
  2309.                 if( !m_pDialog->m_bKeyboardInput )
  2310.                     m_pDialog->ClearFocus();
  2311.  
  2312.                 // Button click
  2313.                 if( ContainsPoint( pt ) )
  2314.                     m_pDialog->SendEvent( EVENT_BUTTON_CLICKED, true, this );
  2315.  
  2316.                 return true;
  2317.             }
  2318.  
  2319.             break;
  2320.         }
  2321.     };
  2322.     
  2323.     return false;
  2324. }
  2325.  
  2326. //--------------------------------------------------------------------------------------
  2327. void CDXUTButton::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  2328. {
  2329.     int nOffsetX = 0;
  2330.     int nOffsetY = 0;
  2331.  
  2332.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  2333.  
  2334.     if( m_bVisible == false )
  2335.     {
  2336.         iState = DXUT_STATE_HIDDEN;
  2337.     }
  2338.     else if( m_bEnabled == false )
  2339.     {
  2340.         iState = DXUT_STATE_DISABLED;
  2341.     }
  2342.     else if( m_bPressed )
  2343.     {
  2344.         iState = DXUT_STATE_PRESSED;
  2345.  
  2346.         nOffsetX = 1;
  2347.         nOffsetY = 2;
  2348.     }
  2349.     else if( m_bMouseOver )
  2350.     {
  2351.         iState = DXUT_STATE_MOUSEOVER;
  2352.  
  2353.         nOffsetX = -1;
  2354.         nOffsetY = -2;
  2355.     }
  2356.     else if( m_bHasFocus )
  2357.     {
  2358.         iState = DXUT_STATE_FOCUS;
  2359.     }
  2360.     
  2361.     // Background fill layer
  2362.     //TODO: remove magic numbers
  2363.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  2364.     
  2365.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  2366.  
  2367.     RECT rcWindow = m_rcBoundingBox;
  2368.     OffsetRect( &rcWindow, nOffsetX, nOffsetY );
  2369.  
  2370.  
  2371.     // Blend current color
  2372.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  2373.     pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate );
  2374.  
  2375.     m_pDialog->DrawSprite( pElement, &rcWindow );
  2376.     m_pDialog->DrawText( m_strText, pElement, &rcWindow );
  2377.  
  2378.     // Main button
  2379.     pElement = m_Elements.GetAt( 1 );
  2380.  
  2381.  
  2382.     // Blend current color
  2383.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  2384.     pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate );
  2385.  
  2386.     m_pDialog->DrawSprite( pElement, &rcWindow );
  2387.     m_pDialog->DrawText( m_strText, pElement, &rcWindow );
  2388. }
  2389.  
  2390.  
  2391.  
  2392. //--------------------------------------------------------------------------------------
  2393. // CDXUTCheckBox class
  2394. //--------------------------------------------------------------------------------------
  2395.  
  2396. //--------------------------------------------------------------------------------------
  2397. CDXUTCheckBox::CDXUTCheckBox( CDXUTDialog *pDialog )
  2398. {
  2399.     m_Type = DXUT_CONTROL_CHECKBOX;
  2400.     m_pDialog = pDialog;
  2401.  
  2402.     m_bChecked = false;
  2403. }
  2404.     
  2405.  
  2406. //--------------------------------------------------------------------------------------
  2407. bool CDXUTCheckBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  2408. {
  2409.     if( !m_bEnabled || !m_bVisible )
  2410.         return false;
  2411.  
  2412.     switch( uMsg )
  2413.     {
  2414.         case WM_KEYDOWN:
  2415.         {
  2416.             switch( wParam )
  2417.             {
  2418.                 case VK_SPACE:
  2419.                     m_bPressed = true;
  2420.                     return true;
  2421.             }
  2422.         }
  2423.  
  2424.         case WM_KEYUP:
  2425.         {
  2426.             switch( wParam )
  2427.             {
  2428.                 case VK_SPACE:
  2429.                     if( m_bPressed == true )
  2430.                     {
  2431.                         m_bPressed = false;
  2432.                         SetCheckedInternal( !m_bChecked, true );
  2433.                     }
  2434.                     return true;
  2435.             }
  2436.         }
  2437.     }
  2438.     return false;
  2439. }
  2440.  
  2441.  
  2442. //--------------------------------------------------------------------------------------
  2443. bool CDXUTCheckBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  2444. {
  2445.     if( !m_bEnabled || !m_bVisible )
  2446.         return false;
  2447.  
  2448.     switch( uMsg )
  2449.     {
  2450.         case WM_LBUTTONDOWN:
  2451.         case WM_LBUTTONDBLCLK:
  2452.         {
  2453.             if( ContainsPoint( pt ) )
  2454.             {
  2455.                 // Pressed while inside the control
  2456.                 m_bPressed = true;
  2457.                 SetCapture( DXUTGetHWND() );
  2458.  
  2459.                 if( !m_bHasFocus && m_pDialog->m_bKeyboardInput )
  2460.                     m_pDialog->RequestFocus( this );
  2461.  
  2462.                 return true;
  2463.             }
  2464.  
  2465.             break;
  2466.         }
  2467.  
  2468.         case WM_LBUTTONUP:
  2469.         {
  2470.             if( m_bPressed )
  2471.             {
  2472.                 m_bPressed = false;
  2473.                 ReleaseCapture();
  2474.  
  2475.                 // Button click
  2476.                 if( ContainsPoint( pt ) )
  2477.                     SetCheckedInternal( !m_bChecked, true );
  2478.                 
  2479.                 return true;
  2480.             }
  2481.  
  2482.             break;
  2483.         }
  2484.     };
  2485.     
  2486.     return false;
  2487. }
  2488.  
  2489.  
  2490. //--------------------------------------------------------------------------------------
  2491. void CDXUTCheckBox::SetCheckedInternal( bool bChecked, bool bFromInput ) 
  2492.     m_bChecked = bChecked; 
  2493.  
  2494.     m_pDialog->SendEvent( EVENT_CHECKBOX_CHANGED, bFromInput, this ); 
  2495. }
  2496.  
  2497.  
  2498. //--------------------------------------------------------------------------------------
  2499. BOOL CDXUTCheckBox::ContainsPoint( POINT pt ) 
  2500.     return ( PtInRect( &m_rcBoundingBox, pt ) || 
  2501.              PtInRect( &m_rcButton, pt ) ); 
  2502. }
  2503.  
  2504.  
  2505.  
  2506. //--------------------------------------------------------------------------------------
  2507. void CDXUTCheckBox::UpdateRects()
  2508. {
  2509.     CDXUTButton::UpdateRects();
  2510.  
  2511.     m_rcButton = m_rcBoundingBox;
  2512.     m_rcButton.right = m_rcButton.left + RectHeight( m_rcButton );
  2513.  
  2514.     m_rcText = m_rcBoundingBox;
  2515.     m_rcText.left += (int) ( 1.25f * RectWidth( m_rcButton ) );
  2516. }
  2517.  
  2518.  
  2519.  
  2520. //--------------------------------------------------------------------------------------
  2521. void CDXUTCheckBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  2522. {
  2523.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  2524.  
  2525.     if( m_bVisible == false )
  2526.         iState = DXUT_STATE_HIDDEN;
  2527.     else if( m_bEnabled == false )
  2528.         iState = DXUT_STATE_DISABLED;
  2529.     else if( m_bPressed )
  2530.         iState = DXUT_STATE_PRESSED;
  2531.     else if( m_bMouseOver )
  2532.         iState = DXUT_STATE_MOUSEOVER;
  2533.     else if( m_bHasFocus )
  2534.         iState = DXUT_STATE_FOCUS;
  2535.  
  2536.     //debug
  2537.     //m_pDialog->DrawRect( &m_rcBoundingBox, D3DCOLOR_ARGB(255, 255, 255, 0) );
  2538.     //m_pDialog->DrawRect( &m_rcButton, D3DCOLOR_ARGB(255, 0, 255, 255) );
  2539.  
  2540.     //TODO: remove magic numbers
  2541.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  2542.     
  2543.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  2544.  
  2545.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  2546.     pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate );
  2547.  
  2548.     m_pDialog->DrawSprite( pElement, &m_rcButton );
  2549.     m_pDialog->DrawText( m_strText, pElement, &m_rcText, true );
  2550.  
  2551.     if( !m_bChecked )
  2552.         iState = DXUT_STATE_HIDDEN;
  2553.  
  2554.     pElement = m_Elements.GetAt( 1 );
  2555.  
  2556.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  2557.     m_pDialog->DrawSprite( pElement, &m_rcButton );
  2558. }
  2559.  
  2560.  
  2561.  
  2562.  
  2563. //--------------------------------------------------------------------------------------
  2564. // CDXUTRadioButton class
  2565. //--------------------------------------------------------------------------------------
  2566.  
  2567. //--------------------------------------------------------------------------------------
  2568. CDXUTRadioButton::CDXUTRadioButton( CDXUTDialog *pDialog )
  2569. {
  2570.     m_Type = DXUT_CONTROL_RADIOBUTTON;
  2571.     m_pDialog = pDialog;
  2572. }
  2573.  
  2574.  
  2575.  
  2576. //--------------------------------------------------------------------------------------
  2577. bool CDXUTRadioButton::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  2578. {
  2579.     if( !m_bEnabled || !m_bVisible )
  2580.         return false;
  2581.  
  2582.     switch( uMsg )
  2583.     {
  2584.         case WM_KEYDOWN:
  2585.         {
  2586.             switch( wParam )
  2587.             {
  2588.                 case VK_SPACE:
  2589.                     m_bPressed = true;
  2590.                     return true;
  2591.             }
  2592.         }
  2593.  
  2594.         case WM_KEYUP:
  2595.         {
  2596.             switch( wParam )
  2597.             {
  2598.                 case VK_SPACE:
  2599.                     if( m_bPressed == true )
  2600.                     {
  2601.                         m_bPressed = false;
  2602.                         
  2603.                         m_pDialog->ClearRadioButtonGroup( m_nButtonGroup );
  2604.                         m_bChecked = !m_bChecked;
  2605.  
  2606.                         m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, true, this );
  2607.                     }
  2608.                     return true;
  2609.             }
  2610.         }
  2611.     }
  2612.     return false;
  2613. }
  2614.  
  2615.  
  2616. //--------------------------------------------------------------------------------------
  2617. bool CDXUTRadioButton::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  2618. {
  2619.     if( !m_bEnabled || !m_bVisible )
  2620.         return false;
  2621.  
  2622.     switch( uMsg )
  2623.     {
  2624.         case WM_LBUTTONDOWN:
  2625.         case WM_LBUTTONDBLCLK:
  2626.         {
  2627.             if( ContainsPoint( pt ) )
  2628.             {
  2629.                 // Pressed while inside the control
  2630.                 m_bPressed = true;
  2631.                 SetCapture( DXUTGetHWND() );
  2632.  
  2633.                 if( !m_bHasFocus && m_pDialog->m_bKeyboardInput )
  2634.                     m_pDialog->RequestFocus( this );
  2635.  
  2636.                 return true;
  2637.             }
  2638.  
  2639.             break;
  2640.         }
  2641.  
  2642.         case WM_LBUTTONUP:
  2643.         {
  2644.             if( m_bPressed )
  2645.             {
  2646.                 m_bPressed = false;
  2647.                 ReleaseCapture();
  2648.  
  2649.                 // Button click
  2650.                 if( ContainsPoint( pt ) )
  2651.                 {
  2652.                     m_pDialog->ClearRadioButtonGroup( m_nButtonGroup );
  2653.                     m_bChecked = !m_bChecked;
  2654.  
  2655.                     m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, true, this );
  2656.                 }
  2657.  
  2658.                 return true;
  2659.             }
  2660.  
  2661.             break;
  2662.         }
  2663.     };
  2664.     
  2665.     return false;
  2666. }
  2667.  
  2668. //--------------------------------------------------------------------------------------
  2669. void CDXUTRadioButton::SetCheckedInternal( bool bChecked, bool bClearGroup, bool bFromInput )
  2670. {
  2671.     if( bChecked && bClearGroup )
  2672.         m_pDialog->ClearRadioButtonGroup( m_nButtonGroup );
  2673.  
  2674.     m_bChecked = bChecked;
  2675.     m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, bFromInput, this );
  2676. }
  2677.  
  2678.  
  2679.  
  2680.  
  2681. //--------------------------------------------------------------------------------------
  2682. // CDXUTComboBox class
  2683. //--------------------------------------------------------------------------------------
  2684.  
  2685. //--------------------------------------------------------------------------------------
  2686. CDXUTComboBox::CDXUTComboBox( CDXUTDialog *pDialog ) :
  2687.     m_ScrollBar( pDialog )
  2688. {
  2689.     m_Type = DXUT_CONTROL_COMBOBOX;
  2690.     m_pDialog = pDialog;
  2691.  
  2692.     m_nDropHeight = 100;
  2693.  
  2694.     m_nSBWidth = 16;
  2695.     m_bOpened = false;
  2696.     m_iSelected = -1;
  2697.     m_iFocused = -1;
  2698. }
  2699.  
  2700.  
  2701. //--------------------------------------------------------------------------------------
  2702. CDXUTComboBox::~CDXUTComboBox()
  2703. {
  2704.     RemoveAllItems();
  2705. }
  2706.  
  2707.  
  2708. //--------------------------------------------------------------------------------------
  2709. void CDXUTComboBox::SetTextColor( D3DCOLOR Color )
  2710. {
  2711.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  2712.  
  2713.     if( pElement )
  2714.         pElement->FontColor.States[DXUT_STATE_NORMAL] = Color;
  2715.  
  2716.     pElement = m_Elements.GetAt( 2 );
  2717.  
  2718.     if( pElement )
  2719.         pElement->FontColor.States[DXUT_STATE_NORMAL] = Color;
  2720. }
  2721.  
  2722.  
  2723. //--------------------------------------------------------------------------------------
  2724. void CDXUTComboBox::UpdateRects()
  2725. {
  2726.     
  2727.     CDXUTButton::UpdateRects();
  2728.  
  2729.     m_rcButton = m_rcBoundingBox;
  2730.     m_rcButton.left = m_rcButton.right - RectHeight( m_rcButton );
  2731.  
  2732.     m_rcText = m_rcBoundingBox;
  2733.     m_rcText.right = m_rcButton.left;
  2734.  
  2735.     m_rcDropdown = m_rcText;
  2736.     OffsetRect( &m_rcDropdown, 0, (int) (0.90f * RectHeight( m_rcText )) );
  2737.     m_rcDropdown.bottom += m_nDropHeight;
  2738.     m_rcDropdown.right -= m_nSBWidth;
  2739.  
  2740.     m_rcDropdownText = m_rcDropdown;
  2741.     m_rcDropdownText.left += (int) (0.1f * RectWidth( m_rcDropdown ));
  2742.     m_rcDropdownText.right -= (int) (0.1f * RectWidth( m_rcDropdown ));
  2743.     m_rcDropdownText.top += (int) (0.1f * RectHeight( m_rcDropdown ));
  2744.     m_rcDropdownText.bottom -= (int) (0.1f * RectHeight( m_rcDropdown ));
  2745.  
  2746.     // Update the scrollbar's rects
  2747.     m_ScrollBar.SetLocation( m_rcDropdown.right, m_rcDropdown.top+2 );
  2748.     m_ScrollBar.SetSize( m_nSBWidth, RectHeight( m_rcDropdown )-2 );
  2749.     DXUTFontNode* pFontNode = DXUTGetGlobalDialogResourceManager()->GetFontNode( m_Elements.GetAt( 2 )->iFont );
  2750.     if( pFontNode && pFontNode->nHeight )
  2751.     {
  2752.         m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) / pFontNode->nHeight );
  2753.  
  2754.         // The selected item may have been scrolled off the page.
  2755.         // Ensure that it is in page again.
  2756.         m_ScrollBar.ShowItem( m_iSelected );
  2757.     }
  2758. }
  2759.  
  2760.  
  2761. //--------------------------------------------------------------------------------------
  2762. void CDXUTComboBox::OnFocusOut()
  2763. {
  2764.     CDXUTButton::OnFocusOut();
  2765.  
  2766.     m_bOpened = false;
  2767. }
  2768.     
  2769.  
  2770. //--------------------------------------------------------------------------------------
  2771. bool CDXUTComboBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  2772. {
  2773.     const DWORD    REPEAT_MASK = (0x40000000);
  2774.  
  2775.     if( !m_bEnabled || !m_bVisible )
  2776.         return false;
  2777.  
  2778.     // Let the scroll bar have a chance to handle it first
  2779.     if( m_ScrollBar.HandleKeyboard( uMsg, wParam, lParam ) )
  2780.         return true;
  2781.  
  2782.     switch( uMsg )
  2783.     {
  2784.         case WM_KEYDOWN:
  2785.         {
  2786.             switch( wParam )
  2787.             {
  2788.                 case VK_RETURN:
  2789.                     if( m_bOpened )
  2790.                     {
  2791.                         if( m_iSelected != m_iFocused )
  2792.                         {
  2793.                             m_iSelected = m_iFocused;
  2794.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  2795.                         }
  2796.                         m_bOpened = false;
  2797.                         
  2798.                         if( !m_pDialog->m_bKeyboardInput )
  2799.                             m_pDialog->ClearFocus();
  2800.  
  2801.                         return true;
  2802.                     }
  2803.                     break;
  2804.  
  2805.                 case VK_F4:
  2806.                     // Filter out auto-repeats
  2807.                     if( lParam & REPEAT_MASK )
  2808.                         return true;
  2809.  
  2810.                     m_bOpened = !m_bOpened;
  2811.  
  2812.                     if( !m_bOpened )
  2813.                     {
  2814.                         m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  2815.  
  2816.                         if( !m_pDialog->m_bKeyboardInput )
  2817.                             m_pDialog->ClearFocus();
  2818.                     }
  2819.  
  2820.                     return true;
  2821.  
  2822.                 case VK_LEFT:
  2823.                 case VK_UP:
  2824.                     if( m_iFocused > 0 )
  2825.                     {
  2826.                         m_iFocused--;
  2827.                         m_iSelected = m_iFocused;
  2828.  
  2829.                         if( !m_bOpened )
  2830.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  2831.                     }
  2832.                     
  2833.                     return true;
  2834.  
  2835.                 case VK_RIGHT:
  2836.                 case VK_DOWN:
  2837.                     if( m_iFocused+1 < (int)GetNumItems() )
  2838.                     {
  2839.                         m_iFocused++;
  2840.                         m_iSelected = m_iFocused;
  2841.  
  2842.                         if( !m_bOpened )
  2843.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  2844.                     }
  2845.  
  2846.                     return true;
  2847.             }
  2848.             break;
  2849.         }
  2850.     }
  2851.  
  2852.     return false;
  2853. }
  2854.  
  2855.  
  2856. //--------------------------------------------------------------------------------------
  2857. bool CDXUTComboBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  2858. {
  2859.     if( !m_bEnabled || !m_bVisible )
  2860.         return false;
  2861.  
  2862.     // Let the scroll bar handle it first.
  2863.     if( m_ScrollBar.HandleMouse( uMsg, pt, wParam, lParam ) )
  2864.         return true;
  2865.  
  2866.     switch( uMsg )
  2867.     {
  2868.         case WM_MOUSEMOVE:
  2869.         {
  2870.             if( m_bOpened && PtInRect( &m_rcDropdown, pt ) )
  2871.             {
  2872.                 // Determine which item has been selected
  2873.                 for( int i=0; i < m_Items.GetSize(); i++ )
  2874.                 {
  2875.                     DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  2876.                     if( pItem -> bVisible &&
  2877.                         PtInRect( &pItem->rcActive, pt ) )
  2878.                     {
  2879.                         m_iFocused = i;
  2880.                     }
  2881.                 }
  2882.                 return true;
  2883.             }
  2884.             break;
  2885.         }
  2886.  
  2887.         case WM_LBUTTONDOWN:
  2888.         case WM_LBUTTONDBLCLK:
  2889.         {
  2890.             if( ContainsPoint( pt ) )
  2891.             {
  2892.                 // Pressed while inside the control
  2893.                 m_bPressed = true;
  2894.                 SetCapture( DXUTGetHWND() );
  2895.  
  2896.                 if( !m_bHasFocus )
  2897.                     m_pDialog->RequestFocus( this );
  2898.  
  2899.                 // Toggle dropdown
  2900.                 if( m_bHasFocus )
  2901.                 {
  2902.                     m_bOpened = !m_bOpened;
  2903.                 
  2904.                     if( !m_bOpened )
  2905.                     {
  2906.                         if( !m_pDialog->m_bKeyboardInput )
  2907.                             m_pDialog->ClearFocus();
  2908.                     }
  2909.                 }
  2910.  
  2911.                 return true;
  2912.             }
  2913.  
  2914.             // Perhaps this click is within the dropdown
  2915.             if( m_bOpened && PtInRect( &m_rcDropdown, pt ) )
  2916.             {
  2917.                 // Determine which item has been selected
  2918.                 for( int i=m_ScrollBar.GetTrackPos(); i < m_Items.GetSize(); i++ )
  2919.                 {
  2920.                     DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  2921.                     if( pItem -> bVisible &&
  2922.                         PtInRect( &pItem->rcActive, pt ) )
  2923.                     {
  2924.                         m_iFocused = m_iSelected = i;
  2925.                         m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  2926.                         m_bOpened = false;
  2927.                         
  2928.                         if( !m_pDialog->m_bKeyboardInput )
  2929.                             m_pDialog->ClearFocus();
  2930.  
  2931.                         break;
  2932.                     }
  2933.                 }
  2934.  
  2935.                 return true;
  2936.             }
  2937.  
  2938.             // Mouse click not on main control or in dropdown, fire an event if needed
  2939.             if( m_bOpened )
  2940.             {
  2941.                 m_iFocused = m_iSelected;
  2942.  
  2943.                 m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  2944.                 m_bOpened = false;
  2945.             }
  2946.  
  2947.             // Make sure the control is no longer in a pressed state
  2948.             m_bPressed = false;
  2949.  
  2950.             // Release focus if appropriate
  2951.             if( !m_pDialog->m_bKeyboardInput )
  2952.             {
  2953.                 m_pDialog->ClearFocus();
  2954.             }
  2955.  
  2956.             break;
  2957.         }
  2958.  
  2959.         case WM_LBUTTONUP:
  2960.         {
  2961.             if( m_bPressed && ContainsPoint( pt ) )
  2962.             {
  2963.                 // Button click
  2964.                 m_bPressed = false;
  2965.                 ReleaseCapture();
  2966.                 return true;
  2967.             }
  2968.  
  2969.             break;
  2970.         }
  2971.  
  2972.         case WM_MOUSEWHEEL:
  2973.         {
  2974.             int zDelta = (short) HIWORD(wParam) / WHEEL_DELTA;
  2975.             if( m_bOpened )
  2976.             {
  2977.                 UINT uLines;
  2978.                 SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &uLines, 0 );
  2979.                 m_ScrollBar.Scroll( -zDelta * uLines );
  2980.             } else
  2981.             {
  2982.                 if( zDelta > 0 )
  2983.                 {
  2984.                     if( m_iFocused > 0 )
  2985.                     {
  2986.                         m_iFocused--;
  2987.                         m_iSelected = m_iFocused;     
  2988.                         
  2989.                         if( !m_bOpened )
  2990.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  2991.                     }          
  2992.                 }
  2993.                 else
  2994.                 {
  2995.                     if( m_iFocused+1 < (int)GetNumItems() )
  2996.                     {
  2997.                         m_iFocused++;
  2998.                         m_iSelected = m_iFocused;   
  2999.  
  3000.                         if( !m_bOpened )
  3001.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  3002.                     }
  3003.                 }
  3004.             }
  3005.             return true;
  3006.         }
  3007.     };
  3008.     
  3009.     return false;
  3010. }
  3011.  
  3012.  
  3013. //--------------------------------------------------------------------------------------
  3014. void CDXUTComboBox::OnHotkey()
  3015. {
  3016.     if( m_bOpened )
  3017.         return;
  3018.  
  3019.     if( m_iSelected == -1 )
  3020.         return;
  3021.  
  3022.     m_iSelected++;
  3023.     
  3024.     if( m_iSelected >= (int) m_Items.GetSize() )
  3025.         m_iSelected = 0;
  3026.  
  3027.     m_iFocused = m_iSelected;
  3028.     m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  3029. }
  3030.  
  3031.  
  3032. //--------------------------------------------------------------------------------------
  3033. void CDXUTComboBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  3034. {
  3035.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  3036.     
  3037.     if( !m_bOpened )
  3038.         iState = DXUT_STATE_HIDDEN;
  3039.  
  3040.     // Dropdown box
  3041.     CDXUTElement* pElement = m_Elements.GetAt( 2 );
  3042.  
  3043.     // If we have not initialized the scroll bar page size,
  3044.     // do that now.
  3045.     static bool bSBInit;
  3046.     if( !bSBInit )
  3047.     {
  3048.         // Update the page size of the scroll bar
  3049.         if( DXUTGetGlobalDialogResourceManager()->GetFontNode( pElement->iFont )->nHeight )
  3050.             m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) / DXUTGetGlobalDialogResourceManager()->GetFontNode( pElement->iFont )->nHeight );
  3051.         else
  3052.             m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) );
  3053.         bSBInit = true;
  3054.     }
  3055.  
  3056.     // Scroll bar
  3057.     if( m_bOpened )
  3058.         m_ScrollBar.Render( pd3dDevice, fElapsedTime );
  3059.  
  3060.     // Blend current color
  3061.     pElement->TextureColor.Blend( iState, fElapsedTime );
  3062.     pElement->FontColor.Blend( iState, fElapsedTime );
  3063.  
  3064.     m_pDialog->DrawSprite( pElement, &m_rcDropdown );
  3065.  
  3066.     // Selection outline
  3067.     CDXUTElement* pSelectionElement = m_Elements.GetAt( 3 );
  3068.     pSelectionElement->TextureColor.Current = pElement->TextureColor.Current;
  3069.     pSelectionElement->FontColor.Current = pSelectionElement->FontColor.States[ DXUT_STATE_NORMAL ];
  3070.  
  3071.     DXUTFontNode* pFont = m_pDialog->GetFont( pElement->iFont );
  3072.     int curY = m_rcDropdownText.top;
  3073.     int nRemainingHeight = RectHeight( m_rcDropdownText );
  3074.     //WCHAR strDropdown[4096] = {0};
  3075.  
  3076.     for( int i = m_ScrollBar.GetTrackPos(); i < m_Items.GetSize(); i++ )
  3077.     {
  3078.         DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  3079.  
  3080.         // Make sure there's room left in the dropdown
  3081.         nRemainingHeight -= pFont->nHeight;
  3082.         if( nRemainingHeight < 0 )
  3083.         {
  3084.             pItem->bVisible = false;
  3085.             continue;
  3086.         }
  3087.  
  3088.         SetRect( &pItem->rcActive, m_rcDropdownText.left, curY, m_rcDropdownText.right, curY + pFont->nHeight );
  3089.         curY += pFont->nHeight;
  3090.         
  3091.         //debug
  3092.         //int blue = 50 * i;
  3093.         //m_pDialog->DrawRect( &pItem->rcActive, 0xFFFF0000 | blue );
  3094.  
  3095.         pItem->bVisible = true;
  3096.  
  3097.         if( m_bOpened )
  3098.         {
  3099.             if( (int)i == m_iFocused )
  3100.             {
  3101.                 RECT rc;
  3102.                 SetRect( &rc, m_rcDropdown.left, pItem->rcActive.top-2, m_rcDropdown.right, pItem->rcActive.bottom+2 );
  3103.                 m_pDialog->DrawSprite( pSelectionElement, &rc );
  3104.                 m_pDialog->DrawText( pItem->strText, pSelectionElement, &pItem->rcActive );
  3105.             }
  3106.             else
  3107.             {
  3108.                 m_pDialog->DrawText( pItem->strText, pElement, &pItem->rcActive );
  3109.             }
  3110.         }
  3111.     }
  3112.  
  3113.     int nOffsetX = 0;
  3114.     int nOffsetY = 0;
  3115.  
  3116.     iState = DXUT_STATE_NORMAL;
  3117.     
  3118.     if( m_bVisible == false )
  3119.         iState = DXUT_STATE_HIDDEN;
  3120.     else if( m_bEnabled == false )
  3121.         iState = DXUT_STATE_DISABLED;
  3122.     else if( m_bPressed )
  3123.     {
  3124.         iState = DXUT_STATE_PRESSED;
  3125.  
  3126.         nOffsetX = 1;
  3127.         nOffsetY = 2;
  3128.     }
  3129.     else if( m_bMouseOver )
  3130.     {
  3131.         iState = DXUT_STATE_MOUSEOVER;
  3132.  
  3133.         nOffsetX = -1;
  3134.         nOffsetY = -2;
  3135.     }
  3136.     else if( m_bHasFocus )
  3137.         iState = DXUT_STATE_FOCUS;
  3138.  
  3139.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  3140.     
  3141.     // Button
  3142.     pElement = m_Elements.GetAt( 1 );
  3143.     
  3144.     // Blend current color
  3145.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  3146.     
  3147.     RECT rcWindow = m_rcButton;
  3148.     OffsetRect( &rcWindow, nOffsetX, nOffsetY );
  3149.     m_pDialog->DrawSprite( pElement, &rcWindow );
  3150.  
  3151.     if( m_bOpened )
  3152.         iState = DXUT_STATE_PRESSED;
  3153.  
  3154.     // Main text box
  3155.     //TODO: remove magic numbers
  3156.     pElement = m_Elements.GetAt( 0 );
  3157.     
  3158.     // Blend current color
  3159.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  3160.     pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate );
  3161.  
  3162.     m_pDialog->DrawSprite( pElement, &m_rcText);
  3163.     
  3164.     if( m_iSelected >= 0 && m_iSelected < (int) m_Items.GetSize() )
  3165.     {
  3166.         DXUTComboBoxItem* pItem = m_Items.GetAt( m_iSelected );
  3167.         if( pItem != NULL )
  3168.         {
  3169.             m_pDialog->DrawText( pItem->strText, pElement, &m_rcText );
  3170.         
  3171.         }
  3172.     }
  3173. }
  3174.  
  3175.  
  3176. //--------------------------------------------------------------------------------------
  3177. HRESULT CDXUTComboBox::AddItem( const WCHAR* strText, void* pData )
  3178. {
  3179.     // Validate parameters
  3180.     if( strText== NULL )
  3181.     {
  3182.         return E_INVALIDARG;
  3183.     }
  3184.     
  3185.     // Create a new item and set the data
  3186.     DXUTComboBoxItem* pItem = new DXUTComboBoxItem;
  3187.     if( pItem == NULL )
  3188.     {
  3189.         return DXTRACE_ERR_MSGBOX( L"new", E_OUTOFMEMORY );
  3190.     }
  3191.     
  3192.     ZeroMemory( pItem, sizeof(DXUTComboBoxItem) );
  3193.     wcsncpy( pItem->strText, strText, 255 );
  3194.     pItem->pData = pData;
  3195.  
  3196.     m_Items.Add( pItem );
  3197.  
  3198.     // Update the scroll bar with new range
  3199.     m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  3200.  
  3201.     // If this is the only item in the list, it's selected
  3202.     if( GetNumItems() == 1 )
  3203.     {
  3204.         m_iSelected = 0;
  3205.         m_iFocused = 0;
  3206.         m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  3207.     }
  3208.  
  3209.     return S_OK;
  3210. }
  3211.  
  3212.  
  3213. //--------------------------------------------------------------------------------------
  3214. void CDXUTComboBox::RemoveItem( UINT index )
  3215. {
  3216.     DXUTComboBoxItem* pItem = m_Items.GetAt( index );
  3217.     SAFE_DELETE( pItem );
  3218.     m_Items.Remove( index );
  3219.     m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  3220.     if( m_iSelected >= m_Items.GetSize() )
  3221.         m_iSelected = m_Items.GetSize() - 1;
  3222. }
  3223.  
  3224.  
  3225. //--------------------------------------------------------------------------------------
  3226. void CDXUTComboBox::RemoveAllItems()
  3227. {
  3228.     for( int i=0; i < m_Items.GetSize(); i++ )
  3229.     {
  3230.         DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  3231.         SAFE_DELETE( pItem );
  3232.     }
  3233.  
  3234.     m_Items.RemoveAll();
  3235.     m_ScrollBar.SetTrackRange( 0, 1 );
  3236.     m_iFocused = m_iSelected = -1;
  3237. }
  3238.  
  3239.  
  3240.  
  3241. //--------------------------------------------------------------------------------------
  3242. bool CDXUTComboBox::ContainsItem( const WCHAR* strText, UINT iStart )
  3243. {
  3244.     return ( -1 != FindItem( strText, iStart ) );
  3245. }
  3246.  
  3247.  
  3248. //--------------------------------------------------------------------------------------
  3249. int CDXUTComboBox::FindItem( const WCHAR* strText, UINT iStart )
  3250. {
  3251.     if( strText == NULL )
  3252.         return -1;
  3253.  
  3254.     for( int i = iStart; i < m_Items.GetSize(); i++ )
  3255.     {
  3256.         DXUTComboBoxItem* pItem = m_Items.GetAt(i);
  3257.  
  3258.         if( 0 == wcscmp( pItem->strText, strText ) )
  3259.         {
  3260.             return i;
  3261.         }
  3262.     }
  3263.  
  3264.     return -1;
  3265. }
  3266.  
  3267.  
  3268. //--------------------------------------------------------------------------------------
  3269. void* CDXUTComboBox::GetSelectedData()
  3270. {
  3271.     if( m_iSelected < 0 )
  3272.         return NULL;
  3273.  
  3274.     DXUTComboBoxItem* pItem = m_Items.GetAt( m_iSelected );
  3275.     return pItem->pData;
  3276. }
  3277.  
  3278.  
  3279. //--------------------------------------------------------------------------------------
  3280. DXUTComboBoxItem* CDXUTComboBox::GetSelectedItem()
  3281. {
  3282.     if( m_iSelected < 0 )
  3283.         return NULL;
  3284.  
  3285.     return m_Items.GetAt( m_iSelected );
  3286. }
  3287.  
  3288.  
  3289. //--------------------------------------------------------------------------------------
  3290. void* CDXUTComboBox::GetItemData( const WCHAR* strText )
  3291. {
  3292.     int index = FindItem( strText );
  3293.     if( index == -1 )
  3294.     {
  3295.         return NULL;
  3296.     }
  3297.  
  3298.     DXUTComboBoxItem* pItem = m_Items.GetAt(index);
  3299.     if( pItem == NULL )
  3300.     {
  3301.         DXTRACE_ERR( L"CGrowableArray::GetAt", E_FAIL );
  3302.         return NULL;
  3303.     }
  3304.  
  3305.     return pItem->pData;
  3306. }
  3307.  
  3308.  
  3309. //--------------------------------------------------------------------------------------
  3310. void* CDXUTComboBox::GetItemData( int nIndex )
  3311. {
  3312.     if( nIndex < 0 || nIndex >= m_Items.GetSize() )
  3313.         return NULL;
  3314.  
  3315.     return m_Items.GetAt( nIndex )->pData;
  3316. }
  3317.  
  3318.  
  3319. //--------------------------------------------------------------------------------------
  3320. HRESULT CDXUTComboBox::SetSelectedByIndex( UINT index )
  3321. {
  3322.     if( index >= GetNumItems() )
  3323.         return E_INVALIDARG;
  3324.  
  3325.     m_iFocused = m_iSelected = index;
  3326.     m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  3327.  
  3328.     return S_OK;
  3329. }
  3330.  
  3331.  
  3332.  
  3333. //--------------------------------------------------------------------------------------
  3334. HRESULT CDXUTComboBox::SetSelectedByText( const WCHAR* strText )
  3335. {
  3336.     if( strText == NULL )
  3337.         return E_INVALIDARG;
  3338.  
  3339.     int index = FindItem( strText );
  3340.     if( index == -1 )
  3341.         return E_FAIL;
  3342.  
  3343.     m_iFocused = m_iSelected = index;
  3344.     m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  3345.  
  3346.     return S_OK;
  3347. }
  3348.  
  3349.  
  3350.  
  3351. //--------------------------------------------------------------------------------------
  3352. HRESULT CDXUTComboBox::SetSelectedByData( void* pData )
  3353. {
  3354.     for( int i=0; i < m_Items.GetSize(); i++ )
  3355.     {
  3356.         DXUTComboBoxItem* pItem = m_Items.GetAt(i);
  3357.  
  3358.         if( pItem->pData == pData )
  3359.         {
  3360.             m_iFocused = m_iSelected = i;
  3361.             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  3362.             return S_OK;
  3363.         }
  3364.     }
  3365.  
  3366.     return E_FAIL;
  3367. }
  3368.  
  3369.  
  3370.  
  3371. //--------------------------------------------------------------------------------------
  3372. CDXUTSlider::CDXUTSlider( CDXUTDialog *pDialog )
  3373. {
  3374.     m_Type = DXUT_CONTROL_SLIDER;
  3375.     m_pDialog = pDialog;
  3376.  
  3377.     m_nMin = 0;
  3378.     m_nMax = 100;
  3379.     m_nValue = 50;
  3380.  
  3381.     m_bPressed = false;
  3382. }
  3383.  
  3384.  
  3385. //--------------------------------------------------------------------------------------
  3386. BOOL CDXUTSlider::ContainsPoint( POINT pt ) 
  3387.     return ( PtInRect( &m_rcBoundingBox, pt ) || 
  3388.              PtInRect( &m_rcButton, pt ) ); 
  3389. }
  3390.  
  3391.  
  3392. //--------------------------------------------------------------------------------------
  3393. void CDXUTSlider::UpdateRects()
  3394. {
  3395.     CDXUTControl::UpdateRects();
  3396.  
  3397.     m_rcButton = m_rcBoundingBox;
  3398.     m_rcButton.right = m_rcButton.left + RectHeight( m_rcButton );
  3399.     OffsetRect( &m_rcButton, -RectWidth( m_rcButton )/2, 0 );
  3400.  
  3401.     m_nButtonX = (int) ( (m_nValue - m_nMin) * (float)RectWidth( m_rcBoundingBox ) / (m_nMax - m_nMin) );
  3402.     OffsetRect( &m_rcButton, m_nButtonX, 0 );
  3403. }
  3404.  
  3405. int CDXUTSlider::ValueFromPos( int x )
  3406.     float fValuePerPixel = (float)(m_nMax - m_nMin) / RectWidth( m_rcBoundingBox );
  3407.     return (int) (0.5f + m_nMin + fValuePerPixel * (x - m_rcBoundingBox.left)) ; 
  3408. }
  3409.  
  3410. //--------------------------------------------------------------------------------------
  3411. bool CDXUTSlider::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  3412. {
  3413.     if( !m_bEnabled || !m_bVisible )
  3414.         return false;
  3415.  
  3416.     switch( uMsg )
  3417.     {
  3418.         case WM_KEYDOWN:
  3419.         {
  3420.             switch( wParam )
  3421.             {
  3422.                 case VK_HOME:
  3423.                     SetValueInternal( m_nMin, true );
  3424.                     return true;
  3425.  
  3426.                 case VK_END:
  3427.                     SetValueInternal( m_nMax, true );
  3428.                     return true;
  3429.  
  3430.                 case VK_PRIOR:
  3431.                 case VK_LEFT:
  3432.                 case VK_UP:
  3433.                     SetValueInternal( m_nValue - 1, true );
  3434.                     return true;
  3435.  
  3436.                 case VK_NEXT:
  3437.                 case VK_RIGHT:
  3438.                 case VK_DOWN:
  3439.                     SetValueInternal( m_nValue + 1, true );
  3440.                     return true;
  3441.             }
  3442.             break;
  3443.         }
  3444.     }
  3445.     
  3446.  
  3447.     return false;
  3448. }
  3449.  
  3450.  
  3451. //--------------------------------------------------------------------------------------
  3452. bool CDXUTSlider::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  3453. {
  3454.     if( !m_bEnabled || !m_bVisible )
  3455.         return false;
  3456.  
  3457.     switch( uMsg )
  3458.     {
  3459.         case WM_LBUTTONDOWN:
  3460.         case WM_LBUTTONDBLCLK:
  3461.         {
  3462.             if( PtInRect( &m_rcButton, pt ) )
  3463.             {
  3464.                 // Pressed while inside the control
  3465.                 m_bPressed = true;
  3466.                 SetCapture( DXUTGetHWND() );
  3467.  
  3468.                 m_nDragX = pt.x;
  3469.                 //m_nDragY = pt.y;
  3470.                 m_nDragOffset = m_nButtonX - m_nDragX;
  3471.  
  3472.                 //m_nDragValue = m_nValue;
  3473.  
  3474.                 if( !m_bHasFocus )
  3475.                     m_pDialog->RequestFocus( this );
  3476.  
  3477.                 return true;
  3478.             }
  3479.  
  3480.             if( PtInRect( &m_rcBoundingBox, pt ) )
  3481.             {
  3482.                if( pt.x > m_nButtonX + m_x )
  3483.                {
  3484.                    SetValueInternal( m_nValue + 1, true );
  3485.                    return true;
  3486.                }
  3487.  
  3488.                if( pt.x < m_nButtonX + m_x )
  3489.                {
  3490.                    SetValueInternal( m_nValue - 1, true );
  3491.                    return true;
  3492.                }
  3493.             }
  3494.  
  3495.             break;
  3496.         }
  3497.  
  3498.         case WM_LBUTTONUP:
  3499.         {
  3500.             if( m_bPressed )
  3501.             {
  3502.                 m_bPressed = false;
  3503.                 ReleaseCapture();
  3504.                 m_pDialog->ClearFocus();
  3505.                 m_pDialog->SendEvent( EVENT_SLIDER_VALUE_CHANGED, true, this );
  3506.  
  3507.                 return true;
  3508.             }
  3509.  
  3510.             break;
  3511.         }
  3512.  
  3513.         case WM_MOUSEMOVE:
  3514.         {
  3515.             if( m_bPressed )
  3516.             {
  3517.                 SetValueInternal( ValueFromPos( m_x + pt.x + m_nDragOffset ), true );
  3518.                 return true;
  3519.             }
  3520.  
  3521.             break;
  3522.         }
  3523.     };
  3524.     
  3525.     return false;
  3526. }
  3527.  
  3528.  
  3529. //--------------------------------------------------------------------------------------
  3530. void CDXUTSlider::SetRange( int nMin, int nMax ) 
  3531. {
  3532.     m_nMin = nMin; 
  3533.     m_nMax = nMax; 
  3534.  
  3535.     SetValueInternal( m_nValue, false );
  3536. }
  3537.  
  3538.  
  3539.  
  3540. //--------------------------------------------------------------------------------------
  3541. void CDXUTSlider::SetValueInternal( int nValue, bool bFromInput )
  3542. {
  3543.     // Clamp to range
  3544.     nValue = max( m_nMin, nValue );
  3545.     nValue = min( m_nMax, nValue );
  3546.     
  3547.     if( nValue == m_nValue )
  3548.         return;
  3549.  
  3550.     m_nValue = nValue;
  3551.     UpdateRects();
  3552.  
  3553.     m_pDialog->SendEvent( EVENT_SLIDER_VALUE_CHANGED, bFromInput, this );
  3554. }
  3555.  
  3556.  
  3557. //--------------------------------------------------------------------------------------
  3558. void CDXUTSlider::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  3559. {
  3560.     int nOffsetX = 0;
  3561.     int nOffsetY = 0;
  3562.  
  3563.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  3564.  
  3565.     if( m_bVisible == false )
  3566.     {
  3567.         iState = DXUT_STATE_HIDDEN;
  3568.     }
  3569.     else if( m_bEnabled == false )
  3570.     {
  3571.         iState = DXUT_STATE_DISABLED;
  3572.     }
  3573.     else if( m_bPressed )
  3574.     {
  3575.         iState = DXUT_STATE_PRESSED;
  3576.  
  3577.         nOffsetX = 1;
  3578.         nOffsetY = 2;
  3579.     }
  3580.     else if( m_bMouseOver )
  3581.     {
  3582.         iState = DXUT_STATE_MOUSEOVER;
  3583.         
  3584.         nOffsetX = -1;
  3585.         nOffsetY = -2;
  3586.     }
  3587.     else if( m_bHasFocus )
  3588.     {
  3589.         iState = DXUT_STATE_FOCUS;
  3590.     }
  3591.  
  3592.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  3593.  
  3594.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  3595.     
  3596.     // Blend current color
  3597.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); 
  3598.     m_pDialog->DrawSprite( pElement, &m_rcBoundingBox );
  3599.  
  3600.     //TODO: remove magic numbers
  3601.     pElement = m_Elements.GetAt( 1 );
  3602.        
  3603.     // Blend current color
  3604.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  3605.     m_pDialog->DrawSprite( pElement, &m_rcButton );
  3606. }
  3607.  
  3608.  
  3609. //--------------------------------------------------------------------------------------
  3610. // CDXUTScrollBar class
  3611. //--------------------------------------------------------------------------------------
  3612.  
  3613. //--------------------------------------------------------------------------------------
  3614. CDXUTScrollBar::CDXUTScrollBar( CDXUTDialog *pDialog )
  3615. {
  3616.     m_Type = DXUT_CONTROL_SCROLLBAR;
  3617.     m_pDialog = pDialog;
  3618.  
  3619.     m_bShowThumb = true;
  3620.  
  3621.     SetRect( &m_rcUpButton, 0, 0, 0, 0 );
  3622.     SetRect( &m_rcDownButton, 0, 0, 0, 0 );
  3623.     SetRect( &m_rcTrack, 0, 0, 0, 0 );
  3624.     SetRect( &m_rcThumb, 0, 0, 0, 0 );
  3625.     m_nPosition = 0;
  3626.     m_nPageSize = 1;
  3627.     m_nStart = 0;
  3628.     m_nEnd = 1;
  3629.     m_Arrow = CLEAR;
  3630.     m_dArrowTS = 0.0;
  3631. }
  3632.  
  3633.  
  3634. //--------------------------------------------------------------------------------------
  3635. CDXUTScrollBar::~CDXUTScrollBar()
  3636. {
  3637. }
  3638.  
  3639.  
  3640. //--------------------------------------------------------------------------------------
  3641. void CDXUTScrollBar::UpdateRects()
  3642. {
  3643.     CDXUTControl::UpdateRects();
  3644.  
  3645.     // Make the buttons square
  3646.  
  3647.     SetRect( &m_rcUpButton, m_rcBoundingBox.left, m_rcBoundingBox.top,
  3648.                             m_rcBoundingBox.right, m_rcBoundingBox.top + RectWidth( m_rcBoundingBox ) );
  3649.     SetRect( &m_rcDownButton, m_rcBoundingBox.left, m_rcBoundingBox.bottom - RectWidth( m_rcBoundingBox ),
  3650.                               m_rcBoundingBox.right, m_rcBoundingBox.bottom );
  3651.     SetRect( &m_rcTrack, m_rcUpButton.left, m_rcUpButton.bottom,
  3652.                          m_rcDownButton.right, m_rcDownButton.top );
  3653.     m_rcThumb.left = m_rcUpButton.left;
  3654.     m_rcThumb.right = m_rcUpButton.right;
  3655.  
  3656.     UpdateThumbRect();
  3657. }
  3658.  
  3659.  
  3660. //--------------------------------------------------------------------------------------
  3661. // Compute the dimension of the scroll thumb
  3662. void CDXUTScrollBar::UpdateThumbRect()
  3663. {
  3664.     if( m_nEnd - m_nStart > m_nPageSize )
  3665.     {
  3666.         int nThumbHeight = max( RectHeight( m_rcTrack ) * m_nPageSize / ( m_nEnd - m_nStart ), SCROLLBAR_MINTHUMBSIZE );
  3667.         int nMaxPosition = m_nEnd - m_nStart - m_nPageSize;
  3668.         m_rcThumb.top = m_rcTrack.top + ( m_nPosition - m_nStart ) * ( RectHeight( m_rcTrack ) - nThumbHeight )
  3669.                         / nMaxPosition;
  3670.         m_rcThumb.bottom = m_rcThumb.top + nThumbHeight;
  3671.         m_bShowThumb = true;
  3672.  
  3673.     } 
  3674.     else
  3675.     {
  3676.         // No content to scroll
  3677.         m_rcThumb.bottom = m_rcThumb.top;
  3678.         m_bShowThumb = false;
  3679.     }
  3680. }
  3681.  
  3682.  
  3683. //--------------------------------------------------------------------------------------
  3684. // Scroll() scrolls by nDelta items.  A positive value scrolls down, while a negative
  3685. // value scrolls up.
  3686. void CDXUTScrollBar::Scroll( int nDelta )
  3687. {
  3688.     // Perform scroll
  3689.     m_nPosition += nDelta;
  3690.  
  3691.     // Cap position
  3692.     Cap();
  3693.  
  3694.     // Update thumb position
  3695.     UpdateThumbRect();
  3696. }
  3697.  
  3698.  
  3699. //--------------------------------------------------------------------------------------
  3700. void CDXUTScrollBar::ShowItem( int nIndex )
  3701. {
  3702.     // Cap the index
  3703.  
  3704.     if( nIndex < 0 )
  3705.         nIndex = 0;
  3706.  
  3707.     if( nIndex >= m_nEnd )
  3708.         nIndex = m_nEnd - 1;
  3709.  
  3710.     // Adjust position
  3711.  
  3712.     if( m_nPosition > nIndex )
  3713.         m_nPosition = nIndex;
  3714.     else
  3715.     if( m_nPosition + m_nPageSize <= nIndex )
  3716.         m_nPosition = nIndex - m_nPageSize + 1;
  3717.  
  3718.     UpdateThumbRect();
  3719. }
  3720.  
  3721.  
  3722. //--------------------------------------------------------------------------------------
  3723. bool CDXUTScrollBar::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  3724. {
  3725.     return false;
  3726. }
  3727.  
  3728.  
  3729. //--------------------------------------------------------------------------------------
  3730. bool CDXUTScrollBar::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  3731. {
  3732.     static int ThumbOffsetY;
  3733.     static bool bDrag;
  3734.  
  3735.     m_LastMouse = pt;
  3736.     switch( uMsg )
  3737.     {
  3738.         case WM_LBUTTONDOWN:
  3739.         case WM_LBUTTONDBLCLK:
  3740.         {
  3741.             SetCapture( DXUTGetHWND() );
  3742.  
  3743.             // Check for click on up button
  3744.  
  3745.             if( PtInRect( &m_rcUpButton, pt ) )
  3746.             {
  3747.                 if( m_nPosition > m_nStart )
  3748.                     --m_nPosition;
  3749.                 UpdateThumbRect();
  3750.                 m_Arrow = CLICKED_UP;
  3751.                 m_dArrowTS = DXUTGetTime();
  3752.                 return true;
  3753.             }
  3754.  
  3755.             // Check for click on down button
  3756.  
  3757.             if( PtInRect( &m_rcDownButton, pt ) )
  3758.             {
  3759.                 if( m_nPosition + m_nPageSize < m_nEnd )
  3760.                     ++m_nPosition;
  3761.                 UpdateThumbRect();
  3762.                 m_Arrow = CLICKED_DOWN;
  3763.                 m_dArrowTS = DXUTGetTime();
  3764.                 return true;
  3765.             }
  3766.  
  3767.             // Check for click on thumb
  3768.  
  3769.             if( PtInRect( &m_rcThumb, pt ) )
  3770.             {
  3771.                 bDrag = true;
  3772.                 ThumbOffsetY = pt.y - m_rcThumb.top;
  3773.                 return true;
  3774.             }
  3775.  
  3776.             // Check for click on track
  3777.  
  3778.             if( m_rcThumb.left <= pt.x &&
  3779.                 m_rcThumb.right > pt.x )
  3780.             {
  3781.                 if( m_rcThumb.top > pt.y &&
  3782.                     m_rcTrack.top <= pt.y )
  3783.                 {
  3784.                     Scroll( -( m_nPageSize - 1 ) );
  3785.                     return true;
  3786.                 } else
  3787.                 if( m_rcThumb.bottom <= pt.y &&
  3788.                     m_rcTrack.bottom > pt.y )
  3789.                 {
  3790.                     Scroll( m_nPageSize - 1 );
  3791.                     return true;
  3792.                 }
  3793.             }
  3794.  
  3795.             break;
  3796.         }
  3797.  
  3798.         case WM_LBUTTONUP:
  3799.         {
  3800.             bDrag = false;
  3801.             ReleaseCapture();
  3802.             UpdateThumbRect();
  3803.             m_Arrow = CLEAR;
  3804.             break;
  3805.         }
  3806.  
  3807.         case WM_MOUSEMOVE:
  3808.         {
  3809.             if( bDrag )
  3810.             {
  3811.                 m_rcThumb.bottom += pt.y - ThumbOffsetY - m_rcThumb.top;
  3812.                 m_rcThumb.top = pt.y - ThumbOffsetY;
  3813.                 if( m_rcThumb.top < m_rcTrack.top )
  3814.                     OffsetRect( &m_rcThumb, 0, m_rcTrack.top - m_rcThumb.top );
  3815.                 else
  3816.                 if( m_rcThumb.bottom > m_rcTrack.bottom )
  3817.                     OffsetRect( &m_rcThumb, 0, m_rcTrack.bottom - m_rcThumb.bottom );
  3818.  
  3819.                 // Compute first item index based on thumb position
  3820.  
  3821.                 int nMaxFirstItem = m_nEnd - m_nStart - m_nPageSize;  // Largest possible index for first item
  3822.                 int nMaxThumb = RectHeight( m_rcTrack ) - RectHeight( m_rcThumb );  // Largest possible thumb position from the top
  3823.  
  3824.                 m_nPosition = m_nStart +
  3825.                               ( m_rcThumb.top - m_rcTrack.top +
  3826.                                 nMaxThumb / ( nMaxFirstItem * 2 ) ) * // Shift by half a row to avoid last row covered by only one pixel
  3827.                               nMaxFirstItem  / nMaxThumb;
  3828.  
  3829.                 return true;
  3830.             }
  3831.  
  3832.             break;
  3833.         }
  3834.     }
  3835.  
  3836.     return false;
  3837. }
  3838.  
  3839.  
  3840. //--------------------------------------------------------------------------------------
  3841. void CDXUTScrollBar::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  3842. {
  3843.     // Check if the arrow button has been held for a while.
  3844.     // If so, update the thumb position to simulate repeated
  3845.     // scroll.
  3846.     if( m_Arrow != CLEAR )
  3847.     {
  3848.         double dCurrTime = DXUTGetTime();
  3849.         if( PtInRect( &m_rcUpButton, m_LastMouse ) )
  3850.         {
  3851.             switch( m_Arrow )
  3852.             {
  3853.                 case CLICKED_UP:
  3854.                     if( SCROLLBAR_ARROWCLICK_DELAY < dCurrTime - m_dArrowTS )
  3855.                     {
  3856.                         Scroll( -1 );
  3857.                         m_Arrow = HELD_UP;
  3858.                         m_dArrowTS = dCurrTime;
  3859.                     }
  3860.                     break;
  3861.                 case HELD_UP:
  3862.                     if( SCROLLBAR_ARROWCLICK_REPEAT < dCurrTime - m_dArrowTS )
  3863.                     {
  3864.                         Scroll( -1 );
  3865.                         m_dArrowTS = dCurrTime;
  3866.                     }
  3867.                     break;
  3868.             }
  3869.         } else
  3870.         if( PtInRect( &m_rcDownButton, m_LastMouse ) )
  3871.         {
  3872.             switch( m_Arrow )
  3873.             {
  3874.                 case CLICKED_DOWN:
  3875.                     if( SCROLLBAR_ARROWCLICK_DELAY < dCurrTime - m_dArrowTS )
  3876.                     {
  3877.                         Scroll( 1 );
  3878.                         m_Arrow = HELD_DOWN;
  3879.                         m_dArrowTS = dCurrTime;
  3880.                     }
  3881.                     break;
  3882.                 case HELD_DOWN:
  3883.                     if( SCROLLBAR_ARROWCLICK_REPEAT < dCurrTime - m_dArrowTS )
  3884.                     {
  3885.                         Scroll( 1 );
  3886.                         m_dArrowTS = dCurrTime;
  3887.                     }
  3888.                     break;
  3889.             }
  3890.         }
  3891.     }
  3892.  
  3893.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  3894.  
  3895.     if( m_bVisible == false )
  3896.         iState = DXUT_STATE_HIDDEN;
  3897.     else if( m_bEnabled == false || m_bShowThumb == false )
  3898.         iState = DXUT_STATE_DISABLED;
  3899.     else if( m_bMouseOver )
  3900.         iState = DXUT_STATE_MOUSEOVER;
  3901.     else if( m_bHasFocus )
  3902.         iState = DXUT_STATE_FOCUS;
  3903.  
  3904.  
  3905.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  3906.  
  3907.     // Background track layer
  3908.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  3909.     
  3910.     // Blend current color
  3911.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  3912.     m_pDialog->DrawSprite( pElement, &m_rcTrack );
  3913.  
  3914.     // Up Arrow
  3915.     pElement = m_Elements.GetAt( 1 );
  3916.     
  3917.     // Blend current color
  3918.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  3919.     m_pDialog->DrawSprite( pElement, &m_rcUpButton );
  3920.  
  3921.     // Down Arrow
  3922.     pElement = m_Elements.GetAt( 2 );
  3923.     
  3924.     // Blend current color
  3925.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  3926.     m_pDialog->DrawSprite( pElement, &m_rcDownButton );
  3927.  
  3928.     // Thumb button
  3929.     pElement = m_Elements.GetAt( 3 );
  3930.     
  3931.     // Blend current color
  3932.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  3933.     m_pDialog->DrawSprite( pElement, &m_rcThumb );
  3934.  
  3935. }
  3936.  
  3937.  
  3938. //--------------------------------------------------------------------------------------
  3939. void CDXUTScrollBar::SetTrackRange( int nStart, int nEnd )
  3940. {
  3941.     m_nStart = nStart; m_nEnd = nEnd;
  3942.     Cap();
  3943.     UpdateThumbRect();
  3944. }
  3945.  
  3946.  
  3947. //--------------------------------------------------------------------------------------
  3948. void CDXUTScrollBar::Cap()  // Clips position at boundaries. Ensures it stays within legal range.
  3949. {
  3950.     if( m_nPosition < m_nStart ||
  3951.         m_nEnd - m_nStart <= m_nPageSize )
  3952.     {
  3953.         m_nPosition = m_nStart;
  3954.     }
  3955.     else
  3956.     if( m_nPosition + m_nPageSize > m_nEnd )
  3957.         m_nPosition = m_nEnd - m_nPageSize;
  3958. }
  3959.  
  3960. //--------------------------------------------------------------------------------------
  3961. // CDXUTListBox class
  3962. //--------------------------------------------------------------------------------------
  3963.  
  3964. //--------------------------------------------------------------------------------------
  3965. CDXUTListBox::CDXUTListBox( CDXUTDialog *pDialog ) :
  3966.     m_ScrollBar( pDialog )
  3967. {
  3968.     m_Type = DXUT_CONTROL_LISTBOX;
  3969.     m_pDialog = pDialog;
  3970.  
  3971.     m_dwStyle = 0;
  3972.     m_nSBWidth = 16;
  3973.     m_nSelected = -1;
  3974.     m_nSelStart = 0;
  3975.     m_bDrag = false;
  3976.     m_nBorder = 6;
  3977.     m_nMargin = 5;
  3978.     m_nTextHeight = 0;
  3979. }
  3980.  
  3981.  
  3982. //--------------------------------------------------------------------------------------
  3983. CDXUTListBox::~CDXUTListBox()
  3984. {
  3985.     RemoveAllItems();
  3986. }
  3987.  
  3988.  
  3989. //--------------------------------------------------------------------------------------
  3990. void CDXUTListBox::UpdateRects()
  3991. {
  3992.     CDXUTControl::UpdateRects();
  3993.  
  3994.     m_rcSelection = m_rcBoundingBox;
  3995.     m_rcSelection.right -= m_nSBWidth;
  3996.     InflateRect( &m_rcSelection, -m_nBorder, -m_nBorder );
  3997.     m_rcText = m_rcSelection;
  3998.     InflateRect( &m_rcText, -m_nMargin, 0 );
  3999.  
  4000.     // Update the scrollbar's rects
  4001.     m_ScrollBar.SetLocation( m_rcBoundingBox.right - m_nSBWidth, m_rcBoundingBox.top );
  4002.     m_ScrollBar.SetSize( m_nSBWidth, m_height );
  4003.     DXUTFontNode* pFontNode = DXUTGetGlobalDialogResourceManager()->GetFontNode( m_Elements.GetAt( 0 )->iFont );
  4004.     if( pFontNode && pFontNode->nHeight )
  4005.     {
  4006.         m_ScrollBar.SetPageSize( RectHeight( m_rcText ) / pFontNode->nHeight );
  4007.  
  4008.         // The selected item may have been scrolled off the page.
  4009.         // Ensure that it is in page again.
  4010.         m_ScrollBar.ShowItem( m_nSelected );
  4011.     }
  4012. }
  4013.  
  4014.  
  4015. //--------------------------------------------------------------------------------------
  4016. HRESULT CDXUTListBox::AddItem( const WCHAR *wszText, void *pData )
  4017. {
  4018.     DXUTListBoxItem *pNewItem = new DXUTListBoxItem;
  4019.     if( !pNewItem )
  4020.         return E_OUTOFMEMORY;
  4021.  
  4022.     wcsncpy( pNewItem->strText, wszText, 256 );
  4023.     pNewItem->strText[255] = L'\0';
  4024.     pNewItem->pData = pData;
  4025.     SetRect( &pNewItem->rcActive, 0, 0, 0, 0 );
  4026.     pNewItem->bSelected = false;
  4027.  
  4028.     HRESULT hr = m_Items.Add( pNewItem );
  4029.     if( SUCCEEDED( hr ) )
  4030.         m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  4031.  
  4032.     return hr;
  4033. }
  4034.  
  4035.  
  4036. //--------------------------------------------------------------------------------------
  4037. HRESULT CDXUTListBox::InsertItem( int nIndex, const WCHAR *wszText, void *pData )
  4038. {
  4039.     DXUTListBoxItem *pNewItem = new DXUTListBoxItem;
  4040.     if( !pNewItem )
  4041.         return E_OUTOFMEMORY;
  4042.  
  4043.     wcsncpy( pNewItem->strText, wszText, 256 );
  4044.     pNewItem->strText[255] = L'\0';
  4045.     pNewItem->pData = pData;
  4046.     SetRect( &pNewItem->rcActive, 0, 0, 0, 0 );
  4047.     pNewItem->bSelected = false;
  4048.  
  4049.     HRESULT hr = m_Items.Insert( nIndex, pNewItem );
  4050.     if( SUCCEEDED( hr ) )
  4051.         m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  4052.  
  4053.     return hr;
  4054. }
  4055.  
  4056.  
  4057. //--------------------------------------------------------------------------------------
  4058. void CDXUTListBox::RemoveItem( int nIndex )
  4059. {
  4060.     if( nIndex < 0 || nIndex >= (int)m_Items.GetSize() )
  4061.         return;
  4062.  
  4063.     DXUTListBoxItem *pItem = m_Items.GetAt( nIndex );
  4064.  
  4065.     delete pItem;
  4066.     m_Items.Remove( nIndex );
  4067.     m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  4068.     if( m_nSelected >= (int)m_Items.GetSize() )
  4069.         m_nSelected = m_Items.GetSize() - 1;
  4070.  
  4071.     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4072. }
  4073.  
  4074.  
  4075. //--------------------------------------------------------------------------------------
  4076. void CDXUTListBox::RemoveItemByText( WCHAR *wszText )
  4077. {
  4078. }
  4079.  
  4080.  
  4081. //--------------------------------------------------------------------------------------
  4082. void CDXUTListBox::RemoveItemByData( void *pData )
  4083. {
  4084. }
  4085.  
  4086.  
  4087. //--------------------------------------------------------------------------------------
  4088. void CDXUTListBox::RemoveAllItems()
  4089. {
  4090.     for( int i = 0; i < m_Items.GetSize(); ++i )
  4091.     {
  4092.         DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4093.         delete pItem;
  4094.     }
  4095.  
  4096.     m_Items.RemoveAll();
  4097.     m_ScrollBar.SetTrackRange( 0, 1 );
  4098. }
  4099.  
  4100.  
  4101. //--------------------------------------------------------------------------------------
  4102. DXUTListBoxItem *CDXUTListBox::GetItem( int nIndex )
  4103. {
  4104.     if( nIndex < 0 || nIndex >= (int)m_Items.GetSize() )
  4105.         return NULL;
  4106.  
  4107.     return m_Items[nIndex];
  4108. }
  4109.  
  4110.  
  4111. //--------------------------------------------------------------------------------------
  4112. // For single-selection listbox, returns the index of the selected item.
  4113. // For multi-selection, returns the first selected item after the nPreviousSelected position.
  4114. // To search for the first selected item, the app passes -1 for nPreviousSelected.  For
  4115. // subsequent searches, the app passes the returned index back to GetSelectedIndex as.
  4116. // nPreviousSelected.
  4117. // Returns -1 on error or if no item is selected.
  4118. int CDXUTListBox::GetSelectedIndex( int nPreviousSelected )
  4119. {
  4120.     if( nPreviousSelected < -1 )
  4121.         return -1;
  4122.  
  4123.     if( m_dwStyle & MULTISELECTION )
  4124.     {
  4125.         // Multiple selection enabled. Search for the next item with the selected flag.
  4126.         for( int i = nPreviousSelected + 1; i < (int)m_Items.GetSize(); ++i )
  4127.         {
  4128.             DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4129.  
  4130.             if( pItem->bSelected )
  4131.                 return i;
  4132.         }
  4133.  
  4134.         return -1;
  4135.     }
  4136.     else
  4137.     {
  4138.         // Single selection
  4139.         return m_nSelected;
  4140.     }
  4141. }
  4142.  
  4143.  
  4144. //--------------------------------------------------------------------------------------
  4145. void CDXUTListBox::SelectItem( int nNewIndex )
  4146. {
  4147.     // If no item exists, do nothing.
  4148.     if( m_Items.GetSize() == 0 )
  4149.         return;
  4150.  
  4151.     int nOldSelected = m_nSelected;
  4152.  
  4153.     // Adjust m_nSelected
  4154.     m_nSelected = nNewIndex;
  4155.  
  4156.     // Perform capping
  4157.     if( m_nSelected < 0 )
  4158.         m_nSelected = 0;
  4159.     if( m_nSelected >= (int)m_Items.GetSize() )
  4160.         m_nSelected = m_Items.GetSize() - 1;
  4161.  
  4162.     if( nOldSelected != m_nSelected )
  4163.     {
  4164.         if( m_dwStyle & MULTISELECTION )
  4165.         {
  4166.             m_Items[m_nSelected]->bSelected = true;
  4167.         }
  4168.  
  4169.         // Update selection start
  4170.         m_nSelStart = m_nSelected;
  4171.  
  4172.         // Adjust scroll bar
  4173.         m_ScrollBar.ShowItem( m_nSelected );
  4174.     }
  4175.  
  4176.     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4177. }
  4178.  
  4179.  
  4180. //--------------------------------------------------------------------------------------
  4181. bool CDXUTListBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  4182. {
  4183.     if( !m_bEnabled || !m_bVisible )
  4184.         return false;
  4185.  
  4186.     // Let the scroll bar have a chance to handle it first
  4187.     if( m_ScrollBar.HandleKeyboard( uMsg, wParam, lParam ) )
  4188.         return true;
  4189.  
  4190.     switch( uMsg )
  4191.     {
  4192.         case WM_KEYDOWN:
  4193.             switch( wParam )
  4194.             {
  4195.                 case VK_UP:
  4196.                 case VK_DOWN:
  4197.                 case VK_NEXT:
  4198.                 case VK_PRIOR:
  4199.                 case VK_HOME:
  4200.                 case VK_END:
  4201.  
  4202.                     // If no item exists, do nothing.
  4203.                     if( m_Items.GetSize() == 0 )
  4204.                         return true;
  4205.  
  4206.                     int nOldSelected = m_nSelected;
  4207.  
  4208.                     // Adjust m_nSelected
  4209.                     switch( wParam )
  4210.                     {
  4211.                         case VK_UP: --m_nSelected; break;
  4212.                         case VK_DOWN: ++m_nSelected; break;
  4213.                         case VK_NEXT: m_nSelected += m_ScrollBar.GetPageSize() - 1; break;
  4214.                         case VK_PRIOR: m_nSelected -= m_ScrollBar.GetPageSize() - 1; break;
  4215.                         case VK_HOME: m_nSelected = 0; break;
  4216.                         case VK_END: m_nSelected = m_Items.GetSize() - 1; break;
  4217.                     }
  4218.  
  4219.                     // Perform capping
  4220.                     if( m_nSelected < 0 )
  4221.                         m_nSelected = 0;
  4222.                     if( m_nSelected >= (int)m_Items.GetSize() )
  4223.                         m_nSelected = m_Items.GetSize() - 1;
  4224.  
  4225.                     if( nOldSelected != m_nSelected )
  4226.                     {
  4227.                         if( m_dwStyle & MULTISELECTION )
  4228.                         {
  4229.                             // Multiple selection
  4230.  
  4231.                             // Clear all selection
  4232.                             for( int i = 0; i < (int)m_Items.GetSize(); ++i )
  4233.                             {
  4234.                                 DXUTListBoxItem *pItem = m_Items[i];
  4235.                                 pItem->bSelected = false;
  4236.                             }
  4237.  
  4238.                             if( GetKeyState( VK_SHIFT ) < 0 )
  4239.                             {
  4240.                                 // Select all items from m_nSelStart to
  4241.                                 // m_nSelected
  4242.                                 int nEnd = max( m_nSelStart, m_nSelected );
  4243.  
  4244.                                 for( int n = min( m_nSelStart, m_nSelected ); n <= nEnd; ++n )
  4245.                                     m_Items[n]->bSelected = true;
  4246.                             }
  4247.                             else
  4248.                             {
  4249.                                 m_Items[m_nSelected]->bSelected = true;
  4250.  
  4251.                                 // Update selection start
  4252.                                 m_nSelStart = m_nSelected;
  4253.                             }
  4254.                         } else
  4255.                             m_nSelStart = m_nSelected;
  4256.  
  4257.                         // Adjust scroll bar
  4258.  
  4259.                         m_ScrollBar.ShowItem( m_nSelected );
  4260.  
  4261.                         // Send notification
  4262.  
  4263.                         m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4264.                     }
  4265.                     return true;
  4266.             }
  4267.             break;
  4268.     }
  4269.  
  4270.     return false;
  4271. }
  4272.  
  4273.  
  4274. //--------------------------------------------------------------------------------------
  4275. bool CDXUTListBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  4276. {
  4277.     if( !m_bEnabled || !m_bVisible )
  4278.         return false;
  4279.  
  4280.     // First acquire focus
  4281.     if( WM_LBUTTONDOWN == uMsg )
  4282.         if( !m_bHasFocus )
  4283.             m_pDialog->RequestFocus( this );
  4284.  
  4285.     // Let the scroll bar handle it first.
  4286.     if( m_ScrollBar.HandleMouse( uMsg, pt, wParam, lParam ) )
  4287.         return true;
  4288.  
  4289.     switch( uMsg )
  4290.     {
  4291.         case WM_LBUTTONDOWN:
  4292.         case WM_LBUTTONDBLCLK:
  4293.             // Check for clicks in the text area
  4294.             if( m_Items.GetSize() > 0 && PtInRect( &m_rcSelection, pt ) )
  4295.             {
  4296.                 // Compute the index of the clicked item
  4297.  
  4298.                 int nClicked;
  4299.                 if( m_nTextHeight )
  4300.                     nClicked = m_ScrollBar.GetTrackPos() + ( pt.y - m_rcText.top ) / m_nTextHeight;
  4301.                 else
  4302.                     nClicked = -1;
  4303.  
  4304.                 // Only proceed if the click falls on top of an item.
  4305.  
  4306.                 if( nClicked >= m_ScrollBar.GetTrackPos() &&
  4307.                     nClicked < (int)m_Items.GetSize() &&
  4308.                     nClicked < m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() )
  4309.                 {
  4310.                     SetCapture( DXUTGetHWND() );
  4311.                     m_bDrag = true;
  4312.  
  4313.                     // If this is a double click, fire off an event and exit
  4314.                     // since the first click would have taken care of the selection
  4315.                     // updating.
  4316.                     if( uMsg == WM_LBUTTONDBLCLK )
  4317.                     {
  4318.                         m_pDialog->SendEvent( EVENT_LISTBOX_ITEM_DBLCLK, true, this );
  4319.                         return true;
  4320.                     }
  4321.  
  4322.                     m_nSelected = nClicked;
  4323.                     if( !( wParam & MK_SHIFT ) )
  4324.                         m_nSelStart = m_nSelected;
  4325.  
  4326.                     // If this is a multi-selection listbox, update per-item
  4327.                     // selection data.
  4328.  
  4329.                     if( m_dwStyle & MULTISELECTION )
  4330.                     {
  4331.                         // Determine behavior based on the state of Shift and Ctrl
  4332.  
  4333.                         DXUTListBoxItem *pSelItem = m_Items.GetAt( m_nSelected );
  4334.                         if( ( wParam & (MK_SHIFT|MK_CONTROL) ) == MK_CONTROL )
  4335.                         {
  4336.                             // Control click. Reverse the selection of this item.
  4337.  
  4338.                             pSelItem->bSelected = !pSelItem->bSelected;
  4339.                         } else
  4340.                         if( ( wParam & (MK_SHIFT|MK_CONTROL) ) == MK_SHIFT )
  4341.                         {
  4342.                             // Shift click. Set the selection for all items
  4343.                             // from last selected item to the current item.
  4344.                             // Clear everything else.
  4345.  
  4346.                             int nBegin = min( m_nSelStart, m_nSelected );
  4347.                             int nEnd = max( m_nSelStart, m_nSelected );
  4348.  
  4349.                             for( int i = 0; i < nBegin; ++i )
  4350.                             {
  4351.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4352.                                 pItem->bSelected = false;
  4353.                             }
  4354.  
  4355.                             for( int i = nEnd + 1; i < (int)m_Items.GetSize(); ++i )
  4356.                             {
  4357.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4358.                                 pItem->bSelected = false;
  4359.                             }
  4360.  
  4361.                             for( int i = nBegin; i <= nEnd; ++i )
  4362.                             {
  4363.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4364.                                 pItem->bSelected = true;
  4365.                             }
  4366.                         } else
  4367.                         if( ( wParam & (MK_SHIFT|MK_CONTROL) ) == ( MK_SHIFT|MK_CONTROL ) )
  4368.                         {
  4369.                             // Control-Shift-click.
  4370.  
  4371.                             // The behavior is:
  4372.                             //   Set all items from m_nSelStart to m_nSelected to
  4373.                             //     the same state as m_nSelStart, not including m_nSelected.
  4374.                             //   Set m_nSelected to selected.
  4375.  
  4376.                             int nBegin = min( m_nSelStart, m_nSelected );
  4377.                             int nEnd = max( m_nSelStart, m_nSelected );
  4378.  
  4379.                             // The two ends do not need to be set here.
  4380.  
  4381.                             bool bLastSelected = m_Items.GetAt( m_nSelStart )->bSelected;
  4382.                             for( int i = nBegin + 1; i < nEnd; ++i )
  4383.                             {
  4384.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4385.                                 pItem->bSelected = bLastSelected;
  4386.                             }
  4387.  
  4388.                             pSelItem->bSelected = true;
  4389.  
  4390.                             // Restore m_nSelected to the previous value
  4391.                             // This matches the Windows behavior
  4392.  
  4393.                             m_nSelected = m_nSelStart;
  4394.                         } else
  4395.                         {
  4396.                             // Simple click.  Clear all items and select the clicked
  4397.                             // item.
  4398.  
  4399.  
  4400.                             for( int i = 0; i < (int)m_Items.GetSize(); ++i )
  4401.                             {
  4402.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4403.                                 pItem->bSelected = false;
  4404.                             }
  4405.  
  4406.                             pSelItem->bSelected = true;
  4407.                         }
  4408.                     }  // End of multi-selection case
  4409.  
  4410.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4411.                 }
  4412.  
  4413.                 return true;
  4414.             }
  4415.             break;
  4416.  
  4417.         case WM_LBUTTONUP:
  4418.         {
  4419.             ReleaseCapture();
  4420.             m_bDrag = false;
  4421.  
  4422.             if( m_nSelected != -1 )
  4423.             {
  4424.                 // Set all items between m_nSelStart and m_nSelected to
  4425.                 // the same state as m_nSelStart
  4426.                 int nEnd = max( m_nSelStart, m_nSelected );
  4427.  
  4428.                 for( int n = min( m_nSelStart, m_nSelected ) + 1; n < nEnd; ++n )
  4429.                     m_Items[n]->bSelected = m_Items[m_nSelStart]->bSelected;
  4430.                 m_Items[m_nSelected]->bSelected = m_Items[m_nSelStart]->bSelected;
  4431.  
  4432.                 // If m_nSelStart and m_nSelected are not the same,
  4433.                 // the user has dragged the mouse to make a selection.
  4434.                 // Notify the application of this.
  4435.                 if( m_nSelStart != m_nSelected )
  4436.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4437.             }
  4438.             return false;
  4439.         }
  4440.  
  4441.         case WM_MOUSEMOVE:
  4442.             if( m_bDrag )
  4443.             {
  4444.                 // Compute the index of the item below cursor
  4445.  
  4446.                 int nItem;
  4447.                 if( m_nTextHeight )
  4448.                     nItem = m_ScrollBar.GetTrackPos() + ( pt.y - m_rcText.top ) / m_nTextHeight;
  4449.                 else
  4450.                     nItem = -1;
  4451.  
  4452.                 // Only proceed if the cursor is on top of an item.
  4453.  
  4454.                 if( nItem >= (int)m_ScrollBar.GetTrackPos() &&
  4455.                     nItem < (int)m_Items.GetSize() &&
  4456.                     nItem < m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() )
  4457.                 {
  4458.                     m_nSelected = nItem;
  4459.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4460.                 } else
  4461.                 if( nItem < (int)m_ScrollBar.GetTrackPos() )
  4462.                 {
  4463.                     // User drags the mouse above window top
  4464.                     m_ScrollBar.Scroll( -1 );
  4465.                     m_nSelected = m_ScrollBar.GetTrackPos();
  4466.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4467.                 } else
  4468.                 if( nItem >= m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() )
  4469.                 {
  4470.                     // User drags the mouse below window bottom
  4471.                     m_ScrollBar.Scroll( 1 );
  4472.                     m_nSelected = min( (int)m_Items.GetSize(), m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() ) - 1;
  4473.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  4474.                 }
  4475.             }
  4476.             break;
  4477.  
  4478.         case WM_MOUSEWHEEL:
  4479.         {
  4480.             UINT uLines;
  4481.             SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &uLines, 0 );
  4482.             int nScrollAmount = int((short)HIWORD(wParam)) / WHEEL_DELTA * uLines;
  4483.             m_ScrollBar.Scroll( -nScrollAmount );
  4484.             return true;
  4485.         }
  4486.     }
  4487.  
  4488.     return false;
  4489. }
  4490.  
  4491.  
  4492. //--------------------------------------------------------------------------------------
  4493. void CDXUTListBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  4494. {
  4495.     if( m_bVisible == false )
  4496.         return;
  4497.  
  4498.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  4499.     pElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  4500.     pElement->FontColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  4501.  
  4502.     CDXUTElement* pSelElement = m_Elements.GetAt( 1 );
  4503.     pSelElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  4504.     pSelElement->FontColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  4505.  
  4506.     m_pDialog->DrawSprite( pElement, &m_rcBoundingBox );
  4507.  
  4508.     // Render the text
  4509.     if( m_Items.GetSize() > 0 )
  4510.     {
  4511.         // Find out the height of a single line of text
  4512.         RECT rc = m_rcText;
  4513.         RECT rcSel = m_rcSelection;
  4514.         rc.bottom = rc.top + DXUTGetGlobalDialogResourceManager()->GetFontNode( pElement->iFont )->nHeight;
  4515.  
  4516.         // Update the line height formation
  4517.         m_nTextHeight = rc.bottom - rc.top;
  4518.  
  4519.         static bool bSBInit;
  4520.         if( !bSBInit )
  4521.         {
  4522.             // Update the page size of the scroll bar
  4523.             if( m_nTextHeight )
  4524.                 m_ScrollBar.SetPageSize( RectHeight( m_rcText ) / m_nTextHeight );
  4525.             else
  4526.                 m_ScrollBar.SetPageSize( RectHeight( m_rcText ) );
  4527.             bSBInit = true;
  4528.         }
  4529.  
  4530.         rc.right = m_rcText.right;
  4531.         for( int i = m_ScrollBar.GetTrackPos(); i < (int)m_Items.GetSize(); ++i )
  4532.         {
  4533.             if( rc.bottom > m_rcText.bottom )
  4534.                 break;
  4535.  
  4536.             DXUTListBoxItem *pItem = m_Items.GetAt( i );
  4537.  
  4538.             // Determine if we need to render this item with the
  4539.             // selected element.
  4540.             bool bSelectedStyle = false;
  4541.  
  4542.             if( !( m_dwStyle & MULTISELECTION ) && i == m_nSelected )
  4543.                 bSelectedStyle = true;
  4544.             else
  4545.             if( m_dwStyle & MULTISELECTION )
  4546.             {
  4547.                 if( m_bDrag &&
  4548.                     ( ( i >= m_nSelected && i < m_nSelStart ) ||
  4549.                       ( i <= m_nSelected && i > m_nSelStart ) ) )
  4550.                     bSelectedStyle = m_Items[m_nSelStart]->bSelected;
  4551.                 else
  4552.                 if( pItem->bSelected )
  4553.                     bSelectedStyle = true;
  4554.             }
  4555.  
  4556.             if( bSelectedStyle )
  4557.             {
  4558.                 rcSel.top = rc.top; rcSel.bottom = rc.bottom;
  4559.                 m_pDialog->DrawSprite( pSelElement, &rcSel );
  4560.                 m_pDialog->DrawText( pItem->strText, pSelElement, &rc );
  4561.             }
  4562.             else
  4563.                 m_pDialog->DrawText( pItem->strText, pElement, &rc );
  4564.  
  4565.             OffsetRect( &rc, 0, m_nTextHeight );
  4566.         }
  4567.     }
  4568.  
  4569.     // Render the scroll bar
  4570.  
  4571.     m_ScrollBar.Render( pd3dDevice, fElapsedTime );
  4572. }
  4573.  
  4574.  
  4575. // Helper class that help us automatically initialize and uninitialize external API.
  4576. // Important: C++ does not guaranteed the order global and static objects are
  4577. //            initialized in.  Therefore, do not use edit controls inside
  4578. //            a constructor.
  4579. class CExternalApiInitializer
  4580. {
  4581. public:
  4582.     CExternalApiInitializer()
  4583.     {
  4584.         CDXUTEditBox::CUniBuffer::InitializeUniscribe();
  4585.         CDXUTIMEEditBox::InitializeImm();
  4586.     }
  4587.     ~CExternalApiInitializer()
  4588.     {
  4589.         CDXUTEditBox::CUniBuffer::UninitializeUniscribe();
  4590.         CDXUTIMEEditBox::UninitializeImm();
  4591.     }
  4592. } EXTERNAL_API_INITIALIZER;
  4593.  
  4594. // Static member initialization
  4595. HINSTANCE CDXUTEditBox::CUniBuffer::s_hDll = NULL;
  4596. HRESULT (WINAPI *CDXUTEditBox::CUniBuffer::_ScriptApplyDigitSubstitution)( const SCRIPT_DIGITSUBSTITUTE*, SCRIPT_CONTROL*, SCRIPT_STATE* )
  4597.     = Dummy_ScriptApplyDigitSubstitution;
  4598. HRESULT (WINAPI *CDXUTEditBox::CUniBuffer::_ScriptStringAnalyse)( HDC, const void *, int, int, int, DWORD, int, SCRIPT_CONTROL*, SCRIPT_STATE*,
  4599.                                                     const int*, SCRIPT_TABDEF*, const BYTE*, SCRIPT_STRING_ANALYSIS* )
  4600.     = Dummy_ScriptStringAnalyse;
  4601. HRESULT (WINAPI *CDXUTEditBox::CUniBuffer::_ScriptStringCPtoX)( SCRIPT_STRING_ANALYSIS, int, BOOL, int* )
  4602.     = Dummy_ScriptStringCPtoX;
  4603. HRESULT (WINAPI *CDXUTEditBox::CUniBuffer::_ScriptStringXtoCP)( SCRIPT_STRING_ANALYSIS, int, int*, int* )
  4604.     = Dummy_ScriptStringXtoCP;
  4605. HRESULT (WINAPI *CDXUTEditBox::CUniBuffer::_ScriptStringFree)( SCRIPT_STRING_ANALYSIS* )
  4606.     = Dummy_ScriptStringFree;
  4607. const SCRIPT_LOGATTR* (WINAPI *CDXUTEditBox::CUniBuffer::_ScriptString_pLogAttr)( SCRIPT_STRING_ANALYSIS )
  4608.     = Dummy_ScriptString_pLogAttr;
  4609. const int* (WINAPI *CDXUTEditBox::CUniBuffer::_ScriptString_pcOutChars)( SCRIPT_STRING_ANALYSIS )
  4610.     = Dummy_ScriptString_pcOutChars;
  4611. bool CDXUTEditBox::s_bHideCaret;   // If true, we don't render the caret.
  4612.  
  4613.  
  4614.  
  4615. //--------------------------------------------------------------------------------------
  4616. // CDXUTEditBox class
  4617. //--------------------------------------------------------------------------------------
  4618.  
  4619. // When scrolling, EDITBOX_SCROLLEXTENT is reciprocal of the amount to scroll.
  4620. // If EDITBOX_SCROLLEXTENT = 4, then we scroll 1/4 of the control each time.
  4621. #define EDITBOX_SCROLLEXTENT 4
  4622.  
  4623. //--------------------------------------------------------------------------------------
  4624. CDXUTEditBox::CDXUTEditBox( CDXUTDialog *pDialog )
  4625. {
  4626.     m_Type = DXUT_CONTROL_EDITBOX;
  4627.     m_pDialog = pDialog;
  4628.  
  4629.     m_nBorder = 5;  // Default border width
  4630.     m_nSpacing = 4;  // Default spacing
  4631.  
  4632.     m_bCaretOn = true;
  4633.     m_dfBlink = GetCaretBlinkTime() * 0.001f;
  4634.     m_dfLastBlink = DXUTGetGlobalTimer()->GetAbsoluteTime();
  4635.     s_bHideCaret = false;
  4636.     m_nFirstVisible = 0;
  4637.     m_TextColor = D3DCOLOR_ARGB( 255, 16, 16, 16 );
  4638.     m_SelTextColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
  4639.     m_SelBkColor = D3DCOLOR_ARGB( 255, 40, 50, 92 );
  4640.     m_CaretColor = D3DCOLOR_ARGB( 255, 0, 0, 0 );
  4641.     m_nCaret = m_nSelStart = 0;
  4642.     m_bInsertMode = true;
  4643.  
  4644.     m_bMouseDrag = false;
  4645. }
  4646.  
  4647.  
  4648. //--------------------------------------------------------------------------------------
  4649. CDXUTEditBox::~CDXUTEditBox()
  4650. {
  4651. }
  4652.  
  4653.  
  4654. //--------------------------------------------------------------------------------------
  4655. // PlaceCaret: Set the caret to a character position, and adjust the scrolling if
  4656. //             necessary.
  4657. //--------------------------------------------------------------------------------------
  4658. void CDXUTEditBox::PlaceCaret( int nCP )
  4659. {
  4660.     assert( nCP >= 0 && nCP <= m_Buffer.GetTextSize() );
  4661.     m_nCaret = nCP;
  4662.  
  4663.     // Obtain the X offset of the character.
  4664.     int nX1st, nX, nX2, nXOffset;
  4665.     m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st );  // 1st visible char
  4666.     nXOffset = nX1st;
  4667.     m_Buffer.CPtoX( nCP, FALSE, &nX );  // LEAD
  4668.     // If nCP is the NULL terminator, get the leading edge instead of trailing.
  4669.     if( nCP == m_Buffer.GetTextSize() )
  4670.         nX2 = nX;
  4671.     else
  4672.         m_Buffer.CPtoX( nCP, TRUE, &nX2 );  // TRAIL
  4673.  
  4674.     // If the left edge of the char is smaller than the left edge of the 1st visible char,
  4675.     // we need to scroll left until this char is visible.
  4676.     if( nX < nX1st )
  4677.     {
  4678.         // Simply make the first visible character the char at the new caret position.
  4679.         m_nFirstVisible = nCP;
  4680.     }
  4681.     else
  4682.     // If the right of the character is bigger than the offset of the control's
  4683.     // right edge, we need to scroll right to this character.
  4684.     if( nX2 > nX1st + RectWidth( m_rcText ) )
  4685.     {
  4686.         // Compute the X of the new left-most pixel
  4687.         int nXNewLeft = nX2 - RectWidth( m_rcText );
  4688.  
  4689.         // Compute the char position of this character
  4690.         int nCPNew1st, nNewTrail;
  4691.         m_Buffer.XtoCP( nXNewLeft, &nCPNew1st, &nNewTrail );
  4692.  
  4693.         // If this coordinate is not on a character border,
  4694.         // start from the next character so that the caret
  4695.         // position does not fall outside the text rectangle.
  4696.         int nXNew1st;
  4697.         m_Buffer.CPtoX( nCPNew1st, FALSE, &nXNew1st );
  4698.         if( nXNew1st < nXNewLeft )
  4699.             ++nCPNew1st;
  4700.  
  4701.         m_nFirstVisible = nCPNew1st;
  4702.     }
  4703. }
  4704.  
  4705.  
  4706. //--------------------------------------------------------------------------------------
  4707. void CDXUTEditBox::ClearText()
  4708. {
  4709.     m_Buffer.Clear();
  4710.     PlaceCaret( 0 );
  4711.     m_nSelStart = 0;
  4712. }
  4713.  
  4714.  
  4715. //--------------------------------------------------------------------------------------
  4716. void CDXUTEditBox::SetText( LPCWSTR wszText, bool bSelected )
  4717. {
  4718.     assert( wszText != NULL );
  4719.  
  4720.     m_Buffer.SetText( wszText );
  4721.     // Move the caret to the end of the text
  4722.     PlaceCaret( m_Buffer.GetTextSize() );
  4723.     m_nSelStart = bSelected ? 0 : m_nCaret;
  4724. }
  4725.  
  4726.  
  4727. //--------------------------------------------------------------------------------------
  4728. HRESULT CDXUTEditBox::GetTextCopy( LPWSTR strDest, UINT bufferCount )
  4729. {
  4730.     assert( strDest );
  4731.  
  4732.     wcsncpy( strDest, m_Buffer.GetBuffer(), bufferCount );
  4733.     *(strDest + bufferCount - 1) = L'\0';
  4734.  
  4735.     return S_OK;
  4736. }
  4737.  
  4738.  
  4739. //--------------------------------------------------------------------------------------
  4740. void CDXUTEditBox::DeleteSelectionText()
  4741. {
  4742.     int nFirst = min( m_nCaret, m_nSelStart );
  4743.     int nLast = max( m_nCaret, m_nSelStart );
  4744.     // Update caret and selection
  4745.     PlaceCaret( nFirst );
  4746.     m_nSelStart = m_nCaret;
  4747.     // Remove the characters
  4748.     for( int i = nFirst; i < nLast; ++i )
  4749.         m_Buffer.RemoveChar( nFirst );
  4750. }
  4751.  
  4752.  
  4753. //--------------------------------------------------------------------------------------
  4754. void CDXUTEditBox::UpdateRects()
  4755. {
  4756.     CDXUTControl::UpdateRects();
  4757.  
  4758.     // Update the text rectangle
  4759.     m_rcText = m_rcBoundingBox;
  4760.     // First inflate by m_nBorder to compute render rects
  4761.     InflateRect( &m_rcText, -m_nBorder, -m_nBorder );
  4762.  
  4763.     // Update the render rectangles
  4764.     m_rcRender[0] = m_rcText;
  4765.     SetRect( &m_rcRender[1], m_rcBoundingBox.left, m_rcBoundingBox.top, m_rcText.left, m_rcText.top );
  4766.     SetRect( &m_rcRender[2], m_rcText.left, m_rcBoundingBox.top, m_rcText.right, m_rcText.top );
  4767.     SetRect( &m_rcRender[3], m_rcText.right, m_rcBoundingBox.top, m_rcBoundingBox.right, m_rcText.top );
  4768.     SetRect( &m_rcRender[4], m_rcBoundingBox.left, m_rcText.top, m_rcText.left, m_rcText.bottom );
  4769.     SetRect( &m_rcRender[5], m_rcText.right, m_rcText.top, m_rcBoundingBox.right, m_rcText.bottom );
  4770.     SetRect( &m_rcRender[6], m_rcBoundingBox.left, m_rcText.bottom, m_rcText.left, m_rcBoundingBox.bottom );
  4771.     SetRect( &m_rcRender[7], m_rcText.left, m_rcText.bottom, m_rcText.right, m_rcBoundingBox.bottom );
  4772.     SetRect( &m_rcRender[8], m_rcText.right, m_rcText.bottom, m_rcBoundingBox.right, m_rcBoundingBox.bottom );
  4773.  
  4774.     // Inflate further by m_nSpacing
  4775.     InflateRect( &m_rcText, -m_nSpacing, -m_nSpacing );
  4776. }
  4777.  
  4778.  
  4779. void CDXUTEditBox::CopyToClipboard()
  4780. {
  4781.     // Copy the selection text to the clipboard
  4782.     if( m_nCaret != m_nSelStart && OpenClipboard( NULL ) )
  4783.     {
  4784.         EmptyClipboard();
  4785.  
  4786.         HGLOBAL hBlock = GlobalAlloc( GMEM_MOVEABLE, sizeof(WCHAR) * ( m_Buffer.GetTextSize() + 1 ) );
  4787.         if( hBlock )
  4788.         {
  4789.             WCHAR *pwszText = (WCHAR*)GlobalLock( hBlock );
  4790.             if( pwszText )
  4791.             {
  4792.                 int nFirst = min( m_nCaret, m_nSelStart );
  4793.                 int nLast = max( m_nCaret, m_nSelStart );
  4794.                 if( nLast - nFirst > 0 )
  4795.                     CopyMemory( pwszText, m_Buffer.GetBuffer() + nFirst, (nLast - nFirst) * sizeof(WCHAR) );
  4796.                 pwszText[nLast - nFirst] = L'\0';  // Terminate it
  4797.                 GlobalUnlock( hBlock );
  4798.             }
  4799.             SetClipboardData( CF_UNICODETEXT, hBlock );
  4800.         }
  4801.         CloseClipboard();
  4802.         // We must not free the object until CloseClipboard is called.
  4803.         if( hBlock )
  4804.             GlobalFree( hBlock );
  4805.     }
  4806. }
  4807.  
  4808.  
  4809. void CDXUTEditBox::PasteFromClipboard()
  4810. {
  4811.     DeleteSelectionText();
  4812.  
  4813.     if( OpenClipboard( NULL ) )
  4814.     {
  4815.         HANDLE handle = GetClipboardData( CF_UNICODETEXT );
  4816.         if( handle )
  4817.         {
  4818.             // Convert the ANSI string to Unicode, then
  4819.             // insert to our buffer.
  4820.             WCHAR *pwszText = (WCHAR*)GlobalLock( handle );
  4821.             if( pwszText )
  4822.             {
  4823.                 // Copy all characters up to null.
  4824.                 if( m_Buffer.InsertString( m_nCaret, pwszText ) )
  4825.                     PlaceCaret( m_nCaret + lstrlenW( pwszText ) );
  4826.                 m_nSelStart = m_nCaret;
  4827.                 GlobalUnlock( handle );
  4828.             }
  4829.         }
  4830.         CloseClipboard();
  4831.     }
  4832. }
  4833.  
  4834.  
  4835. //--------------------------------------------------------------------------------------
  4836. bool CDXUTEditBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  4837. {
  4838.     if( !m_bEnabled || !m_bVisible )
  4839.         return false;
  4840.  
  4841.     bool bHandled = false;
  4842.  
  4843.     switch( uMsg )
  4844.     {
  4845.         case WM_KEYDOWN:
  4846.         {
  4847.             switch( wParam )
  4848.             {
  4849.                 case VK_HOME:
  4850.                     PlaceCaret( 0 );
  4851.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  4852.                         // Shift is not down. Update selection
  4853.                         // start along with the caret.
  4854.                         m_nSelStart = m_nCaret;
  4855.                     ResetCaretBlink();
  4856.                     bHandled = true;
  4857.                     break;
  4858.  
  4859.                 case VK_END:
  4860.                     PlaceCaret( m_Buffer.GetTextSize() );
  4861.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  4862.                         // Shift is not down. Update selection
  4863.                         // start along with the caret.
  4864.                         m_nSelStart = m_nCaret;
  4865.                     ResetCaretBlink();
  4866.                     bHandled = true;
  4867.                     break;
  4868.  
  4869.                 case VK_INSERT:
  4870.                     if( GetKeyState( VK_CONTROL ) < 0 )
  4871.                     {
  4872.                         // Control Insert. Copy to clipboard
  4873.                         CopyToClipboard();
  4874.                     } else
  4875.                     if( GetKeyState( VK_SHIFT ) < 0 )
  4876.                     {
  4877.                         // Shift Insert. Paste from clipboard
  4878.                         PasteFromClipboard();
  4879.                     } else
  4880.                     {
  4881.                         // Toggle caret insert mode
  4882.                         m_bInsertMode = !m_bInsertMode;
  4883.                     }
  4884.                     break;
  4885.  
  4886.                 case VK_DELETE:
  4887.                     // Check if there is a text selection.
  4888.                     if( m_nCaret != m_nSelStart )
  4889.                     {
  4890.                         DeleteSelectionText();
  4891.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  4892.                     }
  4893.                     else
  4894.                     {
  4895.                         // Deleting one character
  4896.                         if( m_Buffer.RemoveChar( m_nCaret ) )
  4897.                             m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  4898.                     }
  4899.                     ResetCaretBlink();
  4900.                     bHandled = true;
  4901.                     break;
  4902.  
  4903.                 case VK_LEFT:
  4904.                     if( GetKeyState( VK_CONTROL ) < 0 )
  4905.                     {
  4906.                         // Control is down. Move the caret to a new item
  4907.                         // instead of a character.
  4908.                         m_Buffer.GetPriorItemPos( m_nCaret, &m_nCaret );
  4909.                         PlaceCaret( m_nCaret );
  4910.                     }
  4911.                     else
  4912.                     if( m_nCaret > 0 )
  4913.                         PlaceCaret( m_nCaret - 1 );
  4914.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  4915.                         // Shift is not down. Update selection
  4916.                         // start along with the caret.
  4917.                         m_nSelStart = m_nCaret;
  4918.                     ResetCaretBlink();
  4919.                     bHandled = true;
  4920.                     break;
  4921.  
  4922.                 case VK_RIGHT:
  4923.                     if( GetKeyState( VK_CONTROL ) < 0 )
  4924.                     {
  4925.                         // Control is down. Move the caret to a new item
  4926.                         // instead of a character.
  4927.                         m_Buffer.GetNextItemPos( m_nCaret, &m_nCaret );
  4928.                         PlaceCaret( m_nCaret );
  4929.                     }
  4930.                     else
  4931.                     if( m_nCaret < m_Buffer.GetTextSize() )
  4932.                         PlaceCaret( m_nCaret + 1 );
  4933.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  4934.                         // Shift is not down. Update selection
  4935.                         // start along with the caret.
  4936.                         m_nSelStart = m_nCaret;
  4937.                     ResetCaretBlink();
  4938.                     bHandled = true;
  4939.                     break;
  4940.  
  4941.                 case VK_UP:
  4942.                 case VK_DOWN:
  4943.                     // Trap up and down arrows so that the dialog
  4944.                     // does not switch focus to another control.
  4945.                     bHandled = true;
  4946.                     break;
  4947.  
  4948.                 default:
  4949.                     bHandled = wParam != VK_ESCAPE;  // Let the application handle Esc.
  4950.             }
  4951.         }
  4952.     }
  4953.     return bHandled;
  4954. }
  4955.  
  4956.  
  4957. //--------------------------------------------------------------------------------------
  4958. bool CDXUTEditBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  4959. {
  4960.     if( !m_bEnabled || !m_bVisible )
  4961.         return false;
  4962.  
  4963.     switch( uMsg )
  4964.     {
  4965.         case WM_LBUTTONDOWN:
  4966.         case WM_LBUTTONDBLCLK:
  4967.         {
  4968.             if( !m_bHasFocus )
  4969.                 m_pDialog->RequestFocus( this );
  4970.  
  4971.             if( !ContainsPoint( pt ) )
  4972.                 return false;
  4973.  
  4974.             m_bMouseDrag = true;
  4975.             SetCapture( DXUTGetHWND() );
  4976.             // Determine the character corresponding to the coordinates.
  4977.             int nCP, nTrail, nX1st;
  4978.             m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st );  // X offset of the 1st visible char
  4979.             if( SUCCEEDED( m_Buffer.XtoCP( pt.x - m_rcText.left + nX1st, &nCP, &nTrail ) ) )
  4980.             {
  4981.                 // Cap at the NULL character.
  4982.                 if( nTrail && nCP < m_Buffer.GetTextSize() )
  4983.                     PlaceCaret( nCP + 1 );
  4984.                 else
  4985.                     PlaceCaret( nCP );
  4986.                 m_nSelStart = m_nCaret;
  4987.                 ResetCaretBlink();
  4988.             }
  4989.             return true;
  4990.         }
  4991.  
  4992.         case WM_LBUTTONUP:
  4993.             ReleaseCapture();
  4994.             m_bMouseDrag = false;
  4995.             break;
  4996.  
  4997.         case WM_MOUSEMOVE:
  4998.             if( m_bMouseDrag )
  4999.             {
  5000.                 // Determine the character corresponding to the coordinates.
  5001.                 int nCP, nTrail, nX1st;
  5002.                 m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st );  // X offset of the 1st visible char
  5003.                 if( SUCCEEDED( m_Buffer.XtoCP( pt.x - m_rcText.left + nX1st, &nCP, &nTrail ) ) )
  5004.                 {
  5005.                     // Cap at the NULL character.
  5006.                     if( nTrail && nCP < m_Buffer.GetTextSize() )
  5007.                         PlaceCaret( nCP + 1 );
  5008.                     else
  5009.                         PlaceCaret( nCP );
  5010.                 }
  5011.             }
  5012.             break;
  5013.     }
  5014.  
  5015.     return false;
  5016. }
  5017.  
  5018.  
  5019. //--------------------------------------------------------------------------------------
  5020. void CDXUTEditBox::OnFocusIn()
  5021. {
  5022.     CDXUTControl::OnFocusIn();
  5023.  
  5024.     ResetCaretBlink();
  5025. }
  5026.  
  5027.  
  5028. //--------------------------------------------------------------------------------------
  5029. bool CDXUTEditBox::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  5030. {
  5031.     if( !m_bEnabled || !m_bVisible )
  5032.         return false;
  5033.  
  5034.     switch( uMsg )
  5035.     {
  5036.         case WM_CHAR:
  5037.         {
  5038.             switch( (WCHAR)wParam )
  5039.             {
  5040.                 // Backspace
  5041.                 case VK_BACK:
  5042.                 {
  5043.                     // If there's a selection, treat this
  5044.                     // like a delete key.
  5045.                     if( m_nCaret != m_nSelStart )
  5046.                     {
  5047.                         DeleteSelectionText();
  5048.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  5049.                     }
  5050.                     else
  5051.                     if( m_nCaret > 0 )
  5052.                     {
  5053.                         // Move the caret, then delete the char.
  5054.                         PlaceCaret( m_nCaret - 1 );
  5055.                         m_nSelStart = m_nCaret;
  5056.                         m_Buffer.RemoveChar( m_nCaret );
  5057.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  5058.                     }
  5059.                     ResetCaretBlink();
  5060.                     break;
  5061.                 }
  5062.  
  5063.                 case 24:        // Ctrl-X Cut
  5064.                 case VK_CANCEL: // Ctrl-C Copy
  5065.                 {
  5066.                     CopyToClipboard();
  5067.  
  5068.                     // If the key is Ctrl-X, delete the selection too.
  5069.                     if( (WCHAR)wParam == 24 )
  5070.                     {
  5071.                         DeleteSelectionText();
  5072.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  5073.                     }
  5074.  
  5075.                     break;
  5076.                 }
  5077.  
  5078.                 // Ctrl-V Paste
  5079.                 case 22:
  5080.                 {
  5081.                     PasteFromClipboard();
  5082.                     m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  5083.                     break;
  5084.                 }
  5085.  
  5086.                 // Ctrl-A Select All
  5087.                 case 1:
  5088.                     if( m_nSelStart == m_nCaret )
  5089.                     {
  5090.                         m_nSelStart = 0;
  5091.                         PlaceCaret( m_Buffer.GetTextSize() );
  5092.                     }
  5093.                     break;
  5094.  
  5095.                 case VK_RETURN:
  5096.                     // Invoke the callback when the user presses Enter.
  5097.                     m_pDialog->SendEvent( EVENT_EDITBOX_STRING, true, this );
  5098.                     break;
  5099.  
  5100.                 // Junk characters we don't want in the string
  5101.                 case 26:  // Ctrl Z
  5102.                 case 2:   // Ctrl B
  5103.                 case 14:  // Ctrl N
  5104.                 case 19:  // Ctrl S
  5105.                 case 4:   // Ctrl D
  5106.                 case 6:   // Ctrl F
  5107.                 case 7:   // Ctrl G
  5108.                 case 10:  // Ctrl J
  5109.                 case 11:  // Ctrl K
  5110.                 case 12:  // Ctrl L
  5111.                 case 17:  // Ctrl Q
  5112.                 case 23:  // Ctrl W
  5113.                 case 5:   // Ctrl E
  5114.                 case 18:  // Ctrl R
  5115.                 case 20:  // Ctrl T
  5116.                 case 25:  // Ctrl Y
  5117.                 case 21:  // Ctrl U
  5118.                 case 9:   // Ctrl I
  5119.                 case 15:  // Ctrl O
  5120.                 case 16:  // Ctrl P
  5121.                 case 27:  // Ctrl [
  5122.                 case 29:  // Ctrl ]
  5123.                 case 28:  // Ctrl \ 
  5124.                     break;
  5125.  
  5126.                 default:
  5127.                 {
  5128.                     // If there's a selection and the user
  5129.                     // starts to type, the selection should
  5130.                     // be deleted.
  5131.                     if( m_nCaret != m_nSelStart )
  5132.                         DeleteSelectionText();
  5133.  
  5134.                     // If we are in overwrite mode and there is already
  5135.                     // a char at the caret's position, simply replace it.
  5136.                     // Otherwise, we insert the char as normal.
  5137.                     if( !m_bInsertMode && m_nCaret < m_Buffer.GetTextSize() )
  5138.                     {
  5139.                         m_Buffer[m_nCaret] = (WCHAR)wParam;
  5140.                         PlaceCaret( m_nCaret + 1 );
  5141.                         m_nSelStart = m_nCaret;
  5142.                     } else
  5143.                     {
  5144.                         // Insert the char
  5145.                         if( m_Buffer.InsertChar( m_nCaret, (WCHAR)wParam ) )
  5146.                         {
  5147.                             PlaceCaret( m_nCaret + 1 );
  5148.                             m_nSelStart = m_nCaret;
  5149.                         }
  5150.                     }
  5151.                     ResetCaretBlink();
  5152.                     m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  5153.                 }
  5154.             }
  5155.             return true;
  5156.         }
  5157.     }
  5158.     return false;
  5159. }
  5160.  
  5161.  
  5162. //--------------------------------------------------------------------------------------
  5163. void CDXUTEditBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  5164. {
  5165.     if( m_bVisible == false )
  5166.         return;
  5167.  
  5168.     HRESULT hr;
  5169.     int nSelStartX = 0, nCaretX = 0;  // Left and right X cordinates of the selection region
  5170.  
  5171.     CDXUTElement* pElement = GetElement( 0 );
  5172.     if( pElement )
  5173.     {
  5174.         m_Buffer.SetFontIndex( pElement->iFont );
  5175.         PlaceCaret( m_nCaret );  // Call PlaceCaret now that we have the DC,
  5176.                                     // so that scrolling can be handled.
  5177.     }
  5178.  
  5179.     // Render the control graphics
  5180.     for( int e = 0; e < 9; ++e )
  5181.     {
  5182.         pElement = m_Elements.GetAt( e );
  5183.         pElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  5184.  
  5185.         m_pDialog->DrawSprite( pElement, &m_rcRender[e] );
  5186.     }
  5187.  
  5188.     //
  5189.     // Compute the X coordinates of the first visible character.
  5190.     //
  5191.     int nXFirst;
  5192.     m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nXFirst );
  5193.  
  5194.     //
  5195.     // Compute the X coordinates of the selection rectangle
  5196.     //
  5197.     hr = m_Buffer.CPtoX( m_nCaret, FALSE, &nCaretX );
  5198.     if( m_nCaret != m_nSelStart )
  5199.         hr = m_Buffer.CPtoX( m_nSelStart, FALSE, &nSelStartX );
  5200.     else
  5201.         nSelStartX = nCaretX;
  5202.  
  5203.     //
  5204.     // Render the selection rectangle
  5205.     //
  5206.     RECT rcSelection;  // Make this available for rendering selected text
  5207.     if( m_nCaret != m_nSelStart )
  5208.     {
  5209.         int nSelLeftX = nCaretX, nSelRightX = nSelStartX;
  5210.         // Swap if left is bigger than right
  5211.         if( nSelLeftX > nSelRightX )
  5212.             { int nTemp = nSelLeftX; nSelLeftX = nSelRightX; nSelRightX = nTemp; }
  5213.  
  5214.         SetRect( &rcSelection, nSelLeftX, m_rcText.top, nSelRightX, m_rcText.bottom );
  5215.         OffsetRect( &rcSelection, m_rcText.left - nXFirst, 0 );
  5216.         IntersectRect( &rcSelection, &m_rcText, &rcSelection );
  5217.         m_pDialog->DrawRect( &rcSelection, m_SelBkColor );
  5218.     }
  5219.  
  5220.     //
  5221.     // Render the text
  5222.     //
  5223.     // Element 0 for text
  5224.     m_Elements.GetAt( 0 )->FontColor.Current = m_TextColor;
  5225.     m_pDialog->DrawText( m_Buffer.GetBuffer() + m_nFirstVisible, m_Elements.GetAt( 0 ), &m_rcText );
  5226.  
  5227.     // Render the selected text
  5228.     if( m_nCaret != m_nSelStart )
  5229.     {
  5230.         int nFirstToRender = max( m_nFirstVisible, min( m_nSelStart, m_nCaret ) );
  5231.         int nNumChatToRender = max( m_nSelStart, m_nCaret ) - nFirstToRender;
  5232.         m_Elements.GetAt( 0 )->FontColor.Current = m_SelTextColor;
  5233.         m_pDialog->DrawText( m_Buffer.GetBuffer() + nFirstToRender,
  5234.                              m_Elements.GetAt( 0 ), &rcSelection, false, nNumChatToRender );
  5235.     }
  5236.  
  5237.     //
  5238.     // Blink the caret
  5239.     //
  5240.     if( DXUTGetGlobalTimer()->GetAbsoluteTime() - m_dfLastBlink >= m_dfBlink )
  5241.     {
  5242.         m_bCaretOn = !m_bCaretOn;
  5243.         m_dfLastBlink = DXUTGetGlobalTimer()->GetAbsoluteTime();
  5244.     }
  5245.  
  5246.     //
  5247.     // Render the caret if this control has the focus
  5248.     //
  5249.     if( m_bHasFocus && m_bCaretOn && !s_bHideCaret )
  5250.     {
  5251.         // Start the rectangle with insert mode caret
  5252.         RECT rcCaret = { m_rcText.left - nXFirst + nCaretX - 1, m_rcText.top,
  5253.                          m_rcText.left - nXFirst + nCaretX + 1, m_rcText.bottom };
  5254.  
  5255.         // If we are in overwrite mode, adjust the caret rectangle
  5256.         // to fill the entire character.
  5257.         if( !m_bInsertMode )
  5258.         {
  5259.             // Obtain the right edge X coord of the current character
  5260.             int nRightEdgeX;
  5261.             m_Buffer.CPtoX( m_nCaret, TRUE, &nRightEdgeX );
  5262.             rcCaret.right = m_rcText.left - nXFirst + nRightEdgeX;
  5263.         }
  5264.  
  5265.         m_pDialog->DrawRect( &rcCaret, m_CaretColor );
  5266.     }
  5267. }
  5268.  
  5269.  
  5270. #define IN_FLOAT_CHARSET( c ) \
  5271.     ( (c) == L'-' || (c) == L'.' || ( (c) >= L'0' && (c) <= L'9' ) )
  5272.  
  5273. void CDXUTEditBox::ParseFloatArray( float *pNumbers, int nCount )
  5274. {
  5275.     int nWritten = 0;  // Number of floats written
  5276.     const WCHAR *pToken, *pEnd;
  5277.     WCHAR wszToken[60];
  5278.  
  5279.     pToken = m_Buffer.GetBuffer();
  5280.     while( nWritten < nCount && *pToken != L'\0' )
  5281.     {
  5282.         // Skip leading spaces
  5283.         while( *pToken == L' ' )
  5284.             ++pToken;
  5285.  
  5286.         if( *pToken == L'\0' )
  5287.             break;
  5288.  
  5289.         // Locate the end of number
  5290.         pEnd = pToken;
  5291.         while( IN_FLOAT_CHARSET( *pEnd ) )
  5292.             ++pEnd;
  5293.  
  5294.         // Copy the token to our buffer
  5295.         int nTokenLen = min( sizeof(wszToken) / sizeof(wszToken[0]) - 1, int(pEnd - pToken) );
  5296.         wcsncpy( wszToken, pToken, nTokenLen );
  5297.         wszToken[nTokenLen] = L'\0';
  5298.         *pNumbers = (float)wcstod( wszToken, NULL );
  5299.         ++nWritten;
  5300.         ++pNumbers;
  5301.         pToken = pEnd;
  5302.     }
  5303. }
  5304.  
  5305.  
  5306. void CDXUTEditBox::SetTextFloatArray( const float *pNumbers, int nCount )
  5307. {
  5308.     WCHAR wszBuffer[512];
  5309.     WCHAR *pNext = wszBuffer;
  5310.  
  5311.     for( int i = 0; i < nCount; ++i )
  5312.     {
  5313.         pNext += _snwprintf( pNext, 512 - (pNext - wszBuffer), L"%.4f ", pNumbers[i] );
  5314.     }
  5315.  
  5316.     // Don't want the last space
  5317.     if( nCount > 0 )
  5318.         *(pNext - 1) = L'\0';
  5319.     else
  5320.         *pNext = L'\0';
  5321.  
  5322.     SetText( wszBuffer );
  5323. }
  5324.  
  5325.  
  5326. //--------------------------------------------------------------------------------------
  5327. // CDXUTIMEEditBox class
  5328. //--------------------------------------------------------------------------------------
  5329. // IME constants
  5330. #define CHT_IMEFILENAME1    "TINTLGNT.IME" // New Phonetic
  5331. #define CHT_IMEFILENAME2    "CINTLGNT.IME" // New Chang Jie
  5332. #define CHT_IMEFILENAME3    "MSTCIPHA.IME" // Phonetic 5.1
  5333. #define CHS_IMEFILENAME1    "PINTLGNT.IME" // MSPY1.5/2/3
  5334. #define CHS_IMEFILENAME2    "MSSCIPYA.IME" // MSPY3 for OfficeXP
  5335.  
  5336. #define LANG_CHT            MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
  5337. #define LANG_CHS            MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
  5338. #define _CHT_HKL            ( (HKL)(INT_PTR)0xE0080404 ) // New Phonetic
  5339. #define _CHT_HKL2           ( (HKL)(INT_PTR)0xE0090404 ) // New Chang Jie
  5340. #define _CHS_HKL            ( (HKL)(INT_PTR)0xE00E0804 ) // MSPY
  5341. #define MAKEIMEVERSION( major, minor ) \
  5342.     ( (DWORD)( ( (BYTE)( major ) << 24 ) | ( (BYTE)( minor ) << 16 ) ) )
  5343.  
  5344. #define IMEID_CHT_VER42 ( LANG_CHT | MAKEIMEVERSION( 4, 2 ) )    // New(Phonetic/ChanJie)IME98  : 4.2.x.x // Win98
  5345. #define IMEID_CHT_VER43 ( LANG_CHT | MAKEIMEVERSION( 4, 3 ) )    // New(Phonetic/ChanJie)IME98a : 4.3.x.x // Win2k
  5346. #define IMEID_CHT_VER44 ( LANG_CHT | MAKEIMEVERSION( 4, 4 ) )    // New ChanJie IME98b          : 4.4.x.x // WinXP
  5347. #define IMEID_CHT_VER50 ( LANG_CHT | MAKEIMEVERSION( 5, 0 ) )    // New(Phonetic/ChanJie)IME5.0 : 5.0.x.x // WinME
  5348. #define IMEID_CHT_VER51 ( LANG_CHT | MAKEIMEVERSION( 5, 1 ) )    // New(Phonetic/ChanJie)IME5.1 : 5.1.x.x // IME2002(w/OfficeXP)
  5349. #define IMEID_CHT_VER52 ( LANG_CHT | MAKEIMEVERSION( 5, 2 ) )    // New(Phonetic/ChanJie)IME5.2 : 5.2.x.x // IME2002a(w/Whistler)
  5350. #define IMEID_CHT_VER60 ( LANG_CHT | MAKEIMEVERSION( 6, 0 ) )    // New(Phonetic/ChanJie)IME6.0 : 6.0.x.x // IME XP(w/WinXP SP1)
  5351. #define IMEID_CHS_VER41    ( LANG_CHS | MAKEIMEVERSION( 4, 1 ) )    // MSPY1.5    // SCIME97 or MSPY1.5 (w/Win98, Office97)
  5352. #define IMEID_CHS_VER42    ( LANG_CHS | MAKEIMEVERSION( 4, 2 ) )    // MSPY2    // Win2k/WinME
  5353. #define IMEID_CHS_VER53    ( LANG_CHS | MAKEIMEVERSION( 5, 3 ) )    // MSPY3    // WinXP
  5354.  
  5355. // Function pointers
  5356. INPUTCONTEXT* (WINAPI * CDXUTIMEEditBox::_ImmLockIMC)( HIMC )
  5357.     = CDXUTIMEEditBox::Dummy_ImmLockIMC;
  5358. BOOL (WINAPI * CDXUTIMEEditBox::_ImmUnlockIMC)( HIMC )
  5359.     = CDXUTIMEEditBox::Dummy_ImmUnlockIMC;
  5360. LPVOID (WINAPI * CDXUTIMEEditBox::_ImmLockIMCC)( HIMCC )
  5361.     = CDXUTIMEEditBox::Dummy_ImmLockIMCC;
  5362. BOOL (WINAPI * CDXUTIMEEditBox::_ImmUnlockIMCC)( HIMCC )
  5363.     = CDXUTIMEEditBox::Dummy_ImmUnlockIMCC;
  5364. BOOL (WINAPI * CDXUTIMEEditBox::_ImmDisableTextFrameService)( DWORD )
  5365.     = CDXUTIMEEditBox::Dummy_ImmDisableTextFrameService;
  5366. LONG (WINAPI * CDXUTIMEEditBox::_ImmGetCompositionStringW)( HIMC, DWORD, LPVOID, DWORD )
  5367.     = CDXUTIMEEditBox::Dummy_ImmGetCompositionStringW;
  5368. DWORD (WINAPI * CDXUTIMEEditBox::_ImmGetCandidateListW)( HIMC, DWORD, LPCANDIDATELIST, DWORD )
  5369.     = CDXUTIMEEditBox::Dummy_ImmGetCandidateListW;
  5370. HIMC (WINAPI * CDXUTIMEEditBox::_ImmGetContext)( HWND )
  5371.     = CDXUTIMEEditBox::Dummy_ImmGetContext;
  5372. BOOL (WINAPI * CDXUTIMEEditBox::_ImmReleaseContext)( HWND, HIMC )
  5373.     = CDXUTIMEEditBox::Dummy_ImmReleaseContext;
  5374. HIMC (WINAPI * CDXUTIMEEditBox::_ImmAssociateContext)( HWND, HIMC )
  5375.     = CDXUTIMEEditBox::Dummy_ImmAssociateContext;
  5376. BOOL (WINAPI * CDXUTIMEEditBox::_ImmGetOpenStatus)( HIMC )
  5377.     = CDXUTIMEEditBox::Dummy_ImmGetOpenStatus;
  5378. BOOL (WINAPI * CDXUTIMEEditBox::_ImmSetOpenStatus)( HIMC, BOOL )
  5379.     = CDXUTIMEEditBox::Dummy_ImmSetOpenStatus;
  5380. BOOL (WINAPI * CDXUTIMEEditBox::_ImmGetConversionStatus)( HIMC, LPDWORD, LPDWORD )
  5381.     = CDXUTIMEEditBox::Dummy_ImmGetConversionStatus;
  5382. HWND (WINAPI * CDXUTIMEEditBox::_ImmGetDefaultIMEWnd)( HWND )
  5383.     = CDXUTIMEEditBox::Dummy_ImmGetDefaultIMEWnd;
  5384. UINT (WINAPI * CDXUTIMEEditBox::_ImmGetIMEFileNameA)( HKL, LPSTR, UINT )
  5385.     = CDXUTIMEEditBox::Dummy_ImmGetIMEFileNameA;
  5386. UINT (WINAPI * CDXUTIMEEditBox::_ImmGetVirtualKey)( HWND )
  5387.     = CDXUTIMEEditBox::Dummy_ImmGetVirtualKey;
  5388. BOOL (WINAPI * CDXUTIMEEditBox::_ImmNotifyIME)( HIMC, DWORD, DWORD, DWORD )
  5389.     = CDXUTIMEEditBox::Dummy_ImmNotifyIME;
  5390. BOOL (WINAPI * CDXUTIMEEditBox::_ImmSetConversionStatus)( HIMC, DWORD, DWORD )
  5391.     = CDXUTIMEEditBox::Dummy_ImmSetConversionStatus;
  5392. BOOL (WINAPI * CDXUTIMEEditBox::_ImmSimulateHotKey)( HWND, DWORD )
  5393.     = CDXUTIMEEditBox::Dummy_ImmSimulateHotKey;
  5394. BOOL (WINAPI * CDXUTIMEEditBox::_ImmIsIME)( HKL )
  5395.     = CDXUTIMEEditBox::Dummy_ImmIsIME;
  5396. // Traditional Chinese IME
  5397. UINT (WINAPI * CDXUTIMEEditBox::_GetReadingString)( HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT )
  5398.     = CDXUTIMEEditBox::Dummy_GetReadingString;
  5399. BOOL (WINAPI * CDXUTIMEEditBox::_ShowReadingWindow)( HIMC, BOOL )
  5400.     = CDXUTIMEEditBox::Dummy_ShowReadingWindow;
  5401.  
  5402. BOOL (APIENTRY * CDXUTIMEEditBox::_VerQueryValueA)( const LPVOID, LPSTR, LPVOID *, PUINT )
  5403.     = CDXUTIMEEditBox::Dummy_VerQueryValueA;
  5404. BOOL (APIENTRY * CDXUTIMEEditBox::_GetFileVersionInfoA)( LPSTR, DWORD, DWORD, LPVOID )
  5405.     = CDXUTIMEEditBox::Dummy_GetFileVersionInfoA;
  5406. DWORD (APIENTRY * CDXUTIMEEditBox::_GetFileVersionInfoSizeA)( LPSTR, LPDWORD )
  5407.     = CDXUTIMEEditBox::Dummy_GetFileVersionInfoSizeA;
  5408.  
  5409. HINSTANCE CDXUTIMEEditBox::s_hDllImm32;      // IMM32 DLL handle
  5410. HINSTANCE CDXUTIMEEditBox::s_hDllVer;        // Version DLL handle
  5411. HKL       CDXUTIMEEditBox::s_hklCurrent;     // Current keyboard layout of the process
  5412. bool      CDXUTIMEEditBox::s_bVerticalCand;  // Indicates that the candidates are listed vertically
  5413. WCHAR     CDXUTIMEEditBox::s_aszIndicator[5][3] = // String to draw to indicate current input locale
  5414.             {
  5415.                 L"En",
  5416.                 L"\x7B80",
  5417.                 L"\x7E41",
  5418.                 L"\xAC00",
  5419.                 L"\x3042",
  5420.             };
  5421. LPWSTR    CDXUTIMEEditBox::s_wszCurrIndicator   // Points to an indicator string that corresponds to current input locale
  5422.             = CDXUTIMEEditBox::s_aszIndicator[0];
  5423. bool      CDXUTIMEEditBox::s_bInsertOnType;     // Insert the character as soon as a key is pressed (Korean behavior)
  5424. HINSTANCE CDXUTIMEEditBox::s_hDllIme;           // Instance handle of the current IME module
  5425. HIMC      CDXUTIMEEditBox::s_hImcDef;           // Default input context
  5426. CDXUTIMEEditBox::IMESTATE  CDXUTIMEEditBox::s_ImeState = IMEUI_STATE_OFF;
  5427. bool      CDXUTIMEEditBox::s_bEnableImeSystem;  // Whether the IME system is active
  5428. POINT     CDXUTIMEEditBox::s_ptCompString;      // Composition string position. Updated every frame.
  5429. int       CDXUTIMEEditBox::s_nCompCaret;
  5430. int       CDXUTIMEEditBox::s_nFirstTargetConv;  // Index of the first target converted char in comp string.  If none, -1.
  5431. CDXUTEditBox::CUniBuffer CDXUTIMEEditBox::s_CompString = CDXUTEditBox::CUniBuffer( MAX_COMPSTRING_SIZE );
  5432. BYTE      CDXUTIMEEditBox::s_abCompStringAttr[MAX_COMPSTRING_SIZE];
  5433. DWORD     CDXUTIMEEditBox::s_adwCompStringClause[MAX_COMPSTRING_SIZE];
  5434. WCHAR     CDXUTIMEEditBox::s_wszReadingString[32];
  5435. CDXUTIMEEditBox::CCandList CDXUTIMEEditBox::s_CandList;       // Data relevant to the candidate list
  5436. bool      CDXUTIMEEditBox::s_bShowReadingWindow; // Indicates whether reading window is visible
  5437. bool      CDXUTIMEEditBox::s_bHorizontalReading; // Indicates whether the reading window is vertical or horizontal
  5438. bool      CDXUTIMEEditBox::s_bChineseIME;
  5439. CGrowableArray< CDXUTIMEEditBox::CInputLocale > CDXUTIMEEditBox::s_Locale; // Array of loaded keyboard layout on system
  5440.  
  5441.  
  5442. //--------------------------------------------------------------------------------------
  5443. CDXUTIMEEditBox::CDXUTIMEEditBox( CDXUTDialog *pDialog )
  5444. {
  5445.     m_Type = DXUT_CONTROL_IMEEDITBOX;
  5446.     m_pDialog = pDialog;
  5447.  
  5448.     s_bEnableImeSystem = true;
  5449.     m_nIndicatorWidth = 0;
  5450.     m_ReadingColor = D3DCOLOR_ARGB( 188, 255, 255, 255 );
  5451.     m_ReadingWinColor = D3DCOLOR_ARGB( 128, 0, 0, 0 );
  5452.     m_ReadingSelColor = D3DCOLOR_ARGB( 255, 255, 0, 0 );
  5453.     m_ReadingSelBkColor = D3DCOLOR_ARGB( 128, 80, 80, 80 );
  5454.     m_CandidateColor = D3DCOLOR_ARGB( 255, 200, 200, 200 );
  5455.     m_CandidateWinColor = D3DCOLOR_ARGB( 128, 0, 0, 0 );
  5456.     m_CandidateSelColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
  5457.     m_CandidateSelBkColor = D3DCOLOR_ARGB( 128, 158, 158, 158 );
  5458.     m_CompColor = D3DCOLOR_ARGB( 255, 200, 200, 255 );
  5459.     m_CompWinColor = D3DCOLOR_ARGB( 198, 0, 0, 0 );
  5460.     m_CompCaretColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
  5461.     m_CompTargetColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
  5462.     m_CompTargetBkColor = D3DCOLOR_ARGB( 255, 150, 150, 150 );
  5463.     m_CompTargetNonColor = D3DCOLOR_ARGB( 255, 255, 255, 0 );
  5464.     m_CompTargetNonBkColor = D3DCOLOR_ARGB( 255, 150, 150, 150 );
  5465.     m_IndicatorImeColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
  5466.     m_IndicatorEngColor = D3DCOLOR_ARGB( 255, 0, 0, 0 );
  5467.     m_IndicatorBkColor = D3DCOLOR_ARGB( 255, 128, 128, 128 );
  5468. }
  5469.  
  5470.  
  5471. //--------------------------------------------------------------------------------------
  5472. CDXUTIMEEditBox::~CDXUTIMEEditBox()
  5473. {
  5474. }
  5475.  
  5476.  
  5477. //--------------------------------------------------------------------------------------
  5478. void CDXUTIMEEditBox::SendKey( BYTE nVirtKey )
  5479. {
  5480.     keybd_event( nVirtKey, 0, 0,               0 );
  5481.     keybd_event( nVirtKey, 0, KEYEVENTF_KEYUP, 0 );
  5482. }
  5483.  
  5484.  
  5485. //--------------------------------------------------------------------------------------
  5486. // Called by CDXUTResourceCache's OnCreateDevice.  This gives the class a
  5487. // chance to initialize its default input context associated with the app window.
  5488. HRESULT CDXUTIMEEditBox::StaticOnCreateDevice()
  5489. {
  5490.     // Save the default input context
  5491.     s_hImcDef = _ImmGetContext( DXUTGetHWND() );
  5492.     _ImmReleaseContext( DXUTGetHWND(), s_hImcDef );
  5493.  
  5494.     return S_OK;
  5495. }
  5496.  
  5497.  
  5498. //--------------------------------------------------------------------------------------
  5499. void CDXUTIMEEditBox::UpdateRects()
  5500. {
  5501.     // Temporary adjust m_width so that CDXUTEditBox can compute
  5502.     // the correct rects for its rendering since we need to make space
  5503.     // for the indicator button
  5504.     int nWidth = m_width;
  5505.     m_width -= m_nIndicatorWidth + m_nBorder * 2; // Make room for the indicator button
  5506.     CDXUTEditBox::UpdateRects();
  5507.     m_width = nWidth;  // Restore
  5508.  
  5509.     // Compute the indicator button rectangle
  5510.     SetRect( &m_rcIndicator, m_rcBoundingBox.right, m_rcBoundingBox.top, m_x + m_width, m_rcBoundingBox.bottom );
  5511. //    InflateRect( &m_rcIndicator, -m_nBorder, -m_nBorder );
  5512.     m_rcBoundingBox.right = m_rcBoundingBox.left + m_width;
  5513. }
  5514.  
  5515.  
  5516. //--------------------------------------------------------------------------------------
  5517. //    GetImeId( UINT uIndex )
  5518. //        returns 
  5519. //    returned value:
  5520. //    0: In the following cases
  5521. //        - Non Chinese IME input locale
  5522. //        - Older Chinese IME
  5523. //        - Other error cases
  5524. //
  5525. //    Othewise:
  5526. //      When uIndex is 0 (default)
  5527. //            bit 31-24:    Major version
  5528. //            bit 23-16:    Minor version
  5529. //            bit 15-0:    Language ID
  5530. //        When uIndex is 1
  5531. //            pVerFixedInfo->dwFileVersionLS
  5532. //
  5533. //    Use IMEID_VER and IMEID_LANG macro to extract version and language information.
  5534. //    
  5535.  
  5536. // We define the locale-invariant ID ourselves since it doesn't exist prior to WinXP
  5537. // For more information, see the CompareString() reference.
  5538. #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
  5539.  
  5540. DWORD CDXUTIMEEditBox::GetImeId( UINT uIndex )
  5541. {
  5542.     static HKL hklPrev = 0;
  5543.     static DWORD dwID[2] = { 0, 0 };  // Cache the result
  5544.     
  5545.     DWORD   dwVerSize;
  5546.     DWORD   dwVerHandle;
  5547.     LPVOID  lpVerBuffer;
  5548.     LPVOID  lpVerData;
  5549.     UINT    cbVerData;
  5550.     char    szTmp[1024];
  5551.  
  5552.     if( uIndex >= sizeof( dwID ) / sizeof( dwID[0] ) )
  5553.         return 0;
  5554.  
  5555.     if( hklPrev == s_hklCurrent )
  5556.         return dwID[uIndex];
  5557.  
  5558.     hklPrev = s_hklCurrent;  // Save for the next invocation
  5559.  
  5560.     // Check if we are using an older Chinese IME
  5561.     if( !( ( s_hklCurrent == _CHT_HKL ) || ( s_hklCurrent == _CHT_HKL2 ) || ( s_hklCurrent == _CHS_HKL ) ) )
  5562.     {
  5563.         dwID[0] = dwID[1] = 0;
  5564.         return dwID[uIndex];
  5565.     }
  5566.  
  5567.     // Obtain the IME file name
  5568.     if ( !_ImmGetIMEFileNameA( s_hklCurrent, szTmp, ( sizeof(szTmp) / sizeof(szTmp[0]) ) - 1 ) )
  5569.     {
  5570.         dwID[0] = dwID[1] = 0;
  5571.         return dwID[uIndex];
  5572.     }
  5573.  
  5574.     // Check for IME that doesn't implement reading string API
  5575.     if ( !_GetReadingString )
  5576.     {
  5577.         if( ( CompareStringA( LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHT_IMEFILENAME1, -1 ) != CSTR_EQUAL ) &&
  5578.             ( CompareStringA( LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHT_IMEFILENAME2, -1 ) != CSTR_EQUAL ) &&
  5579.             ( CompareStringA( LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHT_IMEFILENAME3, -1 ) != CSTR_EQUAL ) &&
  5580.             ( CompareStringA( LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHS_IMEFILENAME1, -1 ) != CSTR_EQUAL ) &&
  5581.             ( CompareStringA( LCID_INVARIANT, NORM_IGNORECASE, szTmp, -1, CHS_IMEFILENAME2, -1 ) != CSTR_EQUAL ) )
  5582.         {
  5583.             dwID[0] = dwID[1] = 0;
  5584.             return dwID[uIndex];
  5585.         }
  5586.     }
  5587.  
  5588.     dwVerSize = _GetFileVersionInfoSizeA( szTmp, &dwVerHandle );
  5589.     if( dwVerSize )
  5590.     {
  5591.         lpVerBuffer = HeapAlloc( GetProcessHeap(), 0, dwVerSize );
  5592.         if( lpVerBuffer )
  5593.         {
  5594.             if( _GetFileVersionInfoA( szTmp, dwVerHandle, dwVerSize, lpVerBuffer ) )
  5595.             {
  5596.                 if( _VerQueryValueA( lpVerBuffer, "\\", &lpVerData, &cbVerData ) )
  5597.                 {
  5598.                     DWORD dwVer = ( (VS_FIXEDFILEINFO*)lpVerData )->dwFileVersionMS;
  5599.                     dwVer = ( dwVer & 0x00ff0000 ) << 8 | ( dwVer & 0x000000ff ) << 16;
  5600.                     if( _GetReadingString
  5601.                         ||
  5602.                         ( GetLanguage() == LANG_CHT &&
  5603.                           ( dwVer == MAKEIMEVERSION(4, 2) || 
  5604.                             dwVer == MAKEIMEVERSION(4, 3) || 
  5605.                             dwVer == MAKEIMEVERSION(4, 4) || 
  5606.                             dwVer == MAKEIMEVERSION(5, 0) ||
  5607.                             dwVer == MAKEIMEVERSION(5, 1) ||
  5608.                             dwVer == MAKEIMEVERSION(5, 2) ||
  5609.                             dwVer == MAKEIMEVERSION(6, 0) ) )
  5610.                         ||
  5611.                         ( GetLanguage() == LANG_CHS &&
  5612.                           ( dwVer == MAKEIMEVERSION(4, 1) ||
  5613.                             dwVer == MAKEIMEVERSION(4, 2) ||
  5614.                             dwVer == MAKEIMEVERSION(5, 3) ) )
  5615.                       )
  5616.                     {
  5617.                         dwID[0] = dwVer | GetLanguage();
  5618.                         dwID[1] = ( (VS_FIXEDFILEINFO*)lpVerData )->dwFileVersionLS;
  5619.                     }
  5620.                 }
  5621.             }
  5622.             HeapFree( GetProcessHeap(), 0, lpVerBuffer );
  5623.         }
  5624.     }
  5625.  
  5626.     return dwID[uIndex];
  5627. }
  5628.  
  5629.  
  5630. //--------------------------------------------------------------------------------------
  5631. void CDXUTIMEEditBox::CheckInputLocale()
  5632. {
  5633.     static HKL hklPrev = 0;
  5634.     s_hklCurrent = GetKeyboardLayout( 0 );
  5635.     if ( hklPrev == s_hklCurrent )
  5636.         return;
  5637.  
  5638.     hklPrev = s_hklCurrent;
  5639.     switch ( GetPrimaryLanguage() )
  5640.     {
  5641.         // Simplified Chinese
  5642.         case LANG_CHINESE:
  5643.             s_bVerticalCand = true;
  5644.             switch ( GetSubLanguage() )
  5645.             {
  5646.                 case SUBLANG_CHINESE_SIMPLIFIED:
  5647.                     s_wszCurrIndicator = s_aszIndicator[INDICATOR_CHS];
  5648.                     s_bVerticalCand = GetImeId() == 0;
  5649.                     break;
  5650.                 case SUBLANG_CHINESE_TRADITIONAL:
  5651.                     s_wszCurrIndicator = s_aszIndicator[INDICATOR_CHT];
  5652.                     break;
  5653.                 default:    // unsupported sub-language
  5654.                     s_wszCurrIndicator = s_aszIndicator[INDICATOR_NON_IME];
  5655.                     break;
  5656.             }
  5657.             break;
  5658.         // Korean
  5659.         case LANG_KOREAN:
  5660.             s_wszCurrIndicator = s_aszIndicator[INDICATOR_KOREAN];
  5661.             s_bVerticalCand = false;
  5662.             break;
  5663.         // Japanese
  5664.         case LANG_JAPANESE:
  5665.             s_wszCurrIndicator = s_aszIndicator[INDICATOR_JAPANESE];
  5666.             s_bVerticalCand = true;
  5667.             break;
  5668.         default:
  5669.             // A non-IME language.  Obtain the language abbreviation
  5670.             // and store it for rendering the indicator later.
  5671.             s_wszCurrIndicator = s_aszIndicator[INDICATOR_NON_IME];
  5672.     }
  5673.  
  5674.     // If non-IME, use the language abbreviation.
  5675.     if( s_wszCurrIndicator == s_aszIndicator[INDICATOR_NON_IME] )
  5676.     {
  5677.         WCHAR wszLang[5];
  5678.         GetLocaleInfoW( MAKELCID( LOWORD( s_hklCurrent ), SORT_DEFAULT ), LOCALE_SABBREVLANGNAME, wszLang, 5 );
  5679.         s_wszCurrIndicator[0] = wszLang[0];
  5680.         s_wszCurrIndicator[1] = towlower( wszLang[1] );
  5681.     }
  5682. }
  5683.  
  5684.  
  5685. //--------------------------------------------------------------------------------------
  5686. void CDXUTIMEEditBox::CheckToggleState()
  5687. {
  5688.     CheckInputLocale();
  5689.     bool bIme = _ImmIsIME( s_hklCurrent ) != 0;
  5690.     s_bChineseIME = ( GetPrimaryLanguage() == LANG_CHINESE ) && bIme;
  5691.  
  5692.     HIMC hImc;
  5693.     if( NULL != ( hImc = _ImmGetContext( DXUTGetHWND() ) ) )
  5694.     {
  5695.         if( s_bChineseIME )
  5696.         {
  5697.             DWORD dwConvMode, dwSentMode;
  5698.             _ImmGetConversionStatus( hImc, &dwConvMode, &dwSentMode );
  5699.             s_ImeState = ( dwConvMode & IME_CMODE_NATIVE ) ? IMEUI_STATE_ON : IMEUI_STATE_ENGLISH;
  5700.         }
  5701.         else
  5702.         {
  5703.             s_ImeState = ( bIme && _ImmGetOpenStatus( hImc ) != 0 ) ? IMEUI_STATE_ON : IMEUI_STATE_OFF;
  5704.         }
  5705.         _ImmReleaseContext( DXUTGetHWND(), hImc );
  5706.     }
  5707.     else
  5708.         s_ImeState = IMEUI_STATE_OFF;
  5709. }
  5710.  
  5711.  
  5712. //--------------------------------------------------------------------------------------
  5713. // Enable/disable the entire IME system.  When disabled, the default IME handling
  5714. // kicks in.
  5715. void CDXUTIMEEditBox::EnableImeSystem( bool bEnable )
  5716. {
  5717.     s_bEnableImeSystem = bEnable;
  5718. }
  5719.  
  5720.  
  5721. //--------------------------------------------------------------------------------------
  5722. // Sets up IME-specific APIs for the IME edit controls.  This is called every time
  5723. // the input locale changes.
  5724. void CDXUTIMEEditBox::SetupImeApi()
  5725. {
  5726.     char szImeFile[MAX_PATH + 1];
  5727.  
  5728.     _GetReadingString = NULL;
  5729.     _ShowReadingWindow = NULL;
  5730.     if( _ImmGetIMEFileNameA( s_hklCurrent, szImeFile, sizeof(szImeFile)/sizeof(szImeFile[0]) - 1 ) == 0 )
  5731.         return;
  5732.  
  5733.     if( s_hDllIme ) FreeLibrary( s_hDllIme );
  5734.     s_hDllIme = LoadLibraryA( szImeFile );
  5735.     if ( !s_hDllIme )
  5736.         return;
  5737.     _GetReadingString = (UINT (WINAPI*)(HIMC, UINT, LPWSTR, PINT, BOOL*, PUINT))
  5738.         ( GetProcAddress( s_hDllIme, "GetReadingString" ) );
  5739.     _ShowReadingWindow =(BOOL (WINAPI*)(HIMC, BOOL))
  5740.         ( GetProcAddress( s_hDllIme, "ShowReadingWindow" ) );
  5741. }
  5742.  
  5743.  
  5744. //--------------------------------------------------------------------------------------
  5745. // Resets the composition string.
  5746. void CDXUTIMEEditBox::ResetCompositionString()
  5747. {
  5748.     s_nCompCaret = 0;
  5749.     s_CompString.SetText( L"" );
  5750.     ZeroMemory( s_abCompStringAttr, sizeof(s_abCompStringAttr) );
  5751. }
  5752.  
  5753.  
  5754. //--------------------------------------------------------------------------------------
  5755. // Truncate composition string by sending keystrokes to the window.
  5756. void CDXUTIMEEditBox::TruncateCompString( bool bUseBackSpace, int iNewStrLen )
  5757. {
  5758.     if( !s_bInsertOnType )
  5759.         return;
  5760.  
  5761.     int cc = (int) wcslen( s_CompString.GetBuffer() );
  5762.     assert( iNewStrLen == 0 || iNewStrLen >= cc );
  5763.  
  5764.     // Send right arrow keystrokes to move the caret
  5765.     //   to the end of the composition string.
  5766.     for (int i = 0; i < cc - s_nCompCaret; ++i )
  5767.         SendMessage( DXUTGetHWND(), WM_KEYDOWN, VK_RIGHT, 0 );
  5768.     SendMessage( DXUTGetHWND(), WM_KEYUP, VK_RIGHT, 0 );
  5769.  
  5770.     if( bUseBackSpace || m_bInsertMode )
  5771.         iNewStrLen = 0;
  5772.  
  5773.     // The caller sets bUseBackSpace to false if there's possibility of sending
  5774.     // new composition string to the app right after this function call.
  5775.     // 
  5776.     // If the app is in overwriting mode and new comp string is 
  5777.     // shorter than current one, delete previous comp string 
  5778.     // till it's same long as the new one. Then move caret to the beginning of comp string.
  5779.     // New comp string will overwrite old one.
  5780.     if( iNewStrLen < cc )
  5781.     {
  5782.         for( int i = 0; i < cc - iNewStrLen; ++i )
  5783.         {
  5784.             SendMessage( DXUTGetHWND(), WM_KEYDOWN, VK_BACK, 0 );  // Backspace character
  5785.             SendMessageW( DXUTGetHWND(), WM_CHAR, VK_BACK, 0 );
  5786.         }
  5787.         SendMessage( DXUTGetHWND(), WM_KEYUP, VK_BACK, 0 );
  5788.     }
  5789.     else
  5790.         iNewStrLen = cc;
  5791.  
  5792.     // Move the caret to the beginning by sending left keystrokes
  5793.     for (int i = 0; i < iNewStrLen; ++i )
  5794.         SendMessage( DXUTGetHWND(), WM_KEYDOWN, VK_LEFT, 0 );
  5795.     SendMessage( DXUTGetHWND(), WM_KEYUP, VK_LEFT, 0 );
  5796. }
  5797.  
  5798.  
  5799. //--------------------------------------------------------------------------------------
  5800. // Sends the current composition string to the application by sending keystroke
  5801. // messages.
  5802. void CDXUTIMEEditBox::SendCompString()
  5803. {
  5804.     for( int i = 0; i < lstrlen( s_CompString.GetBuffer() ); ++i )
  5805.         MsgProc( WM_CHAR, (WPARAM)s_CompString[i], 0 );
  5806. }
  5807.  
  5808.  
  5809. //--------------------------------------------------------------------------------------
  5810. // Outputs current composition string then cleans up the composition task.
  5811. void CDXUTIMEEditBox::FinalizeString( bool bSend )
  5812. {
  5813.     HIMC hImc;
  5814.     if( NULL == ( hImc = _ImmGetContext( DXUTGetHWND() ) ) )
  5815.         return;
  5816.  
  5817.     static bool bProcessing = false;
  5818.     if( bProcessing )    // avoid infinite recursion
  5819.     {
  5820.         DXUTTRACE( L"CDXUTIMEEditBox::FinalizeString: Reentrant detected!\n" );
  5821.         _ImmReleaseContext( DXUTGetHWND(), hImc );
  5822.         return;
  5823.     }
  5824.     bProcessing = true;
  5825.  
  5826.     if( !s_bInsertOnType && bSend )
  5827.     {
  5828.         // Send composition string to app.
  5829.         LONG lLength = lstrlen( s_CompString.GetBuffer() );
  5830.         // In case of CHT IME, don't send the trailing double byte space, if it exists.
  5831.         if( GetLanguage() == LANG_CHT
  5832.             && s_CompString[lLength - 1] == 0x3000 )
  5833.         {
  5834.             --lLength;
  5835.         }
  5836.         SendCompString();
  5837.     }
  5838.  
  5839.     ResetCompositionString();
  5840.     // Clear composition string in IME
  5841.     _ImmNotifyIME( hImc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 );
  5842.     // the following line is necessary as Korean IME doesn't close cand list
  5843.     // when comp string is cancelled.
  5844.     _ImmNotifyIME( hImc, NI_CLOSECANDIDATE, 0, 0 ); 
  5845.     _ImmReleaseContext( DXUTGetHWND(), hImc );
  5846.     bProcessing = false;
  5847. }
  5848.  
  5849.  
  5850. //--------------------------------------------------------------------------------------
  5851. // Determine whether the reading window should be vertical or horizontal.
  5852. void CDXUTIMEEditBox::GetReadingWindowOrientation( DWORD dwId )
  5853. {
  5854.     s_bHorizontalReading = ( s_hklCurrent == _CHS_HKL ) || ( s_hklCurrent == _CHT_HKL2 ) || ( dwId == 0 );
  5855.     if( !s_bHorizontalReading && ( dwId & 0x0000FFFF ) == LANG_CHT )
  5856.     {
  5857.         WCHAR wszRegPath[MAX_PATH];
  5858.         HKEY hKey;
  5859.         DWORD dwVer = dwId & 0xFFFF0000;
  5860.         lstrcpy( wszRegPath, L"software\\microsoft\\windows\\currentversion\\" );
  5861.         lstrcat( wszRegPath, ( dwVer >= MAKEIMEVERSION( 5, 1 ) ) ? L"MSTCIPH" : L"TINTLGNT" );
  5862.         LONG lRc = RegOpenKeyExW( HKEY_CURRENT_USER, wszRegPath, 0, KEY_READ, &hKey );
  5863.         if (lRc == ERROR_SUCCESS)
  5864.         {
  5865.             DWORD dwSize = sizeof(DWORD), dwMapping, dwType;
  5866.             lRc = RegQueryValueExW( hKey, L"Keyboard Mapping", NULL, &dwType, (PBYTE)&dwMapping, &dwSize );
  5867.             if (lRc == ERROR_SUCCESS)
  5868.             {
  5869.                 if ( ( dwVer <= MAKEIMEVERSION( 5, 0 ) && 
  5870.                        ( (BYTE)dwMapping == 0x22 || (BYTE)dwMapping == 0x23 ) )
  5871.                      ||
  5872.                      ( ( dwVer == MAKEIMEVERSION( 5, 1 ) || dwVer == MAKEIMEVERSION( 5, 2 ) ) &&
  5873.                        (BYTE)dwMapping >= 0x22 && (BYTE)dwMapping <= 0x24 )
  5874.                    )
  5875.                 {
  5876.                     s_bHorizontalReading = true;
  5877.                 }
  5878.             }
  5879.             RegCloseKey( hKey );
  5880.         }
  5881.     }
  5882. }
  5883.  
  5884.  
  5885. //--------------------------------------------------------------------------------------
  5886. // Obtain the reading string upon WM_IME_NOTIFY/INM_PRIVATE notification.
  5887. void CDXUTIMEEditBox::GetPrivateReadingString()
  5888. {
  5889.     DWORD dwId = GetImeId();
  5890.     if( !dwId )
  5891.     {
  5892.         s_bShowReadingWindow = false;
  5893.         return;
  5894.     }
  5895.  
  5896.     HIMC hImc;
  5897.     hImc = _ImmGetContext( DXUTGetHWND() );
  5898.     if( !hImc )
  5899.     {
  5900.         s_bShowReadingWindow = false;
  5901.         return;
  5902.     }
  5903.  
  5904.     DWORD dwReadingStrLen = 0;
  5905.     DWORD dwErr = 0;
  5906.     WCHAR *pwszReadingStringBuffer = NULL;  // Buffer for when the IME supports GetReadingString()
  5907.     WCHAR *wstr = 0;
  5908.     bool bUnicodeIme = false;  // Whether the IME context component is Unicode.
  5909.     INPUTCONTEXT *lpIC = NULL;
  5910.  
  5911.     if( _GetReadingString )
  5912.     {
  5913.         UINT uMaxUiLen;
  5914.         BOOL bVertical;
  5915.         // Obtain the reading string size
  5916.         dwReadingStrLen = _GetReadingString( hImc, 0, NULL, (PINT)&dwErr, &bVertical, &uMaxUiLen );
  5917.         if( dwReadingStrLen )
  5918.         {
  5919.             wstr = pwszReadingStringBuffer = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * dwReadingStrLen );
  5920.             if( !pwszReadingStringBuffer )
  5921.             {
  5922.                 // Out of memory. Exit.
  5923.                 _ImmReleaseContext( DXUTGetHWND(), hImc );
  5924.                 return;
  5925.             }
  5926.  
  5927.             // Obtain the reading string
  5928.             dwReadingStrLen = _GetReadingString( hImc, dwReadingStrLen, wstr, (PINT)&dwErr, &bVertical, &uMaxUiLen );
  5929.         }
  5930.  
  5931.         s_bHorizontalReading = !bVertical;
  5932.         bUnicodeIme = true;
  5933.     }
  5934.     else
  5935.     {
  5936.         // IMEs that doesn't implement Reading String API
  5937.  
  5938.         lpIC = _ImmLockIMC( hImc );
  5939.         
  5940.         LPBYTE p = 0;
  5941.         switch( dwId )
  5942.         {
  5943.             case IMEID_CHT_VER42: // New(Phonetic/ChanJie)IME98  : 4.2.x.x // Win98
  5944.             case IMEID_CHT_VER43: // New(Phonetic/ChanJie)IME98a : 4.3.x.x // WinMe, Win2k
  5945.             case IMEID_CHT_VER44: // New ChanJie IME98b          : 4.4.x.x // WinXP
  5946.                 p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC( lpIC->hPrivate ) + 24 );
  5947.                 if( !p ) break;
  5948.                 dwReadingStrLen = *(DWORD *)( p + 7 * 4 + 32 * 4 );
  5949.                 dwErr = *(DWORD *)( p + 8 * 4 + 32 * 4 );
  5950.                 wstr = (WCHAR *)( p + 56 );
  5951.                 bUnicodeIme = true;
  5952.                 break;
  5953.  
  5954.             case IMEID_CHT_VER50: // 5.0.x.x // WinME
  5955.                 p = *(LPBYTE *)( (LPBYTE)_ImmLockIMCC( lpIC->hPrivate ) + 3 * 4 );
  5956.                 if( !p ) break;
  5957.                 p = *(LPBYTE *)( (LPBYTE)p + 1*4 + 5*4 + 4*2 );
  5958.                 if( !p ) break;
  5959.                 dwReadingStrLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16);
  5960.                 dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 + 1*4);
  5961.                 wstr = (WCHAR *)(p + 1*4 + (16*2+2*4) + 5*4);
  5962.                 bUnicodeIme = false;
  5963.                 break;
  5964.  
  5965.             case IMEID_CHT_VER51: // 5.1.x.x // IME2002(w/OfficeXP)
  5966.             case IMEID_CHT_VER52: // 5.2.x.x // (w/whistler)
  5967.             case IMEID_CHS_VER53: // 5.3.x.x // SCIME2k or MSPY3 (w/OfficeXP and Whistler)
  5968.                 p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC( lpIC->hPrivate ) + 4);
  5969.                 if( !p ) break;
  5970.                 p = *(LPBYTE *)((LPBYTE)p + 1*4 + 5*4);
  5971.                 if( !p ) break;
  5972.                 dwReadingStrLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * 2);
  5973.                 dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * 2 + 1*4);
  5974.                 wstr  = (WCHAR *) (p + 1*4 + (16*2+2*4) + 5*4);
  5975.                 bUnicodeIme = true;
  5976.                 break;
  5977.  
  5978.             // the code tested only with Win 98 SE (MSPY 1.5/ ver 4.1.0.21)
  5979.             case IMEID_CHS_VER41:
  5980.             {
  5981.                 int nOffset;
  5982.                 nOffset = ( GetImeId( 1 ) >= 0x00000002 ) ? 8 : 7;
  5983.  
  5984.                 p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC( lpIC->hPrivate ) + nOffset * 4);
  5985.                 if( !p ) break;
  5986.                 dwReadingStrLen = *(DWORD *)(p + 7*4 + 16*2*4);
  5987.                 dwErr = *(DWORD *)(p + 8*4 + 16*2*4);
  5988.                 dwErr = min( dwErr, dwReadingStrLen );
  5989.                 wstr = (WCHAR *)(p + 6*4 + 16*2*1);
  5990.                 bUnicodeIme = true;
  5991.                 break;
  5992.             }
  5993.  
  5994.             case IMEID_CHS_VER42: // 4.2.x.x // SCIME98 or MSPY2 (w/Office2k, Win2k, WinME, etc)
  5995.             {
  5996.                 OSVERSIONINFOW osi;
  5997.                 osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
  5998.                 GetVersionExW( &osi );
  5999.  
  6000.                 int nTcharSize = ( osi.dwPlatformId == VER_PLATFORM_WIN32_NT ) ? sizeof(WCHAR) : sizeof(char);
  6001.                 p = *(LPBYTE *)((LPBYTE)_ImmLockIMCC( lpIC->hPrivate ) + 1*4 + 1*4 + 6*4);
  6002.                 if( !p ) break;
  6003.                 dwReadingStrLen = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * nTcharSize);
  6004.                 dwErr = *(DWORD *)(p + 1*4 + (16*2+2*4) + 5*4 + 16 * nTcharSize + 1*4);
  6005.                 wstr  = (WCHAR *) (p + 1*4 + (16*2+2*4) + 5*4);
  6006.                 bUnicodeIme = ( osi.dwPlatformId == VER_PLATFORM_WIN32_NT ) ? true : false;
  6007.             }
  6008.         }   // switch
  6009.     }
  6010.  
  6011.     // Copy the reading string to the candidate list first
  6012.     s_CandList.awszCandidate[0][0] = 0;
  6013.     s_CandList.awszCandidate[1][0] = 0;
  6014.     s_CandList.awszCandidate[2][0] = 0;
  6015.     s_CandList.awszCandidate[3][0] = 0;
  6016.     s_CandList.dwCount = dwReadingStrLen;
  6017.     s_CandList.dwSelection = (DWORD)-1; // do not select any char
  6018.     if( bUnicodeIme )
  6019.     {
  6020.         UINT i;
  6021.         for( i = 0; i < dwReadingStrLen; ++i ) // dwlen > 0, if known IME
  6022.         {
  6023.             if( dwErr <= i && s_CandList.dwSelection == (DWORD)-1 )
  6024.             {
  6025.                 // select error char
  6026.                 s_CandList.dwSelection = i;
  6027.             }
  6028.  
  6029.             s_CandList.awszCandidate[i][0] = wstr[i];
  6030.             s_CandList.awszCandidate[i][1] = 0;
  6031.         }
  6032.         s_CandList.awszCandidate[i][0] = 0;
  6033.     }
  6034.     else
  6035.     {
  6036.         char *p = (char *)wstr;
  6037.         DWORD i, j;
  6038.         for( i = 0, j = 0; i < dwReadingStrLen; ++i, ++j ) // dwlen > 0, if known IME
  6039.         {
  6040.             if( dwErr <= i && s_CandList.dwSelection == (DWORD)-1 )
  6041.             {
  6042.                 s_CandList.dwSelection = j;
  6043.             }
  6044.             // Obtain the current code page
  6045.             WCHAR wszCodePage[8];
  6046.             UINT uCodePage = CP_ACP;  // Default code page
  6047.             if( GetLocaleInfoW( MAKELCID( GetLanguage(), SORT_DEFAULT ),
  6048.                                 LOCALE_IDEFAULTANSICODEPAGE,
  6049.                                 wszCodePage,
  6050.                                 sizeof(wszCodePage)/sizeof(wszCodePage[0]) ) )
  6051.             {
  6052.                 uCodePage = wcstoul( wszCodePage, NULL, 0 );
  6053.             }
  6054.             MultiByteToWideChar( uCodePage, 0, p + i, IsDBCSLeadByteEx( uCodePage, p[i] ) ? 2 : 1,
  6055.                                  s_CandList.awszCandidate[j], 1 );
  6056.             if( IsDBCSLeadByteEx( uCodePage, p[i] ) )
  6057.                 ++i;
  6058.         }
  6059.         s_CandList.awszCandidate[j][0] = 0;
  6060.         s_CandList.dwCount = j;
  6061.     }
  6062.     if( !_GetReadingString )
  6063.     {
  6064.         _ImmUnlockIMCC( lpIC->hPrivate );
  6065.         _ImmUnlockIMC( hImc );
  6066.         GetReadingWindowOrientation( dwId );
  6067.     }
  6068.     _ImmReleaseContext( DXUTGetHWND(), hImc );
  6069.  
  6070.     if( pwszReadingStringBuffer )
  6071.         HeapFree( GetProcessHeap(), 0, pwszReadingStringBuffer );
  6072.  
  6073.     // Copy the string to the reading string buffer
  6074.     if( s_CandList.dwCount > 0 )
  6075.         s_bShowReadingWindow = true;
  6076.     else
  6077.         s_bShowReadingWindow = false;
  6078.     if( s_bHorizontalReading )
  6079.     {
  6080.         s_CandList.nReadingError = -1;
  6081.         s_wszReadingString[0] = 0;
  6082.         for( UINT i = 0; i < s_CandList.dwCount; ++i )
  6083.         {
  6084.             if( s_CandList.dwSelection == i )
  6085.                 s_CandList.nReadingError = lstrlen( s_wszReadingString );
  6086.             wcsncat( s_wszReadingString, s_CandList.awszCandidate[i], 32 - lstrlenW( s_wszReadingString ) - 1 );
  6087.         }
  6088.     }
  6089.  
  6090.     s_CandList.dwPageSize = MAX_CANDLIST;
  6091. }
  6092.  
  6093.  
  6094. //--------------------------------------------------------------------------------------
  6095. // This function is used only briefly in CHT IME handling,
  6096. // so accelerator isn't processed.
  6097. void CDXUTIMEEditBox::PumpMessage()
  6098. {
  6099.     MSG msg;
  6100.  
  6101.     while( PeekMessageW( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  6102.     {
  6103.         if( !GetMessageW( &msg, NULL, 0, 0 ) )
  6104.         {
  6105.             PostQuitMessage( (int)msg.wParam );
  6106.             return;
  6107.         }
  6108.         TranslateMessage( &msg );
  6109.         DispatchMessageA( &msg );
  6110.     }
  6111. }
  6112.  
  6113.  
  6114. //--------------------------------------------------------------------------------------
  6115. void CDXUTIMEEditBox::OnFocusIn()
  6116. {
  6117.     CDXUTEditBox::OnFocusIn();
  6118.  
  6119.     if( s_bEnableImeSystem )
  6120.     {
  6121.         _ImmAssociateContext( DXUTGetHWND(), s_hImcDef );
  6122.         CheckToggleState();
  6123.     } else
  6124.         _ImmAssociateContext( DXUTGetHWND(), NULL );
  6125.  
  6126.     //
  6127.     // Set up the IME global state according to the current instance state
  6128.     //
  6129.     HIMC hImc;
  6130.     if( NULL != ( hImc = _ImmGetContext( DXUTGetHWND() ) ) ) 
  6131.     {
  6132.         if( !s_bEnableImeSystem )
  6133.             s_ImeState = IMEUI_STATE_OFF;
  6134.  
  6135.         _ImmReleaseContext( DXUTGetHWND(), hImc );
  6136.         CheckToggleState();
  6137.     }
  6138. }
  6139.  
  6140.  
  6141. //--------------------------------------------------------------------------------------
  6142. void CDXUTIMEEditBox::OnFocusOut()
  6143. {
  6144.     CDXUTEditBox::OnFocusOut();
  6145.  
  6146.     FinalizeString( false );  // Don't send the comp string as to match RichEdit behavior
  6147.  
  6148.     _ImmAssociateContext( DXUTGetHWND(), NULL );
  6149. }
  6150.  
  6151.  
  6152. //--------------------------------------------------------------------------------------
  6153. bool CDXUTIMEEditBox::StaticMsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  6154. {
  6155.     HIMC hImc;
  6156.  
  6157.     if( !s_bEnableImeSystem )
  6158.         return false;
  6159.  
  6160.     switch( uMsg )
  6161.     {
  6162.         case WM_ACTIVATEAPP:
  6163.             if( wParam )
  6164.             {
  6165.                 // Populate s_Locale with the list of keyboard layouts.
  6166.                 UINT cKL = GetKeyboardLayoutList( 0, NULL );
  6167.                 s_Locale.RemoveAll();
  6168.                 HKL *phKL = new HKL[cKL];
  6169.                 if( phKL )
  6170.                 {
  6171.                     GetKeyboardLayoutList( cKL, phKL );
  6172.                     for( UINT i = 0; i < cKL; ++i )
  6173.                     {
  6174.                         CInputLocale Locale;
  6175.  
  6176.                         // Filter out East Asian languages that are not IME.
  6177.                         if( ( PRIMARYLANGID( LOWORD( phKL[i] ) ) == LANG_CHINESE ||
  6178.                               PRIMARYLANGID( LOWORD( phKL[i] ) ) == LANG_JAPANESE ||
  6179.                               PRIMARYLANGID( LOWORD( phKL[i] ) ) == LANG_KOREAN ) &&
  6180.                               !_ImmIsIME( phKL[i] ) )
  6181.                               continue;
  6182.  
  6183.                         // If this language is already in the list, don't add it again.
  6184.                         bool bBreak = false;
  6185.                         for( int e = 0; e < s_Locale.GetSize(); ++e )
  6186.                             if( LOWORD( s_Locale.GetAt( e ).m_hKL ) ==
  6187.                                 LOWORD( phKL[i] ) )
  6188.                             {
  6189.                                 bBreak = true;
  6190.                                 break;
  6191.                             }
  6192.                         if( bBreak )
  6193.                             break;
  6194.  
  6195.                         Locale.m_hKL = phKL[i];
  6196.                         WCHAR wszDesc[128] = L"";
  6197.                         switch( PRIMARYLANGID( LOWORD( phKL[i] ) ) )
  6198.                         {
  6199.                             // Simplified Chinese
  6200.                             case LANG_CHINESE:
  6201.                                 switch( SUBLANGID( LOWORD( phKL[i] ) ) )
  6202.                                 {
  6203.                                     case SUBLANG_CHINESE_SIMPLIFIED:
  6204.                                         lstrcpy( Locale.m_wszLangAbb, s_aszIndicator[INDICATOR_CHS] );
  6205.                                         break;
  6206.                                     case SUBLANG_CHINESE_TRADITIONAL:
  6207.                                         lstrcpy( Locale.m_wszLangAbb, s_aszIndicator[INDICATOR_CHT] );
  6208.                                         break;
  6209.                                     default:    // unsupported sub-language
  6210.                                         GetLocaleInfoW( MAKELCID( LOWORD( phKL[i] ), SORT_DEFAULT ), LOCALE_SABBREVLANGNAME, wszDesc, 128 );
  6211.                                         Locale.m_wszLangAbb[0] = wszDesc[0];
  6212.                                         Locale.m_wszLangAbb[1] = towlower( wszDesc[1] );
  6213.                                         Locale.m_wszLangAbb[2] = L'\0';
  6214.                                         break;
  6215.                                 }
  6216.                                 break;
  6217.                             // Korean
  6218.                             case LANG_KOREAN:
  6219.                                 lstrcpy( Locale.m_wszLangAbb, s_aszIndicator[INDICATOR_KOREAN] );
  6220.                                 break;
  6221.                             // Japanese
  6222.                             case LANG_JAPANESE:
  6223.                                 lstrcpy( Locale.m_wszLangAbb, s_aszIndicator[INDICATOR_JAPANESE] );
  6224.                                 break;         
  6225.                             default:
  6226.                                 // A non-IME language.  Obtain the language abbreviation
  6227.                                 // and store it for rendering the indicator later.
  6228.                                 GetLocaleInfoW( MAKELCID( LOWORD( phKL[i] ), SORT_DEFAULT ), LOCALE_SABBREVLANGNAME, wszDesc, 128 );
  6229.                                 Locale.m_wszLangAbb[0] = wszDesc[0];
  6230.                                 Locale.m_wszLangAbb[1] = towlower( wszDesc[1] );
  6231.                                 Locale.m_wszLangAbb[2] = L'\0';
  6232.                                 break;
  6233.                         }
  6234.  
  6235.                         GetLocaleInfoW( MAKELCID( LOWORD( phKL[i] ), SORT_DEFAULT ), LOCALE_SLANGUAGE, wszDesc, 128 );
  6236.                         wcsncpy( Locale.m_wszLang, wszDesc, sizeof(Locale.m_wszLang) / sizeof(Locale.m_wszLang[0]) );
  6237.                         Locale.m_wszLang[sizeof(Locale.m_wszLang) / sizeof(Locale.m_wszLang[0]) - 1] = L'\0';
  6238.  
  6239.                         s_Locale.Add( Locale );
  6240.                     }
  6241.                     delete[] phKL;
  6242.                 }
  6243.             }
  6244.             break;
  6245.  
  6246.         case WM_INPUTLANGCHANGE:
  6247.             DXUTTRACE( L"WM_INPUTLANGCHANGE\n" );
  6248.             {
  6249.                 UINT uLang = GetPrimaryLanguage();
  6250.                 CheckToggleState();
  6251.                 if ( uLang != GetPrimaryLanguage() )
  6252.                 {
  6253.                     // Korean IME always inserts on keystroke.  Other IMEs do not.
  6254.                     s_bInsertOnType = ( GetPrimaryLanguage() == LANG_KOREAN );
  6255.                 }
  6256.  
  6257.                 // IME changed.  Setup the new IME.
  6258.                 SetupImeApi();
  6259.                 if( _ShowReadingWindow )
  6260.                 {
  6261.                     if ( NULL != ( hImc = _ImmGetContext( DXUTGetHWND() ) ) )
  6262.                     {
  6263.                         _ShowReadingWindow( hImc, false );
  6264.                         _ImmReleaseContext( DXUTGetHWND(), hImc );
  6265.                     }
  6266.                 }
  6267.             }
  6268.             return true;
  6269.  
  6270.         case WM_IME_SETCONTEXT:
  6271.             DXUTTRACE( L"WM_IME_SETCONTEXT\n" );
  6272.             //
  6273.             // We don't want anything to display, so we have to clear this
  6274.             //
  6275.             lParam = 0;
  6276.             return false;
  6277.  
  6278.         // Handle WM_IME_STARTCOMPOSITION here since
  6279.         // we do not want the default IME handler to see
  6280.         // this when our fullscreen app is running.
  6281.         case WM_IME_STARTCOMPOSITION:
  6282.             DXUTTRACE( L"WM_IME_STARTCOMPOSITION\n" );
  6283.             ResetCompositionString();
  6284.             // Since the composition string has its own caret, we don't render
  6285.             // the edit control's own caret to avoid double carets on screen.
  6286.             s_bHideCaret = true;
  6287.             return true;
  6288.  
  6289.         case WM_IME_COMPOSITION:
  6290.             DXUTTRACE( L"WM_IME_COMPOSITION\n" );
  6291.             return true;
  6292.     }
  6293.  
  6294.     return false;
  6295. }
  6296.  
  6297.  
  6298. //--------------------------------------------------------------------------------------
  6299. bool CDXUTIMEEditBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  6300. {
  6301.     if( !m_bEnabled || !m_bVisible )
  6302.         return false;
  6303.  
  6304.     switch( uMsg )
  6305.     {
  6306.         case WM_LBUTTONDOWN:
  6307.         case WM_LBUTTONDBLCLK:
  6308.         {
  6309.             DXUTFontNode* pFont = m_pDialog->GetFont( m_Elements.GetAt( 9 )->iFont );
  6310.  
  6311.             // Check if this click is on top of the composition string
  6312.             int nCompStrWidth;
  6313.             s_CompString.CPtoX( s_CompString.GetTextSize(), FALSE, &nCompStrWidth );
  6314.  
  6315.             if( s_ptCompString.x <= pt.x &&
  6316.                 s_ptCompString.y <= pt.y &&
  6317.                 s_ptCompString.x + nCompStrWidth > pt.x &&
  6318.                 s_ptCompString.y + pFont->nHeight > pt.y )
  6319.             {
  6320.                 int nCharBodyHit, nCharHit;
  6321.                 int nTrail;
  6322.  
  6323.                 // Determine the character clicked on.
  6324.                 s_CompString.XtoCP( pt.x - s_ptCompString.x, &nCharBodyHit, &nTrail );
  6325.                 if( nTrail && nCharBodyHit < s_CompString.GetTextSize() )
  6326.                     nCharHit = nCharBodyHit + 1;
  6327.                 else
  6328.                     nCharHit = nCharBodyHit;
  6329.  
  6330.                 // Now generate keypress events to move the comp string cursor
  6331.                 // to the click point.  First, if the candidate window is displayed,
  6332.                 // send Esc to close it.
  6333.                 HIMC hImc = _ImmGetContext( DXUTGetHWND() );
  6334.                 if( !hImc )
  6335.                     return true;
  6336.  
  6337.                 _ImmNotifyIME( hImc, NI_CLOSECANDIDATE, 0, 0 );
  6338.                 _ImmReleaseContext( DXUTGetHWND(), hImc );
  6339.  
  6340.                 switch( GetPrimaryLanguage() )
  6341.                 {
  6342.                     case LANG_JAPANESE:
  6343.                         // For Japanese, there are two cases.  If s_nFirstTargetConv is
  6344.                         // -1, the comp string hasn't been converted yet, and we use
  6345.                         // s_nCompCaret.  For any other value of s_nFirstTargetConv,
  6346.                         // the string has been converted, so we use clause information.
  6347.  
  6348.                         if( s_nFirstTargetConv != -1 )
  6349.                         {
  6350.                             int nClauseClicked = 0;
  6351.                             while( (int)s_adwCompStringClause[nClauseClicked + 1] <= nCharBodyHit )
  6352.                                 ++nClauseClicked;
  6353.  
  6354.                             int nClauseSelected = 0;
  6355.                             while( (int)s_adwCompStringClause[nClauseSelected + 1] <= s_nFirstTargetConv )
  6356.                                 ++nClauseSelected;
  6357.  
  6358.                             BYTE nVirtKey = nClauseClicked > nClauseSelected ? VK_RIGHT : VK_LEFT;
  6359.                             int nSendCount = abs( nClauseClicked - nClauseSelected );
  6360.                             while( nSendCount-- > 0 )
  6361.                                 SendKey( nVirtKey );
  6362.  
  6363.                             return true;
  6364.                         }
  6365.  
  6366.                         // Not converted case. Fall thru to Chinese case.
  6367.  
  6368.                     case LANG_CHINESE:
  6369.                     {
  6370.                         // For Chinese, use s_nCompCaret.
  6371.                         BYTE nVirtKey = nCharHit > s_nCompCaret ? VK_RIGHT : VK_LEFT;
  6372.                         int nSendCount = abs( nCharHit - s_nCompCaret );
  6373.                         while( nSendCount-- > 0 )
  6374.                             SendKey( nVirtKey );
  6375.                         break;
  6376.                     }
  6377.                 }
  6378.  
  6379.                 return true;
  6380.             }
  6381.  
  6382.             // Check if the click is on top of the candidate window
  6383.             if( s_CandList.bShowWindow && PtInRect( &s_CandList.rcCandidate, pt ) )
  6384.             {
  6385.                 if( s_bVerticalCand )
  6386.                 {
  6387.                     // Vertical candidate window
  6388.  
  6389.                     // Compute the row the click is on
  6390.                     int nRow = ( pt.y - s_CandList.rcCandidate.top ) / pFont->nHeight;
  6391.  
  6392.                     if( nRow < (int)s_CandList.dwCount )
  6393.                     {
  6394.                         // nRow is a valid entry.
  6395.                         // Now emulate keystrokes to select the candidate at this row.
  6396.                         switch( GetPrimaryLanguage() )
  6397.                         {
  6398.                             case LANG_CHINESE:
  6399.                             case LANG_KOREAN:
  6400.                                 // For Chinese and Korean, simply send the number keystroke.
  6401.                                 SendKey( '0' + nRow + 1 );
  6402.                                 break;
  6403.  
  6404.                             case LANG_JAPANESE:
  6405.                                 // For Japanese, move the selection to the target row,
  6406.                                 // then send Right, then send Left.
  6407.  
  6408.                                 BYTE nVirtKey;
  6409.                                 if( nRow > (int)s_CandList.dwSelection )
  6410.                                     nVirtKey = VK_DOWN;
  6411.                                 else
  6412.                                     nVirtKey = VK_UP;
  6413.                                 int nNumToHit = abs( int( nRow - s_CandList.dwSelection ) );
  6414.                                 for( int nStrike = 0; nStrike < nNumToHit; ++nStrike )
  6415.                                     SendKey( nVirtKey );
  6416.  
  6417.                                 // Do this to close the candidate window without ending composition.
  6418.                                 SendKey( VK_RIGHT );
  6419.                                 SendKey( VK_LEFT );
  6420.  
  6421.                                 break;
  6422.                         }
  6423.                     }
  6424.                 } else
  6425.                 {
  6426.                     // Horizontal candidate window
  6427.  
  6428.                     // Determine which the character the click has hit.
  6429.                     int nCharHit;
  6430.                     int nTrail;
  6431.                     s_CandList.HoriCand.XtoCP( pt.x - s_CandList.rcCandidate.left, &nCharHit, &nTrail );
  6432.  
  6433.                     // Determine which candidate string the character belongs to.
  6434.                     int nCandidate = s_CandList.dwCount - 1;
  6435.  
  6436.                     int nEntryStart = 0;
  6437.                     for( UINT i = 0; i < s_CandList.dwCount; ++i )
  6438.                     {
  6439.                         if( nCharHit >= nEntryStart )
  6440.                         {
  6441.                             // Haven't found it.
  6442.                             nEntryStart += lstrlenW( s_CandList.awszCandidate[i] ) + 1;  // plus space separator
  6443.                         } else
  6444.                         {
  6445.                             // Found it.  This entry starts at the right side of the click point,
  6446.                             // so the char belongs to the previous entry.
  6447.                             nCandidate = i - 1;
  6448.                             break;
  6449.                         }
  6450.                     }
  6451.  
  6452.                     // Now emulate keystrokes to select the candidate entry.
  6453.                     switch( GetPrimaryLanguage() )
  6454.                     {
  6455.                         case LANG_CHINESE:
  6456.                         case LANG_KOREAN:
  6457.                             // For Chinese and Korean, simply send the number keystroke.
  6458.                             SendKey( '0' + nCandidate + 1 );
  6459.                             break;
  6460.                     }
  6461.                 }
  6462.  
  6463.                 return true;
  6464.             }
  6465.         }
  6466.     }
  6467.  
  6468.     // If we didn't care for the msg, let the parent process it.
  6469.     return CDXUTEditBox::HandleMouse( uMsg, pt, wParam, lParam );
  6470. }
  6471.  
  6472.  
  6473. //--------------------------------------------------------------------------------------
  6474. bool CDXUTIMEEditBox::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  6475. {
  6476.     if( !m_bEnabled || !m_bVisible )
  6477.         return false;
  6478.  
  6479.     // TEMPORARY!!! TEMPORARY!!! TEMPORARY!!!
  6480.     // See how I can get rid of trapped later.
  6481.     bool trappedData;
  6482.     bool *trapped = &trappedData;
  6483.  
  6484.     HIMC hImc;
  6485.     static LPARAM lAlt = 0x80000000, lCtrl = 0x80000000, lShift = 0x80000000;
  6486.  
  6487.     *trapped = false;
  6488.     if( !s_bEnableImeSystem )
  6489.         return CDXUTEditBox::MsgProc( uMsg, wParam, lParam );
  6490.  
  6491.     switch( uMsg )
  6492.     {
  6493.         //
  6494.         //  IME Handling
  6495.         //
  6496.         case WM_IME_COMPOSITION:
  6497.             DXUTTRACE( L"WM_IME_COMPOSITION\n" );
  6498.             {
  6499.                 LONG lRet;  // Returned count in CHARACTERS
  6500.                 WCHAR wszCompStr[MAX_COMPSTRING_SIZE];
  6501.  
  6502.                 *trapped = true;
  6503.                 if( NULL == ( hImc = _ImmGetContext( DXUTGetHWND() ) ) )
  6504.                 {
  6505.                     break;
  6506.                 }
  6507.  
  6508.                 // Get the caret position in composition string
  6509.                 if ( lParam & GCS_CURSORPOS )
  6510.                 {
  6511.                     s_nCompCaret = _ImmGetCompositionStringW( hImc, GCS_CURSORPOS, NULL, 0 );
  6512.                     if( s_nCompCaret < 0 )
  6513.                         s_nCompCaret = 0; // On error, set caret to pos 0.
  6514.                 }
  6515.  
  6516.                 // ResultStr must be processed before composition string.
  6517.                 //
  6518.                 // This is because for some IMEs, such as CHT, pressing Enter
  6519.                 // to complete the composition sends WM_IME_COMPOSITION with both
  6520.                 // GCS_RESULTSTR and GCS_COMPSTR.  Retrieving the result string
  6521.                 // gives the correct string, while retrieving the comp string
  6522.                 // (GCS_COMPSTR) gives empty string.  GCS_RESULTSTR should be
  6523.                 // handled first so that the application receives the string.  Then
  6524.                 // GCS_COMPSTR can be handled to clear the comp string buffer.
  6525.  
  6526.                 if ( lParam & GCS_RESULTSTR )
  6527.                 {
  6528.                     DXUTTRACE( L"  GCS_RESULTSTR\n" );
  6529.                     lRet = _ImmGetCompositionStringW( hImc, GCS_RESULTSTR, wszCompStr, sizeof( wszCompStr ) );
  6530.                     if( lRet > 0 )
  6531.                     {
  6532.                         lRet /= sizeof(WCHAR);
  6533.                         wszCompStr[lRet] = 0;  // Force terminate
  6534.                         TruncateCompString( false, (int)wcslen( wszCompStr ) );
  6535.                         s_CompString.SetText( wszCompStr );
  6536.                         SendCompString();
  6537.                         ResetCompositionString();
  6538.                     }
  6539.                 }
  6540.  
  6541.                 //
  6542.                 // Reads in the composition string.
  6543.                 //
  6544.                 if ( lParam & GCS_COMPSTR )
  6545.                 {
  6546.                     DXUTTRACE( L"  GCS_COMPSTR\n" );
  6547.                     //////////////////////////////////////////////////////
  6548.                     // Retrieve the latest user-selected IME candidates
  6549.                     lRet = _ImmGetCompositionStringW( hImc, GCS_COMPSTR, wszCompStr, sizeof( wszCompStr ) );
  6550.                     if( lRet > 0 )
  6551.                     {
  6552.                         lRet /= sizeof(WCHAR);  // Convert size in byte to size in char
  6553.                         wszCompStr[lRet] = 0;  // Force terminate
  6554.                         //
  6555.                         // Remove the whole of the string
  6556.                         //
  6557.                         TruncateCompString( false, (int)wcslen( wszCompStr ) );
  6558.  
  6559.                         s_CompString.SetText( wszCompStr );
  6560.  
  6561.                         // Older CHT IME uses composition string for reading string
  6562.                         if ( GetLanguage() == LANG_CHT && !GetImeId() )
  6563.                         {
  6564.                             if( lstrlen( s_CompString.GetBuffer() ) )
  6565.                             {
  6566.                                 s_CandList.dwCount = 4;             // Maximum possible length for reading string is 4
  6567.                                 s_CandList.dwSelection = (DWORD)-1; // don't select any candidate
  6568.  
  6569.                                 // Copy the reading string to the candidate list
  6570.                                 for( int i = 3; i >= 0; --i )
  6571.                                 {
  6572.                                     if( i > lstrlen( s_CompString.GetBuffer() ) - 1 )
  6573.                                         s_CandList.awszCandidate[i][0] = 0;  // Doesn't exist
  6574.                                     else
  6575.                                     {
  6576.                                         s_CandList.awszCandidate[i][0] = s_CompString[i];
  6577.                                         s_CandList.awszCandidate[i][1] = 0;
  6578.                                     }
  6579.                                 }
  6580.                                 s_CandList.dwPageSize = MAX_CANDLIST;
  6581.                                 // Clear comp string after we are done copying
  6582.                                 ZeroMemory( (LPVOID)s_CompString.GetBuffer(), 4 * sizeof(WCHAR) );
  6583.                                 s_bShowReadingWindow = true;
  6584.                                 GetReadingWindowOrientation( 0 );
  6585.                                 if( s_bHorizontalReading )
  6586.                                 {
  6587.                                     s_CandList.nReadingError = -1;  // Clear error
  6588.  
  6589.                                     // Create a string that consists of the current
  6590.                                     // reading string.  Since horizontal reading window
  6591.                                     // is used, we take advantage of this by rendering
  6592.                                     // one string instead of several.
  6593.                                     //
  6594.                                     // Copy the reading string from the candidate list
  6595.                                     // to the reading string buffer.
  6596.                                     s_wszReadingString[0] = 0;
  6597.                                     for( UINT i = 0; i < s_CandList.dwCount; ++i )
  6598.                                     {
  6599.                                         if( s_CandList.dwSelection == i )
  6600.                                             s_CandList.nReadingError = lstrlen( s_wszReadingString );
  6601.                                         wcsncat( s_wszReadingString, s_CandList.awszCandidate[i], 32 - lstrlenW( s_wszReadingString ) - 1 );
  6602.                                     }
  6603.                                 }
  6604.                             }
  6605.                             else
  6606.                             {
  6607.                                 s_CandList.dwCount = 0;
  6608.                                 s_bShowReadingWindow = false;
  6609.                             }
  6610.                         }
  6611.  
  6612.                         if( s_bInsertOnType )
  6613.                         {
  6614.                             // Send composition string to the edit control
  6615.                             SendCompString();
  6616.                             // Restore the caret to the correct location.
  6617.                             // It's at the end right now, so compute the number
  6618.                             // of times left arrow should be pressed to
  6619.                             // send it to the original position.
  6620.                             int nCount = lstrlen( s_CompString.GetBuffer() + s_nCompCaret );
  6621.                             // Send left keystrokes
  6622.                             for( int i = 0; i < nCount; ++i )
  6623.                                 SendMessage( DXUTGetHWND(), WM_KEYDOWN, VK_LEFT, 0 );
  6624.                             SendMessage( DXUTGetHWND(), WM_KEYUP, VK_LEFT, 0 );
  6625.                         }
  6626.                     }
  6627.  
  6628.                     ResetCaretBlink();
  6629.                 }
  6630.  
  6631.                 // Retrieve comp string attributes
  6632.                 if( lParam & GCS_COMPATTR )
  6633.                 {
  6634.                     lRet = _ImmGetCompositionStringW( hImc, GCS_COMPATTR, s_abCompStringAttr, sizeof( s_abCompStringAttr ) );
  6635.                     if( lRet > 0 )
  6636.                         s_abCompStringAttr[lRet] = 0;  // ??? Is this needed for attributes?
  6637.                 }
  6638.  
  6639.                 // Retrieve clause information
  6640.                 if( lParam & GCS_COMPCLAUSE )
  6641.                 {
  6642.                     lRet = _ImmGetCompositionStringW(hImc, GCS_COMPCLAUSE, s_adwCompStringClause, sizeof( s_adwCompStringClause ) );
  6643.                     s_adwCompStringClause[lRet / sizeof(DWORD)] = 0;  // Terminate
  6644.                 }
  6645.  
  6646.                 _ImmReleaseContext( DXUTGetHWND(), hImc );
  6647.             }
  6648.             break;
  6649.  
  6650.         case WM_IME_ENDCOMPOSITION:
  6651.             DXUTTRACE( L"WM_IME_ENDCOMPOSITION\n" );
  6652.             TruncateCompString();
  6653.             ResetCompositionString();
  6654.             // We can show the edit control's caret again.
  6655.             s_bHideCaret = false;
  6656.             // Hide reading window
  6657.             s_bShowReadingWindow = false;
  6658.             break;
  6659.  
  6660.         case WM_IME_NOTIFY:
  6661.             DXUTTRACE( L"WM_IME_NOTIFY %u\n", wParam );
  6662.             switch( wParam )
  6663.             {
  6664.                 case IMN_SETCONVERSIONMODE:
  6665.                     DXUTTRACE( L"  IMN_SETCONVERSIONMODE\n" );
  6666.                 case IMN_SETOPENSTATUS:
  6667.                     DXUTTRACE( L"  IMN_SETOPENSTATUS\n" );
  6668.                     CheckToggleState();
  6669.                     break;
  6670.  
  6671.                 case IMN_OPENCANDIDATE:
  6672.                 case IMN_CHANGECANDIDATE:
  6673.                 {
  6674.                     DXUTTRACE( wParam == IMN_CHANGECANDIDATE ? L"  IMN_CHANGECANDIDATE\n" : L"  IMN_OPENCANDIDATE\n" );
  6675.  
  6676.                     s_CandList.bShowWindow = true;
  6677.                     *trapped = true;
  6678.                     if( NULL == ( hImc = _ImmGetContext( DXUTGetHWND() ) ) )
  6679.                         break;
  6680.  
  6681.                     LPCANDIDATELIST lpCandList = NULL;
  6682.                     DWORD dwLenRequired;
  6683.  
  6684.                     s_bShowReadingWindow = false;
  6685.                     // Retrieve the candidate list
  6686.                     dwLenRequired = _ImmGetCandidateListW( hImc, 0, NULL, 0 );
  6687.                     if( dwLenRequired )
  6688.                     {
  6689.                         lpCandList = (LPCANDIDATELIST)HeapAlloc( GetProcessHeap(), 0, dwLenRequired );
  6690.                         dwLenRequired = _ImmGetCandidateListW( hImc, 0, lpCandList, dwLenRequired );
  6691.                     }
  6692.  
  6693.                     if( lpCandList )
  6694.                     {
  6695.                         // Update candidate list data
  6696.                         s_CandList.dwSelection = lpCandList->dwSelection;
  6697.                         s_CandList.dwCount = lpCandList->dwCount;
  6698.  
  6699.                         int nPageTopIndex = 0;
  6700.                         s_CandList.dwPageSize = min( lpCandList->dwPageSize, MAX_CANDLIST );
  6701.                         if( GetPrimaryLanguage() == LANG_JAPANESE )
  6702.                         {
  6703.                             // Japanese IME organizes its candidate list a little
  6704.                             // differently from the other IMEs.
  6705.                             nPageTopIndex = ( s_CandList.dwSelection / s_CandList.dwPageSize ) * s_CandList.dwPageSize;
  6706.                         }
  6707.                         else
  6708.                             nPageTopIndex = lpCandList->dwPageStart;
  6709.  
  6710.                         // Make selection index relative to first entry of page
  6711.                         s_CandList.dwSelection = ( GetLanguage() == LANG_CHS && !GetImeId() ) ? (DWORD)-1
  6712.                                                  : s_CandList.dwSelection - nPageTopIndex;
  6713.  
  6714.                         ZeroMemory( s_CandList.awszCandidate, sizeof(s_CandList.awszCandidate) );
  6715.                         for( UINT i = nPageTopIndex, j = 0;
  6716.                             (DWORD)i < lpCandList->dwCount && j < s_CandList.dwPageSize;
  6717.                             i++, j++ )
  6718.                         {
  6719.                             // Initialize the candidate list strings
  6720.                             LPWSTR pwsz = s_CandList.awszCandidate[j];
  6721.                             // For every candidate string entry,
  6722.                             // write [index] + Space + [String] if vertical,
  6723.                             // write [index] + [String] + Space if horizontal.
  6724.                             *pwsz++ = (WCHAR)( L'0' + ( (j + 1) % 10 ) );  // Index displayed is 1 based
  6725.                             if( s_bVerticalCand )
  6726.                                 *pwsz++ = L' ';
  6727.                             WCHAR *pwszNewCand = (LPWSTR)( (LPBYTE)lpCandList + lpCandList->dwOffset[i] );
  6728.                             while ( *pwszNewCand )
  6729.                                 *pwsz++ = *pwszNewCand++;
  6730.                             if( !s_bVerticalCand )
  6731.                                 *pwsz++ = L' ';
  6732.                             *pwsz = 0;  // Terminate
  6733.                         }
  6734.  
  6735.                         // Make dwCount in s_CandList be number of valid entries in the page.
  6736.                         s_CandList.dwCount = lpCandList->dwCount - lpCandList->dwPageStart;
  6737.                         if( s_CandList.dwCount > lpCandList->dwPageSize )
  6738.                             s_CandList.dwCount = lpCandList->dwPageSize;
  6739.  
  6740.                         HeapFree( GetProcessHeap(), 0, lpCandList );
  6741.                         _ImmReleaseContext( DXUTGetHWND(), hImc );
  6742.  
  6743.                         // Korean and old Chinese IME can't have selection.
  6744.                         // User must use the number hotkey or Enter to select
  6745.                         // a candidate.
  6746.                         if( GetPrimaryLanguage() == LANG_KOREAN ||
  6747.                             GetLanguage() == LANG_CHT && !GetImeId() )
  6748.                         {
  6749.                             s_CandList.dwSelection = (DWORD)-1;
  6750.                         }
  6751.  
  6752.                         // Initialize s_CandList.HoriCand if we have a
  6753.                         // horizontal candidate window.
  6754.                         if( !s_bVerticalCand )
  6755.                         {
  6756.                             WCHAR wszCand[256] = L"";
  6757.  
  6758.                             s_CandList.nFirstSelected = 0;
  6759.                             s_CandList.nHoriSelectedLen = 0;
  6760.                             for( UINT i = 0; i < MAX_CANDLIST; ++i )
  6761.                             {
  6762.                                 if( s_CandList.awszCandidate[i][0] == L'\0' )
  6763.                                     break;
  6764.  
  6765.                                 WCHAR wszEntry[32];
  6766.                                 swprintf( wszEntry, L"%s ", s_CandList.awszCandidate[i] );
  6767.                                 // If this is the selected entry, mark its char position.
  6768.                                 if( s_CandList.dwSelection == i )
  6769.                                 {
  6770.                                     s_CandList.nFirstSelected = lstrlen( wszCand );
  6771.                                     s_CandList.nHoriSelectedLen = lstrlen( wszEntry ) - 1;  // Minus space
  6772.                                 }
  6773.                                 lstrcat( wszCand, wszEntry );
  6774.                             }
  6775.                             wszCand[lstrlen(wszCand) - 1] = L'\0';  // Remove the last space
  6776.                             s_CandList.HoriCand.SetText( wszCand );
  6777.                         }
  6778.                     }
  6779.                     break;
  6780.                 }
  6781.  
  6782.                 case IMN_CLOSECANDIDATE:
  6783.                 {
  6784.                     DXUTTRACE( L"  IMN_CLOSECANDIDATE\n" );
  6785.                     s_CandList.bShowWindow = false;
  6786.                     if( !s_bShowReadingWindow )
  6787.                     {
  6788.                         s_CandList.dwCount = 0;
  6789.                         ZeroMemory( s_CandList.awszCandidate, sizeof(s_CandList.awszCandidate) );
  6790.                     }
  6791.                     *trapped = true;
  6792.                     break;
  6793.                 }
  6794.  
  6795.                 case IMN_PRIVATE:
  6796.                     DXUTTRACE( L"  IMN_PRIVATE\n" );
  6797.                     {
  6798.                         if( !s_CandList.bShowWindow )
  6799.                             GetPrivateReadingString();
  6800.  
  6801.                         // Trap some messages to hide reading window
  6802.                         DWORD dwId = GetImeId();
  6803.                         switch( dwId )
  6804.                         {
  6805.                             case IMEID_CHT_VER42:
  6806.                             case IMEID_CHT_VER43:
  6807.                             case IMEID_CHT_VER44:
  6808.                             case IMEID_CHS_VER41:
  6809.                             case IMEID_CHS_VER42:
  6810.                                 if( ( lParam == 1 ) || ( lParam == 2 ) )
  6811.                                 {
  6812.                                     *trapped = true;
  6813.                                 }
  6814.                                 break;
  6815.  
  6816.                             case IMEID_CHT_VER50:
  6817.                             case IMEID_CHT_VER51:
  6818.                             case IMEID_CHT_VER52:
  6819.                             case IMEID_CHT_VER60:
  6820.                             case IMEID_CHS_VER53:
  6821.                                 if( (lParam == 16) || (lParam == 17) || (lParam == 26) || (lParam == 27) || (lParam == 28) )
  6822.                                 {
  6823.                                     *trapped = true;
  6824.                                 }
  6825.                                 break;
  6826.                         }
  6827.                     }
  6828.                     break;
  6829.  
  6830.                 default:
  6831.                     *trapped = true;
  6832.                     break;
  6833.             }
  6834.             break;
  6835.  
  6836.         // When Text Service Framework is installed in Win2K, Alt+Shift and Ctrl+Shift combination (to switch input
  6837.         // locale / keyboard layout) doesn't send WM_KEYUP message for the key that is released first. We need to check
  6838.         // if these keys are actually up whenever we receive key up message for other keys.
  6839.         case WM_KEYUP:
  6840.         case WM_SYSKEYUP:
  6841.             if ( !( lAlt & 0x80000000 ) && wParam != VK_MENU && ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) == 0 )
  6842.             {
  6843.                 PostMessageW( GetFocus(), WM_KEYUP, (WPARAM)VK_MENU, ( lAlt & 0x01ff0000 ) | 0xC0000001 );
  6844.             }   
  6845.             else if ( !( lCtrl & 0x80000000 ) && wParam != VK_CONTROL && ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) == 0 )
  6846.             {
  6847.                 PostMessageW( GetFocus(), WM_KEYUP, (WPARAM)VK_CONTROL, ( lCtrl & 0x01ff0000 ) | 0xC0000001 );
  6848.             }
  6849.             else if ( !( lShift & 0x80000000 ) && wParam != VK_SHIFT && ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) == 0 )
  6850.             {
  6851.                 PostMessageW( GetFocus(), WM_KEYUP, (WPARAM)VK_SHIFT, ( lShift & 0x01ff0000 ) | 0xC0000001 );
  6852.             }
  6853.             // fall through WM_KEYDOWN / WM_SYSKEYDOWN
  6854.         case WM_KEYDOWN:
  6855.         case WM_SYSKEYDOWN:
  6856.             switch ( wParam )
  6857.             {
  6858.                 case VK_MENU:
  6859.                     lAlt = lParam;
  6860.                     break;
  6861.                 case VK_SHIFT:
  6862.                     lShift = lParam;
  6863.                     break;
  6864.                 case VK_CONTROL:
  6865.                     lCtrl = lParam;
  6866.                     break;
  6867.             }
  6868.             //break;
  6869.             // Fall through to default case
  6870.             // so we invoke the parent.
  6871.  
  6872.         default:
  6873.             // Let the parent handle the message that we
  6874.             // don't handle.
  6875.             return CDXUTEditBox::MsgProc( uMsg, wParam, lParam );
  6876.  
  6877.     }  // switch
  6878.  
  6879.     return *trapped;
  6880. }
  6881.  
  6882.  
  6883. //--------------------------------------------------------------------------------------
  6884. void CDXUTIMEEditBox::RenderCandidateReadingWindow( IDirect3DDevice9* pd3dDevice, float fElapsedTime, bool bReading )
  6885. {
  6886.     RECT rc;
  6887.     UINT nNumEntries = bReading ? 4 : MAX_CANDLIST;
  6888.     D3DCOLOR TextColor, TextBkColor, SelTextColor, SelBkColor;
  6889.     int nX, nXFirst, nXComp;
  6890.     m_Buffer.CPtoX( m_nCaret, FALSE, &nX );
  6891.     m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nXFirst );
  6892.  
  6893.     if( bReading )
  6894.     {
  6895.         TextColor = m_ReadingColor;
  6896.         TextBkColor = m_ReadingWinColor;
  6897.         SelTextColor = m_ReadingSelColor;
  6898.         SelBkColor = m_ReadingSelBkColor;
  6899.     } else
  6900.     {
  6901.         TextColor = m_CandidateColor;
  6902.         TextBkColor = m_CandidateWinColor;
  6903.         SelTextColor = m_CandidateSelColor;
  6904.         SelBkColor = m_CandidateSelBkColor;
  6905.     }
  6906.  
  6907.     // For Japanese IME, align the window with the first target converted character.
  6908.     // For all other IMEs, align with the caret.  This is because the caret
  6909.     // does not move for Japanese IME.
  6910.     if ( GetLanguage() == LANG_CHT && !GetImeId() )
  6911.         nXComp = 0;
  6912.     else
  6913.     if( GetPrimaryLanguage() == LANG_JAPANESE )
  6914.         s_CompString.CPtoX( s_nFirstTargetConv, FALSE, &nXComp );
  6915.     else
  6916.         s_CompString.CPtoX( s_nCompCaret, FALSE, &nXComp );
  6917.  
  6918.     // Compute the size of the candidate window
  6919.     int nWidthRequired = 0;
  6920.     int nHeightRequired = 0;
  6921.     int nSingleLineHeight = 0;
  6922.  
  6923.     if( ( s_bVerticalCand && !bReading ) ||
  6924.         ( !s_bHorizontalReading && bReading ) )
  6925.     {
  6926.         // Vertical window
  6927.         for( UINT i = 0; i < nNumEntries; ++i )
  6928.         {
  6929.             if( s_CandList.awszCandidate[i][0] == L'\0' )
  6930.                 break;
  6931.             SetRect( &rc, 0, 0, 0, 0 );
  6932.             m_pDialog->CalcTextRect( s_CandList.awszCandidate[i], m_Elements.GetAt( 1 ), &rc );
  6933.             nWidthRequired = max( nWidthRequired, rc.right - rc.left );
  6934.             nSingleLineHeight = max( nSingleLineHeight, rc.bottom - rc.top );
  6935.         }
  6936.         nHeightRequired = nSingleLineHeight * nNumEntries;
  6937.     } else
  6938.     {
  6939.         // Horizontal window
  6940.         SetRect( &rc, 0, 0, 0, 0 );
  6941.         if( bReading )
  6942.             m_pDialog->CalcTextRect( s_wszReadingString, m_Elements.GetAt( 1 ), &rc );
  6943.         else
  6944.             m_pDialog->CalcTextRect( s_CandList.HoriCand.GetBuffer(), m_Elements.GetAt( 1 ), &rc );
  6945.         nWidthRequired = rc.right - rc.left;
  6946.         nSingleLineHeight = nHeightRequired = rc.bottom - rc.top;
  6947.     }
  6948.  
  6949.     // Now that we have the dimension, calculate the location for the candidate window.
  6950.     // We attempt to fit the window in this order:
  6951.     // bottom, top, right, left.
  6952.  
  6953.     bool bHasPosition = false;
  6954.  
  6955.     // Bottom
  6956.     SetRect( &rc, s_ptCompString.x + nXComp, s_ptCompString.y + m_rcText.bottom - m_rcText.top,
  6957.                   s_ptCompString.x + nXComp + nWidthRequired, s_ptCompString.y + m_rcText.bottom - m_rcText.top + nHeightRequired );
  6958.     // if the right edge is cut off, move it left.
  6959.     if( rc.right > m_pDialog->GetWidth() )
  6960.     {
  6961.         rc.left -= rc.right - m_pDialog->GetWidth();
  6962.         rc.right = m_pDialog->GetWidth();
  6963.     }
  6964.     if( rc.bottom <= m_pDialog->GetHeight() )
  6965.         bHasPosition = true;
  6966.  
  6967.     // Top
  6968.     if( !bHasPosition )
  6969.     {
  6970.         SetRect( &rc, s_ptCompString.x + nXComp, s_ptCompString.y - nHeightRequired,
  6971.                       s_ptCompString.x + nXComp + nWidthRequired, s_ptCompString.y );
  6972.         // if the right edge is cut off, move it left.
  6973.         if( rc.right > m_pDialog->GetWidth() )
  6974.         {
  6975.             rc.left -= rc.right - m_pDialog->GetWidth();
  6976.             rc.right = m_pDialog->GetWidth();
  6977.         }
  6978.         if( rc.top >= 0 )
  6979.             bHasPosition = true;
  6980.     }
  6981.  
  6982.     // Right
  6983.     if( !bHasPosition )
  6984.     {
  6985.         int nXCompTrail;
  6986.         s_CompString.CPtoX( s_nCompCaret, TRUE, &nXCompTrail );
  6987.         SetRect( &rc, s_ptCompString.x + nXCompTrail, 0,
  6988.                       s_ptCompString.x + nXCompTrail + nWidthRequired, nHeightRequired );
  6989.         if( rc.right <= m_pDialog->GetWidth() )
  6990.             bHasPosition = true;
  6991.     }
  6992.  
  6993.     // Left
  6994.     if( !bHasPosition )
  6995.     {
  6996.         SetRect( &rc, s_ptCompString.x + nXComp - nWidthRequired, 0,
  6997.                       s_ptCompString.x + nXComp, nHeightRequired );
  6998.         if( rc.right >= 0 )
  6999.             bHasPosition = true;
  7000.     }
  7001.  
  7002.     if( !bHasPosition )
  7003.     {
  7004.         // The dialog is too small for the candidate window.
  7005.         // Fall back to render at 0, 0.  Some part of the window
  7006.         // will be cut off.
  7007.         rc.left = 0;
  7008.         rc.right = nWidthRequired;
  7009.     }
  7010.  
  7011.     // If we are rendering the candidate window, save the position
  7012.     // so that mouse clicks are checked properly.
  7013.     if( !bReading )
  7014.         s_CandList.rcCandidate = rc;
  7015.  
  7016.     // Render the elements
  7017.     m_pDialog->DrawRect( &rc, TextBkColor );
  7018.     if( ( s_bVerticalCand && !bReading ) ||
  7019.         ( !s_bHorizontalReading && bReading ) )
  7020.     {
  7021.         // Vertical candidate window
  7022.         for( UINT i = 0; i < nNumEntries; ++i )
  7023.         {
  7024.             // Here we are rendering one line at a time
  7025.             rc.bottom = rc.top + nSingleLineHeight;
  7026.             // Use a different color for the selected string
  7027.             if( s_CandList.dwSelection == i )
  7028.             {
  7029.                 m_pDialog->DrawRect( &rc, SelBkColor );
  7030.                 m_Elements.GetAt( 1 )->FontColor.Current = SelTextColor;
  7031.             } else
  7032.                 m_Elements.GetAt( 1 )->FontColor.Current = TextColor;
  7033.  
  7034.             m_pDialog->DrawText( s_CandList.awszCandidate[i], m_Elements.GetAt( 1 ), &rc );
  7035.  
  7036.             rc.top += nSingleLineHeight;
  7037.         }
  7038.     } else
  7039.     {
  7040.         // Horizontal candidate window
  7041.         m_Elements.GetAt( 1 )->FontColor.Current = TextColor;
  7042.         if( bReading )
  7043.             m_pDialog->DrawText( s_wszReadingString, m_Elements.GetAt( 1 ), &rc );
  7044.         else
  7045.             m_pDialog->DrawText( s_CandList.HoriCand.GetBuffer(), m_Elements.GetAt( 1 ), &rc );
  7046.  
  7047.         // Render the selected entry differently
  7048.         if( !bReading )
  7049.         {
  7050.             int nXLeft, nXRight;
  7051.             s_CandList.HoriCand.CPtoX( s_CandList.nFirstSelected, FALSE, &nXLeft );
  7052.             s_CandList.HoriCand.CPtoX( s_CandList.nFirstSelected + s_CandList.nHoriSelectedLen, FALSE, &nXRight );
  7053.  
  7054.             rc.right = rc.left + nXRight;
  7055.             rc.left += nXLeft;
  7056.             m_pDialog->DrawRect( &rc, SelBkColor );
  7057.             m_Elements.GetAt( 1 )->FontColor.Current = SelTextColor;
  7058.             m_pDialog->DrawText( s_CandList.HoriCand.GetBuffer() + s_CandList.nFirstSelected,
  7059.                                 m_Elements.GetAt( 1 ), &rc, false, s_CandList.nHoriSelectedLen );
  7060.         }
  7061.     }
  7062. }
  7063.  
  7064.  
  7065. //--------------------------------------------------------------------------------------
  7066. void CDXUTIMEEditBox::RenderComposition( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  7067. {
  7068.     RECT rcCaret = { 0, 0, 0, 0 };
  7069.     int nX, nXFirst;
  7070.     m_Buffer.CPtoX( m_nCaret, FALSE, &nX );
  7071.     m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nXFirst );
  7072.     CDXUTElement *pElement = m_Elements.GetAt( 1 );
  7073.  
  7074.     // Get the required width
  7075.     RECT rc = { m_rcText.left + nX - nXFirst, m_rcText.top,
  7076.                 m_rcText.left + nX - nXFirst, m_rcText.bottom };
  7077.     m_pDialog->CalcTextRect( s_CompString.GetBuffer(), pElement, &rc );
  7078.  
  7079.     // If the composition string is too long to fit within
  7080.     // the text area, move it to below the current line.
  7081.     // This matches the behavior of the default IME.
  7082.     if( rc.right > m_rcText.right )
  7083.         OffsetRect( &rc, m_rcText.left - rc.left, rc.bottom - rc.top );
  7084.  
  7085.     // Save the rectangle position for processing highlighted text.
  7086.     RECT rcFirst = rc;
  7087.  
  7088.     // Update s_ptCompString for RenderCandidateReadingWindow().
  7089.     s_ptCompString.x = rc.left; s_ptCompString.y = rc.top;
  7090.  
  7091.     D3DCOLOR TextColor = m_CompColor;
  7092.     // Render the window and string.
  7093.     // If the string is too long, we must wrap the line.
  7094.     pElement->FontColor.Current = TextColor;
  7095.     const WCHAR *pwszComp = s_CompString.GetBuffer();
  7096.     int nCharLeft = s_CompString.GetTextSize();
  7097.     for( ; ; )
  7098.     {
  7099.         // Find the last character that can be drawn on the same line.
  7100.         int nLastInLine;
  7101.         int bTrail;
  7102.         s_CompString.XtoCP( m_rcText.right - rc.left, &nLastInLine, &bTrail );
  7103.         int nNumCharToDraw = min( nCharLeft, nLastInLine );
  7104.         m_pDialog->CalcTextRect( pwszComp, pElement, &rc, nNumCharToDraw );
  7105.  
  7106.         // Draw the background
  7107.         // For Korean IME, blink the composition window background as if it
  7108.         // is a cursor.
  7109.         if( GetPrimaryLanguage() == LANG_KOREAN )
  7110.         {
  7111.             if( m_bCaretOn )
  7112.             {
  7113.                 m_pDialog->DrawRect( &rc, m_CompWinColor );
  7114.             }
  7115.             else
  7116.             {
  7117.                 // Not drawing composition string background. We
  7118.                 // use the editbox's text color for composition
  7119.                 // string text.
  7120.                 TextColor = m_Elements.GetAt(0)->FontColor.States[DXUT_STATE_NORMAL];
  7121.             }
  7122.         } else
  7123.         {
  7124.             // Non-Korean IME. Always draw composition background.
  7125.             m_pDialog->DrawRect( &rc, m_CompWinColor );
  7126.         }
  7127.  
  7128.         // Draw the text
  7129.         pElement->FontColor.Current = TextColor;
  7130.         m_pDialog->DrawText( pwszComp, pElement, &rc, false, nNumCharToDraw );
  7131.  
  7132.         // Advance pointer and counter
  7133.         nCharLeft -= nNumCharToDraw;
  7134.         pwszComp += nNumCharToDraw;
  7135.         if( nCharLeft <= 0 )
  7136.             break;
  7137.  
  7138.         // Advance rectangle coordinates to beginning of next line
  7139.         OffsetRect( &rc, m_rcText.left - rc.left, rc.bottom - rc.top );
  7140.     }
  7141.  
  7142.     // Load the rect for the first line again.
  7143.     rc = rcFirst;
  7144.  
  7145.     // Inspect each character in the comp string.
  7146.     // For target-converted and target-non-converted characters,
  7147.     // we display a different background color so they appear highlighted.
  7148.     int nCharFirst = 0;
  7149.     nXFirst = 0;
  7150.     s_nFirstTargetConv = -1;
  7151.     BYTE *pAttr;
  7152.     const WCHAR *pcComp;
  7153.     for( pcComp = s_CompString.GetBuffer(), pAttr = s_abCompStringAttr;
  7154.           *pcComp != L'\0'; ++pcComp, ++pAttr )
  7155.     {
  7156.         D3DCOLOR bkColor;
  7157.  
  7158.         // Render a different background for this character
  7159.         int nXLeft, nXRight;
  7160.         s_CompString.CPtoX( int(pcComp - s_CompString.GetBuffer()), FALSE, &nXLeft );
  7161.         s_CompString.CPtoX( int(pcComp - s_CompString.GetBuffer()), TRUE, &nXRight );
  7162.  
  7163.         // Check if this character is off the right edge and should
  7164.         // be wrapped to the next line.
  7165.         if( nXRight - nXFirst > m_rcText.right - rc.left )
  7166.         {
  7167.             // Advance rectangle coordinates to beginning of next line
  7168.             OffsetRect( &rc, m_rcText.left - rc.left, rc.bottom - rc.top );
  7169.  
  7170.             // Update the line's first character information
  7171.             nCharFirst = int(pcComp - s_CompString.GetBuffer());
  7172.             s_CompString.CPtoX( nCharFirst, FALSE, &nXFirst );
  7173.         }
  7174.  
  7175.         // If the caret is on this character, save the coordinates
  7176.         // for drawing the caret later.
  7177.         if( s_nCompCaret == int(pcComp - s_CompString.GetBuffer()) )
  7178.         {
  7179.             rcCaret = rc;
  7180.             rcCaret.left += nXLeft - nXFirst - 1;
  7181.             rcCaret.right = rcCaret.left + 2;
  7182.         }
  7183.  
  7184.         // Set up color based on the character attribute
  7185.         if( *pAttr == ATTR_TARGET_CONVERTED )
  7186.         {
  7187.             pElement->FontColor.Current = m_CompTargetColor;
  7188.             bkColor = m_CompTargetBkColor;
  7189.         }
  7190.         else
  7191.         if( *pAttr == ATTR_TARGET_NOTCONVERTED )
  7192.         {
  7193.             pElement->FontColor.Current = m_CompTargetNonColor;
  7194.             bkColor = m_CompTargetNonBkColor;
  7195.         }
  7196.         else
  7197.         {
  7198.             continue;
  7199.         }
  7200.  
  7201.         RECT rcTarget = { rc.left + nXLeft - nXFirst, rc.top, rc.left + nXRight - nXFirst, rc.bottom };
  7202.         m_pDialog->DrawRect( &rcTarget, bkColor );
  7203.         m_pDialog->DrawText( pcComp, pElement, &rcTarget, false, 1 );
  7204.  
  7205.         // Record the first target converted character's index
  7206.         if( -1 == s_nFirstTargetConv )
  7207.             s_nFirstTargetConv = int(pAttr - s_abCompStringAttr);
  7208.     }
  7209.  
  7210.     // Render the composition caret
  7211.     if( m_bCaretOn )
  7212.     {
  7213.         // If the caret is at the very end, its position would not have
  7214.         // been computed in the above loop.  We compute it here.
  7215.         if( s_nCompCaret == s_CompString.GetTextSize() )
  7216.         {
  7217.             s_CompString.CPtoX( s_nCompCaret, FALSE, &nX );
  7218.             rcCaret = rc;
  7219.             rcCaret.left += nX - nXFirst - 1;
  7220.             rcCaret.right = rcCaret.left + 2;
  7221.         }
  7222.  
  7223.         m_pDialog->DrawRect( &rcCaret, m_CompCaretColor );
  7224.     }
  7225. }
  7226.  
  7227.  
  7228. //--------------------------------------------------------------------------------------
  7229. void CDXUTIMEEditBox::RenderIndicator( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  7230. {
  7231.     CDXUTElement *pElement = m_Elements.GetAt( 9 );
  7232.     pElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  7233.  
  7234.     m_pDialog->DrawSprite( pElement, &m_rcIndicator );
  7235.     RECT rc = m_rcIndicator;
  7236.     InflateRect( &rc, -m_nSpacing, -m_nSpacing );
  7237.     pElement->FontColor.Current = s_ImeState == IMEUI_STATE_ON && s_bEnableImeSystem ? m_IndicatorImeColor : m_IndicatorEngColor;
  7238.     RECT rcCalc = { 0, 0, 0, 0 };
  7239.     // If IME system is off, draw English indicator.
  7240.     WCHAR *pwszIndicator = s_bEnableImeSystem ? s_wszCurrIndicator : s_aszIndicator[0];
  7241.  
  7242.     m_pDialog->CalcTextRect( pwszIndicator, pElement, &rcCalc );
  7243.     m_pDialog->DrawText( pwszIndicator, pElement, &rc );
  7244. }
  7245.  
  7246.  
  7247. //--------------------------------------------------------------------------------------
  7248. void CDXUTIMEEditBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  7249. {
  7250.     if( m_bVisible == false )
  7251.         return;
  7252.  
  7253.     // If we have not computed the indicator symbol width,
  7254.     // do it.
  7255.     if( !m_nIndicatorWidth )
  7256.     {
  7257.         for( int i = 0; i < 5; ++i )
  7258.         {
  7259.             RECT rc = { 0, 0, 0, 0 };
  7260.             m_pDialog->CalcTextRect( s_aszIndicator[i], m_Elements.GetAt( 9 ), &rc );
  7261.             m_nIndicatorWidth = max( m_nIndicatorWidth, rc.right - rc.left );
  7262.         }
  7263.         // Update the rectangles now that we have the indicator's width
  7264.         UpdateRects();
  7265.     }
  7266.  
  7267.     // Let the parent render first (edit control)
  7268.     CDXUTEditBox::Render( pd3dDevice, fElapsedTime );
  7269.  
  7270.     CDXUTElement* pElement = GetElement( 1 );
  7271.     if( pElement )
  7272.     {
  7273.         s_CompString.SetFontIndex( pElement->iFont );
  7274.         s_CandList.HoriCand.SetFontIndex( pElement->iFont );
  7275.     }
  7276.  
  7277.     //
  7278.     // Now render the IME elements
  7279.     //
  7280.     if( m_bHasFocus )
  7281.     {
  7282.         // Render the input locale indicator
  7283.         RenderIndicator( pd3dDevice, fElapsedTime );
  7284.  
  7285.         // Display the composition string.
  7286.         // This method should also update s_ptCompString
  7287.         // for RenderCandidateReadingWindow.
  7288.         RenderComposition( pd3dDevice, fElapsedTime );
  7289.  
  7290.         // Display the reading/candidate window. RenderCandidateReadingWindow()
  7291.         // uses s_ptCompString to position itself.  s_ptCompString must have
  7292.         // been filled in by RenderComposition().
  7293.         if( s_bShowReadingWindow )
  7294.             // Reading window
  7295.             RenderCandidateReadingWindow( pd3dDevice, fElapsedTime, true );
  7296.         else
  7297.         if( s_CandList.bShowWindow )
  7298.             // Candidate list window
  7299.             RenderCandidateReadingWindow( pd3dDevice, fElapsedTime, false );
  7300.     }
  7301. }
  7302.  
  7303.  
  7304. //--------------------------------------------------------------------------------------
  7305. void CDXUTEditBox::CUniBuffer::InitializeUniscribe()
  7306. {
  7307.     WCHAR wszPath[MAX_PATH+1];
  7308.     if( !::GetSystemDirectory( wszPath, MAX_PATH+1 ) )
  7309.         return;
  7310.  
  7311.     // Verify whether it is safe to concatenate these strings
  7312.     int len1 = lstrlen(wszPath);
  7313.     int len2 = lstrlen(UNISCRIBE_DLLNAME);
  7314.     if (len1 + len2 > MAX_PATH)
  7315.     {
  7316.         return;
  7317.     }
  7318.  
  7319.     // We have verified that the concatenated string will fit into wszPath,
  7320.     // so it is safe to concatenate them.
  7321.     lstrcatW( wszPath, UNISCRIBE_DLLNAME );
  7322.  
  7323.     s_hDll = LoadLibrary( wszPath );
  7324.     if( s_hDll )
  7325.     {
  7326.         FARPROC Temp;
  7327.         GETPROCADDRESS( s_hDll, ScriptApplyDigitSubstitution, Temp );
  7328.         GETPROCADDRESS( s_hDll, ScriptStringAnalyse, Temp );
  7329.         GETPROCADDRESS( s_hDll, ScriptStringCPtoX, Temp );
  7330.         GETPROCADDRESS( s_hDll, ScriptStringXtoCP, Temp );
  7331.         GETPROCADDRESS( s_hDll, ScriptStringFree, Temp );
  7332.         GETPROCADDRESS( s_hDll, ScriptString_pLogAttr, Temp );
  7333.         GETPROCADDRESS( s_hDll, ScriptString_pcOutChars, Temp );
  7334.     }
  7335. }
  7336.  
  7337.  
  7338. //--------------------------------------------------------------------------------------
  7339. void CDXUTEditBox::CUniBuffer::UninitializeUniscribe()
  7340. {
  7341.     if( s_hDll )
  7342.     {
  7343.         PLACEHOLDERPROC( ScriptApplyDigitSubstitution );
  7344.         PLACEHOLDERPROC( ScriptStringAnalyse );
  7345.         PLACEHOLDERPROC( ScriptStringCPtoX );
  7346.         PLACEHOLDERPROC( ScriptStringXtoCP );
  7347.         PLACEHOLDERPROC( ScriptStringFree );
  7348.         PLACEHOLDERPROC( ScriptString_pLogAttr );
  7349.         PLACEHOLDERPROC( ScriptString_pcOutChars );
  7350.  
  7351.         FreeLibrary( s_hDll );
  7352.         s_hDll = NULL;
  7353.     }
  7354. }
  7355.  
  7356.  
  7357. //--------------------------------------------------------------------------------------
  7358. bool CDXUTEditBox::CUniBuffer::Grow( int nNewSize )
  7359. {
  7360.     // If the current size is already the maximum allowed,
  7361.     // we can't possibly allocate more.
  7362.     if( m_nBufferSize == DXUT_MAX_EDITBOXLENGTH )
  7363.         return false;
  7364.  
  7365.     int nAllocateSize = ( nNewSize == -1 || nNewSize < m_nBufferSize * 2 ) ? ( m_nBufferSize ? m_nBufferSize * 2 : 256 ) : nNewSize * 2;
  7366.  
  7367.     // Cap the buffer size at the maximum allowed.
  7368.     if( nAllocateSize > DXUT_MAX_EDITBOXLENGTH )
  7369.         nAllocateSize = DXUT_MAX_EDITBOXLENGTH;
  7370.  
  7371.     WCHAR *pTempBuffer = new WCHAR[nAllocateSize];
  7372.     if( !pTempBuffer )
  7373.         return false;
  7374.     if( m_pwszBuffer )
  7375.         CopyMemory( pTempBuffer, m_pwszBuffer, (m_nTextSize + 1) * sizeof(WCHAR) );
  7376.     delete[] m_pwszBuffer;
  7377.     m_pwszBuffer = pTempBuffer;
  7378.     m_nBufferSize = nAllocateSize;
  7379.     return true;
  7380. }
  7381.  
  7382.  
  7383. //--------------------------------------------------------------------------------------
  7384. // Uniscribe -- Analyse() analyses the string in the buffer
  7385. //--------------------------------------------------------------------------------------
  7386. HRESULT CDXUTEditBox::CUniBuffer::Analyse()
  7387. {
  7388.     if( m_Analysis )
  7389.         _ScriptStringFree( &m_Analysis );
  7390.  
  7391.     SCRIPT_CONTROL ScriptControl; // For uniscribe
  7392.     SCRIPT_STATE   ScriptState;   // For uniscribe
  7393.     ZeroMemory( &ScriptControl, sizeof(ScriptControl) );
  7394.     ZeroMemory( &ScriptState, sizeof(ScriptState) );
  7395.     _ScriptApplyDigitSubstitution ( NULL, &ScriptControl, &ScriptState );
  7396.  
  7397.     DXUTFontNode* pFontNode = DXUTGetGlobalDialogResourceManager()->GetFontNode( m_iFont );
  7398.  
  7399.     HRESULT hr = _ScriptStringAnalyse( pFontNode->pFont ? pFontNode->pFont->GetDC() : NULL,
  7400.                                        m_pwszBuffer,
  7401.                                        m_nTextSize + 1,  // NULL is also analyzed.
  7402.                                        m_nTextSize * 3 / 2 + 16,
  7403.                                        -1,
  7404.                                        SSA_BREAK | SSA_GLYPHS | SSA_FALLBACK | SSA_LINK,
  7405.                                        0,
  7406.                                        &ScriptControl,
  7407.                                        &ScriptState,
  7408.                                        NULL,
  7409.                                        NULL,
  7410.                                        NULL,
  7411.                                        &m_Analysis );
  7412.     if( SUCCEEDED( hr ) )
  7413.         m_bAnalyseRequired = false;  // Analysis is up-to-date
  7414.     return hr;
  7415. }
  7416.  
  7417.  
  7418. //--------------------------------------------------------------------------------------
  7419. CDXUTEditBox::CUniBuffer::CUniBuffer( int nInitialSize )
  7420. {
  7421.     m_pwszBuffer = new WCHAR[nInitialSize];
  7422.     *m_pwszBuffer = 0;
  7423.     m_nBufferSize = nInitialSize;
  7424.     m_nTextSize = 0;
  7425.     m_bAnalyseRequired = true;
  7426.     m_Analysis = NULL;
  7427.     m_iFont = 0;
  7428. }
  7429.  
  7430.  
  7431. //--------------------------------------------------------------------------------------
  7432. CDXUTEditBox::CUniBuffer::~CUniBuffer()
  7433. {
  7434.     delete[] m_pwszBuffer;
  7435.     if( m_Analysis )
  7436.         _ScriptStringFree( &m_Analysis );
  7437. }
  7438.  
  7439.  
  7440. //--------------------------------------------------------------------------------------
  7441. bool CDXUTEditBox::CUniBuffer::SetBufferSize( int nSize )
  7442. {
  7443.     while( m_nBufferSize < nSize )
  7444.     {
  7445.         if( !Grow() )
  7446.             return false;
  7447.     }
  7448.     return true;
  7449. }
  7450.  
  7451.  
  7452. //--------------------------------------------------------------------------------------
  7453. WCHAR& CDXUTEditBox::CUniBuffer::operator[]( int n )  // No param checking
  7454. {
  7455.     // This version of operator[] is called only
  7456.     // if we are asking for write access, so
  7457.     // re-analysis is required.
  7458.     m_bAnalyseRequired = true;
  7459.     return m_pwszBuffer[n];
  7460. }
  7461.  
  7462.  
  7463. //--------------------------------------------------------------------------------------
  7464. void CDXUTEditBox::CUniBuffer::Clear()
  7465. {
  7466.     *m_pwszBuffer = L'\0';
  7467.     m_nTextSize = 0;
  7468.     m_bAnalyseRequired = true;
  7469. }
  7470.  
  7471.  
  7472. //--------------------------------------------------------------------------------------
  7473. // Inserts the char at specified index.
  7474. // If nIndex == -1, insert to the end.
  7475. //--------------------------------------------------------------------------------------
  7476. bool CDXUTEditBox::CUniBuffer::InsertChar( int nIndex, WCHAR wChar )
  7477. {
  7478.     assert( nIndex >= 0 );
  7479.  
  7480.     if( nIndex > m_nTextSize )
  7481.         return false;  // invalid index
  7482.  
  7483.     // Check for maximum length allowed
  7484.     if( GetTextSize() + 1 >= DXUT_MAX_EDITBOXLENGTH )
  7485.         return false;
  7486.  
  7487.     if( m_nTextSize + 1 >= m_nBufferSize )
  7488.     {
  7489.         if( !Grow() )
  7490.             return false;  // out of memory
  7491.     }
  7492.  
  7493.     MoveMemory( m_pwszBuffer + nIndex + 1, m_pwszBuffer + nIndex, sizeof(WCHAR) * ( m_nTextSize - nIndex + 1 ) );
  7494.     m_pwszBuffer[ nIndex ] = wChar;
  7495.     ++m_nTextSize;
  7496.     m_bAnalyseRequired = true;
  7497.  
  7498.     return true;
  7499. }
  7500.  
  7501.  
  7502. //--------------------------------------------------------------------------------------
  7503. // Removes the char at specified index.
  7504. // If nIndex == -1, remove the last char.
  7505. //--------------------------------------------------------------------------------------
  7506. bool CDXUTEditBox::CUniBuffer::RemoveChar( int nIndex )
  7507. {
  7508.     if( !m_nTextSize || nIndex < 0 || nIndex >= m_nTextSize )
  7509.         return false;  // Invalid index
  7510.  
  7511.     MoveMemory( m_pwszBuffer + nIndex, m_pwszBuffer + nIndex + 1, sizeof(WCHAR) * ( m_nTextSize - nIndex ) );
  7512.     --m_nTextSize;
  7513.     m_bAnalyseRequired = true;
  7514.     return true;
  7515. }
  7516.  
  7517.  
  7518. //--------------------------------------------------------------------------------------
  7519. // Inserts the first nCount characters of the string pStr at specified index.
  7520. // If nCount == -1, the entire string is inserted.
  7521. // If nIndex == -1, insert to the end.
  7522. //--------------------------------------------------------------------------------------
  7523. bool CDXUTEditBox::CUniBuffer::InsertString( int nIndex, const WCHAR *pStr, int nCount )
  7524. {
  7525.     assert( nIndex >= 0 );
  7526.  
  7527.     if( nIndex > m_nTextSize )
  7528.         return false;  // invalid index
  7529.  
  7530.     if( -1 == nCount )
  7531.         nCount = lstrlenW( pStr );
  7532.  
  7533.     // Check for maximum length allowed
  7534.     if( GetTextSize() + nCount >= DXUT_MAX_EDITBOXLENGTH )
  7535.         return false;
  7536.  
  7537.     if( m_nTextSize + nCount >= m_nBufferSize )
  7538.     {
  7539.         if( !Grow( m_nTextSize + nCount + 1 ) )
  7540.             return false;  // out of memory
  7541.     }
  7542.  
  7543.     MoveMemory( m_pwszBuffer + nIndex + nCount, m_pwszBuffer + nIndex, sizeof(WCHAR) * ( m_nTextSize - nIndex + 1 ) );
  7544.     CopyMemory( m_pwszBuffer + nIndex, pStr, nCount * sizeof(WCHAR) );
  7545.     m_nTextSize += nCount;
  7546.     m_bAnalyseRequired = true;
  7547.  
  7548.     return true;
  7549. }
  7550.  
  7551.  
  7552. //--------------------------------------------------------------------------------------
  7553. bool CDXUTEditBox::CUniBuffer::SetText( LPCWSTR wszText )
  7554. {
  7555.     assert( wszText != NULL );
  7556.  
  7557.     int nRequired = int(wcslen( wszText ) + 1);
  7558.  
  7559.     // Check for maximum length allowed
  7560.     if( nRequired >= DXUT_MAX_EDITBOXLENGTH )
  7561.         return false;
  7562.  
  7563.     while( GetBufferSize() < nRequired )
  7564.         if( !Grow() )
  7565.                 break;
  7566.     // Check again in case out of memory occurred inside while loop.
  7567.     if( GetBufferSize() >= nRequired )
  7568.     {
  7569.         wcscpy( m_pwszBuffer, wszText );
  7570.         m_nTextSize = nRequired - 1;
  7571.         m_bAnalyseRequired = true;
  7572.         return true;
  7573.     }
  7574.     else
  7575.         return false;
  7576. }
  7577.  
  7578.  
  7579. //--------------------------------------------------------------------------------------
  7580. HRESULT CDXUTEditBox::CUniBuffer::CPtoX( int nCP, BOOL bTrail, int *pX )
  7581. {
  7582.     assert( pX );
  7583.     *pX = 0;  // Default
  7584.  
  7585.     HRESULT hr = S_OK;
  7586.     if( m_bAnalyseRequired )
  7587.         hr = Analyse();
  7588.  
  7589.     if( SUCCEEDED( hr ) )
  7590.         hr = _ScriptStringCPtoX( m_Analysis, nCP, bTrail, pX );
  7591.  
  7592.     return hr;
  7593. }
  7594.  
  7595.  
  7596. //--------------------------------------------------------------------------------------
  7597. HRESULT CDXUTEditBox::CUniBuffer::XtoCP( int nX, int *pCP, int *pnTrail )
  7598. {
  7599.     assert( pCP && pnTrail );
  7600.     *pCP = 0; *pnTrail = FALSE;  // Default
  7601.  
  7602.     HRESULT hr = S_OK;
  7603.     if( m_bAnalyseRequired )
  7604.         hr = Analyse();
  7605.  
  7606.     if( SUCCEEDED( hr ) )
  7607.         hr = _ScriptStringXtoCP( m_Analysis, nX, pCP, pnTrail );
  7608.  
  7609.     // If the coordinate falls outside the text region, we
  7610.     // can get character positions that don't exist.  We must
  7611.     // filter them here and convert them to those that do exist.
  7612.     if( *pCP == -1 && *pnTrail == TRUE )
  7613.     {
  7614.         *pCP = 0; *pnTrail = FALSE;
  7615.     } else
  7616.     if( *pCP > m_nTextSize && *pnTrail == FALSE )
  7617.     {
  7618.         *pCP = m_nTextSize; *pnTrail = TRUE;
  7619.     }
  7620.  
  7621.     return hr;
  7622. }
  7623.  
  7624.  
  7625. //--------------------------------------------------------------------------------------
  7626. void CDXUTEditBox::CUniBuffer::GetPriorItemPos( int nCP, int *pPrior )
  7627. {
  7628.     *pPrior = nCP;  // Default is the char itself
  7629.  
  7630.     if( m_bAnalyseRequired )
  7631.         if( FAILED( Analyse() ) )
  7632.             return;
  7633.  
  7634.     const SCRIPT_LOGATTR *pLogAttr = _ScriptString_pLogAttr( m_Analysis );
  7635.     if( !pLogAttr )
  7636.         return;
  7637.  
  7638.     if( !_ScriptString_pcOutChars( m_Analysis ) )
  7639.         return;
  7640.     int nInitial = *_ScriptString_pcOutChars( m_Analysis );
  7641.     if( nCP - 1 < nInitial )
  7642.         nInitial = nCP - 1;
  7643.     for( int i = nInitial; i > 0; --i )
  7644.         if( pLogAttr[i].fWordStop ||       // Either the fWordStop flag is set
  7645.             ( !pLogAttr[i].fWhiteSpace &&  // Or the previous char is whitespace but this isn't.
  7646.                 pLogAttr[i-1].fWhiteSpace ) )
  7647.         {
  7648.             *pPrior = i;
  7649.             return;
  7650.         }
  7651.     // We have reached index 0.  0 is always a break point, so simply return it.
  7652.     *pPrior = 0;
  7653. }
  7654.     
  7655.  
  7656. //--------------------------------------------------------------------------------------
  7657. void CDXUTEditBox::CUniBuffer::GetNextItemPos( int nCP, int *pPrior )
  7658. {
  7659.     *pPrior = nCP;  // Default is the char itself
  7660.  
  7661.     HRESULT hr = S_OK;
  7662.     if( m_bAnalyseRequired )
  7663.         hr = Analyse();
  7664.     if( FAILED( hr ) )
  7665.         return;
  7666.  
  7667.     const SCRIPT_LOGATTR *pLogAttr = _ScriptString_pLogAttr( m_Analysis );
  7668.     if( !pLogAttr )
  7669.         return;
  7670.  
  7671.     if( !_ScriptString_pcOutChars( m_Analysis ) )
  7672.         return;
  7673.     int nInitial = *_ScriptString_pcOutChars( m_Analysis );
  7674.     if( nCP + 1 < nInitial )
  7675.         nInitial = nCP + 1;
  7676.     for( int i = nInitial; i < *_ScriptString_pcOutChars( m_Analysis ) - 1; ++i )
  7677.     {
  7678.         if( pLogAttr[i].fWordStop )      // Either the fWordStop flag is set
  7679.         {
  7680.             *pPrior = i;
  7681.             return;
  7682.         }
  7683.         else
  7684.         if( pLogAttr[i].fWhiteSpace &&  // Or this whitespace but the next char isn't.
  7685.             !pLogAttr[i+1].fWhiteSpace )
  7686.         {
  7687.             *pPrior = i+1;  // The next char is a word stop
  7688.             return;
  7689.         }
  7690.     }
  7691.     // We have reached the end. It's always a word stop, so simply return it.
  7692.     *pPrior = *_ScriptString_pcOutChars( m_Analysis ) - 1;
  7693. }
  7694.  
  7695.  
  7696. //--------------------------------------------------------------------------------------
  7697. void CDXUTEditBox::ResetCaretBlink()
  7698. {
  7699.     m_bCaretOn = true;
  7700.     m_dfLastBlink = DXUTGetGlobalTimer()->GetAbsoluteTime();
  7701. }
  7702.  
  7703.  
  7704. //--------------------------------------------------------------------------------------
  7705. void CDXUTIMEEditBox::InitializeImm()
  7706. {
  7707.     FARPROC Temp;
  7708.  
  7709.     WCHAR wszPath[MAX_PATH+1];
  7710.     if( !::GetSystemDirectory( wszPath, MAX_PATH+1 ) )
  7711.         return;
  7712.     lstrcatW( wszPath, IMM32_DLLNAME );
  7713.     s_hDllImm32 = LoadLibrary( wszPath );
  7714.     if( s_hDllImm32 )
  7715.     {
  7716.         GETPROCADDRESS( s_hDllImm32, ImmLockIMC, Temp );
  7717.         GETPROCADDRESS( s_hDllImm32, ImmUnlockIMC, Temp );
  7718.         GETPROCADDRESS( s_hDllImm32, ImmLockIMCC, Temp );
  7719.         GETPROCADDRESS( s_hDllImm32, ImmUnlockIMCC, Temp );
  7720.         GETPROCADDRESS( s_hDllImm32, ImmDisableTextFrameService, Temp );
  7721.         GETPROCADDRESS( s_hDllImm32, ImmGetCompositionStringW, Temp );
  7722.         GETPROCADDRESS( s_hDllImm32, ImmGetCandidateListW, Temp );
  7723.         GETPROCADDRESS( s_hDllImm32, ImmGetContext, Temp );
  7724.         GETPROCADDRESS( s_hDllImm32, ImmReleaseContext, Temp );
  7725.         GETPROCADDRESS( s_hDllImm32, ImmAssociateContext, Temp );
  7726.         GETPROCADDRESS( s_hDllImm32, ImmGetOpenStatus, Temp );
  7727.         GETPROCADDRESS( s_hDllImm32, ImmSetOpenStatus, Temp );
  7728.         GETPROCADDRESS( s_hDllImm32, ImmGetConversionStatus, Temp );
  7729.         GETPROCADDRESS( s_hDllImm32, ImmGetDefaultIMEWnd, Temp );
  7730.         GETPROCADDRESS( s_hDllImm32, ImmGetIMEFileNameA, Temp );
  7731.         GETPROCADDRESS( s_hDllImm32, ImmGetVirtualKey, Temp );
  7732.         GETPROCADDRESS( s_hDllImm32, ImmNotifyIME, Temp );
  7733.         GETPROCADDRESS( s_hDllImm32, ImmSetConversionStatus, Temp );
  7734.         GETPROCADDRESS( s_hDllImm32, ImmSimulateHotKey, Temp );
  7735.         GETPROCADDRESS( s_hDllImm32, ImmIsIME, Temp );
  7736.     }
  7737.  
  7738.     if( !::GetSystemDirectory( wszPath, MAX_PATH+1 ) )
  7739.         return;
  7740.     lstrcatW( wszPath, VER_DLLNAME );
  7741.     s_hDllVer = LoadLibrary( wszPath );
  7742.     if( s_hDllVer )
  7743.     {
  7744.         GETPROCADDRESS( s_hDllVer, VerQueryValueA, Temp );
  7745.         GETPROCADDRESS( s_hDllVer, GetFileVersionInfoA, Temp );
  7746.         GETPROCADDRESS( s_hDllVer, GetFileVersionInfoSizeA, Temp );
  7747.     }
  7748. }
  7749.  
  7750.  
  7751. //--------------------------------------------------------------------------------------
  7752. void CDXUTIMEEditBox::UninitializeImm()
  7753. {
  7754.     if( s_hDllImm32 )
  7755.     {
  7756.         PLACEHOLDERPROC( ImmLockIMC );
  7757.         PLACEHOLDERPROC( ImmUnlockIMC );
  7758.         PLACEHOLDERPROC( ImmLockIMCC );
  7759.         PLACEHOLDERPROC( ImmUnlockIMCC );
  7760.         PLACEHOLDERPROC( ImmDisableTextFrameService );
  7761.         PLACEHOLDERPROC( ImmGetCompositionStringW );
  7762.         PLACEHOLDERPROC( ImmGetCandidateListW );
  7763.         PLACEHOLDERPROC( ImmGetContext );
  7764.         PLACEHOLDERPROC( ImmReleaseContext );
  7765.         PLACEHOLDERPROC( ImmAssociateContext );
  7766.         PLACEHOLDERPROC( ImmGetOpenStatus );
  7767.         PLACEHOLDERPROC( ImmSetOpenStatus );
  7768.         PLACEHOLDERPROC( ImmGetConversionStatus );
  7769.         PLACEHOLDERPROC( ImmGetDefaultIMEWnd );
  7770.         PLACEHOLDERPROC( ImmGetIMEFileNameA );
  7771.         PLACEHOLDERPROC( ImmGetVirtualKey );
  7772.         PLACEHOLDERPROC( ImmNotifyIME );
  7773.         PLACEHOLDERPROC( ImmSetConversionStatus );
  7774.         PLACEHOLDERPROC( ImmSimulateHotKey );
  7775.         PLACEHOLDERPROC( ImmIsIME );
  7776.  
  7777.         FreeLibrary( s_hDllImm32 );
  7778.         s_hDllImm32 = NULL;
  7779.     }
  7780.     if( s_hDllIme )
  7781.     {
  7782.         PLACEHOLDERPROC( GetReadingString );
  7783.         PLACEHOLDERPROC( ShowReadingWindow );
  7784.  
  7785.         FreeLibrary( s_hDllIme );
  7786.         s_hDllIme = NULL;
  7787.     }
  7788.     if( s_hDllVer )
  7789.     {
  7790.         PLACEHOLDERPROC( VerQueryValueA );
  7791.         PLACEHOLDERPROC( GetFileVersionInfoA );
  7792.         PLACEHOLDERPROC( GetFileVersionInfoSizeA );
  7793.  
  7794.         FreeLibrary( s_hDllVer );
  7795.         s_hDllVer = NULL;
  7796.     }
  7797. }
  7798.  
  7799.  
  7800. //--------------------------------------------------------------------------------------
  7801. void DXUTBlendColor::Init( D3DCOLOR defaultColor, D3DCOLOR disabledColor, D3DCOLOR hiddenColor )
  7802. {
  7803.     for( int i=0; i < MAX_CONTROL_STATES; i++ )
  7804.     {
  7805.         States[ i ] = defaultColor;
  7806.     }
  7807.  
  7808.     States[ DXUT_STATE_DISABLED ] = disabledColor;
  7809.     States[ DXUT_STATE_HIDDEN ] = hiddenColor;
  7810.     Current = hiddenColor;
  7811. }
  7812.  
  7813.  
  7814. //--------------------------------------------------------------------------------------
  7815. void DXUTBlendColor::Blend( UINT iState, float fElapsedTime, float fRate )
  7816. {
  7817.     D3DXCOLOR destColor = States[ iState ];
  7818.     D3DXColorLerp( &Current, &Current, &destColor, 1.0f - powf( fRate, 30 * fElapsedTime ) );
  7819. }
  7820.  
  7821.  
  7822.  
  7823. //--------------------------------------------------------------------------------------
  7824. void CDXUTElement::SetTexture( UINT iTexture, RECT* prcTexture, D3DCOLOR defaultTextureColor )
  7825. {
  7826.     this->iTexture = iTexture;
  7827.     
  7828.     if( prcTexture )
  7829.         rcTexture = *prcTexture;
  7830.     else
  7831.         SetRectEmpty( &rcTexture );
  7832.     
  7833.     TextureColor.Init( defaultTextureColor );
  7834. }
  7835.     
  7836.  
  7837. //--------------------------------------------------------------------------------------
  7838. void CDXUTElement::SetFont( UINT iFont, D3DCOLOR defaultFontColor, DWORD dwTextFormat )
  7839. {
  7840.     this->iFont = iFont;
  7841.     this->dwTextFormat = dwTextFormat;
  7842.  
  7843.     FontColor.Init( defaultFontColor );
  7844. }
  7845.  
  7846. //--------------------------------------------------------------------------------------
  7847. void CDXUTElement::Refresh()
  7848. {
  7849.     TextureColor.Current = TextureColor.States[ DXUT_STATE_HIDDEN ];
  7850.     FontColor.Current = FontColor.States[ DXUT_STATE_HIDDEN ];
  7851. }
  7852.  
  7853.  
  7854.  
  7855.  
  7856.  
  7857.  
  7858.  
  7859.