DXUTgui.cpp
上传用户:junlon
上传日期:2022-01-05
资源大小:39075k
文件大小:284k
源码类别:

DirextX编程

开发平台:

Visual C++

  1.     m_pDialog->DrawText( m_strText, pElement, &rcWindow );
  2. }
  3. //--------------------------------------------------------------------------------------
  4. // CDXUTCheckBox class
  5. //--------------------------------------------------------------------------------------
  6. //--------------------------------------------------------------------------------------
  7. CDXUTCheckBox::CDXUTCheckBox( CDXUTDialog *pDialog )
  8. {
  9.     m_Type = DXUT_CONTROL_CHECKBOX;
  10.     m_pDialog = pDialog;
  11.     m_bChecked = false;
  12. }
  13.     
  14. //--------------------------------------------------------------------------------------
  15. bool CDXUTCheckBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  16. {
  17.     if( !m_bEnabled || !m_bVisible )
  18.         return false;
  19.     switch( uMsg )
  20.     {
  21.         case WM_KEYDOWN:
  22.         {
  23.             switch( wParam )
  24.             {
  25.                 case VK_SPACE:
  26.                     m_bPressed = true;
  27.                     return true;
  28.             }
  29.         }
  30.         case WM_KEYUP:
  31.         {
  32.             switch( wParam )
  33.             {
  34.                 case VK_SPACE:
  35.                     if( m_bPressed == true )
  36.                     {
  37.                         m_bPressed = false;
  38.                         SetCheckedInternal( !m_bChecked, true );
  39.                     }
  40.                     return true;
  41.             }
  42.         }
  43.     }
  44.     return false;
  45. }
  46. //--------------------------------------------------------------------------------------
  47. bool CDXUTCheckBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  48. {
  49.     if( !m_bEnabled || !m_bVisible )
  50.         return false;
  51.     switch( uMsg )
  52.     {
  53.         case WM_LBUTTONDOWN:
  54.         case WM_LBUTTONDBLCLK:
  55.         {
  56.             if( ContainsPoint( pt ) )
  57.             {
  58.                 // Pressed while inside the control
  59.                 m_bPressed = true;
  60.                 SetCapture( DXUTGetHWND() );
  61.                 if( !m_bHasFocus )
  62.                     m_pDialog->RequestFocus( this );
  63.                 return true;
  64.             }
  65.             break;
  66.         }
  67.         case WM_LBUTTONUP:
  68.         {
  69.             if( m_bPressed )
  70.             {
  71.                 m_bPressed = false;
  72.                 ReleaseCapture();
  73.                 // Button click
  74.                 if( ContainsPoint( pt ) )
  75.                     SetCheckedInternal( !m_bChecked, true );
  76.                 
  77.                 return true;
  78.             }
  79.             break;
  80.         }
  81.     };
  82.     
  83.     return false;
  84. }
  85. //--------------------------------------------------------------------------------------
  86. void CDXUTCheckBox::SetCheckedInternal( bool bChecked, bool bFromInput ) 
  87.     m_bChecked = bChecked; 
  88.     m_pDialog->SendEvent( EVENT_CHECKBOX_CHANGED, bFromInput, this ); 
  89. }
  90. //--------------------------------------------------------------------------------------
  91. BOOL CDXUTCheckBox::ContainsPoint( POINT pt ) 
  92.     return ( PtInRect( &m_rcBoundingBox, pt ) || 
  93.              PtInRect( &m_rcButton, pt ) ); 
  94. }
  95. //--------------------------------------------------------------------------------------
  96. void CDXUTCheckBox::UpdateRects()
  97. {
  98.     CDXUTButton::UpdateRects();
  99.     m_rcButton = m_rcBoundingBox;
  100.     m_rcButton.right = m_rcButton.left + RectHeight( m_rcButton );
  101.     m_rcText = m_rcBoundingBox;
  102.     m_rcText.left += (int) ( 1.25f * RectWidth( m_rcButton ) );
  103. }
  104. //--------------------------------------------------------------------------------------
  105. void CDXUTCheckBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  106. {
  107.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  108.     if( m_bVisible == false )
  109.         iState = DXUT_STATE_HIDDEN;
  110.     else if( m_bEnabled == false )
  111.         iState = DXUT_STATE_DISABLED;
  112.     else if( m_bPressed )
  113.         iState = DXUT_STATE_PRESSED;
  114.     else if( m_bMouseOver )
  115.         iState = DXUT_STATE_MOUSEOVER;
  116.     else if( m_bHasFocus )
  117.         iState = DXUT_STATE_FOCUS;
  118.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  119.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  120.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  121.     pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate );
  122.     m_pDialog->DrawSprite( pElement, &m_rcButton );
  123.     m_pDialog->DrawText( m_strText, pElement, &m_rcText, true );
  124.     if( !m_bChecked )
  125.         iState = DXUT_STATE_HIDDEN;
  126.     pElement = m_Elements.GetAt( 1 );
  127.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  128.     m_pDialog->DrawSprite( pElement, &m_rcButton );
  129. }
  130. //--------------------------------------------------------------------------------------
  131. // CDXUTRadioButton class
  132. //--------------------------------------------------------------------------------------
  133. //--------------------------------------------------------------------------------------
  134. CDXUTRadioButton::CDXUTRadioButton( CDXUTDialog *pDialog )
  135. {
  136.     m_Type = DXUT_CONTROL_RADIOBUTTON;
  137.     m_pDialog = pDialog;
  138. }
  139. //--------------------------------------------------------------------------------------
  140. bool CDXUTRadioButton::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  141. {
  142.     if( !m_bEnabled || !m_bVisible )
  143.         return false;
  144.     switch( uMsg )
  145.     {
  146.         case WM_KEYDOWN:
  147.         {
  148.             switch( wParam )
  149.             {
  150.                 case VK_SPACE:
  151.                     m_bPressed = true;
  152.                     return true;
  153.             }
  154.         }
  155.         case WM_KEYUP:
  156.         {
  157.             switch( wParam )
  158.             {
  159.                 case VK_SPACE:
  160.                     if( m_bPressed == true )
  161.                     {
  162.                         m_bPressed = false;
  163.                         
  164.                         m_pDialog->ClearRadioButtonGroup( m_nButtonGroup );
  165.                         m_bChecked = !m_bChecked;
  166.                         m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, true, this );
  167.                     }
  168.                     return true;
  169.             }
  170.         }
  171.     }
  172.     return false;
  173. }
  174. //--------------------------------------------------------------------------------------
  175. bool CDXUTRadioButton::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  176. {
  177.     if( !m_bEnabled || !m_bVisible )
  178.         return false;
  179.     switch( uMsg )
  180.     {
  181.         case WM_LBUTTONDOWN:
  182.         case WM_LBUTTONDBLCLK:
  183.         {
  184.             if( ContainsPoint( pt ) )
  185.             {
  186.                 // Pressed while inside the control
  187.                 m_bPressed = true;
  188.                 SetCapture( DXUTGetHWND() );
  189.                 if( !m_bHasFocus )
  190.                     m_pDialog->RequestFocus( this );
  191.                 return true;
  192.             }
  193.             break;
  194.         }
  195.         case WM_LBUTTONUP:
  196.         {
  197.             if( m_bPressed )
  198.             {
  199.                 m_bPressed = false;
  200.                 ReleaseCapture();
  201.                 // Button click
  202.                 if( ContainsPoint( pt ) )
  203.                 {
  204.                     m_pDialog->ClearRadioButtonGroup( m_nButtonGroup );
  205.                     m_bChecked = !m_bChecked;
  206.                     m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, true, this );
  207.                 }
  208.                 return true;
  209.             }
  210.             break;
  211.         }
  212.     };
  213.     
  214.     return false;
  215. }
  216. //--------------------------------------------------------------------------------------
  217. void CDXUTRadioButton::SetCheckedInternal( bool bChecked, bool bClearGroup, bool bFromInput )
  218. {
  219.     if( bChecked && bClearGroup )
  220.         m_pDialog->ClearRadioButtonGroup( m_nButtonGroup );
  221.     m_bChecked = bChecked;
  222.     m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, bFromInput, this );
  223. }
  224. //--------------------------------------------------------------------------------------
  225. // CDXUTComboBox class
  226. //--------------------------------------------------------------------------------------
  227. //--------------------------------------------------------------------------------------
  228. CDXUTComboBox::CDXUTComboBox( CDXUTDialog *pDialog ) :
  229.     m_ScrollBar( pDialog )
  230. {
  231.     m_Type = DXUT_CONTROL_COMBOBOX;
  232.     m_pDialog = pDialog;
  233.     m_nDropHeight = 100;
  234.     m_nSBWidth = 16;
  235.     m_bOpened = false;
  236.     m_iSelected = -1;
  237.     m_iFocused = -1;
  238. }
  239. //--------------------------------------------------------------------------------------
  240. CDXUTComboBox::~CDXUTComboBox()
  241. {
  242.     RemoveAllItems();
  243. }
  244. //--------------------------------------------------------------------------------------
  245. void CDXUTComboBox::SetTextColor( D3DCOLOR Color )
  246. {
  247.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  248.     if( pElement )
  249.         pElement->FontColor.States[DXUT_STATE_NORMAL] = Color;
  250.     pElement = m_Elements.GetAt( 2 );
  251.     if( pElement )
  252.         pElement->FontColor.States[DXUT_STATE_NORMAL] = Color;
  253. }
  254. //--------------------------------------------------------------------------------------
  255. void CDXUTComboBox::UpdateRects()
  256. {
  257.     
  258.     CDXUTButton::UpdateRects();
  259.     m_rcButton = m_rcBoundingBox;
  260.     m_rcButton.left = m_rcButton.right - RectHeight( m_rcButton );
  261.     m_rcText = m_rcBoundingBox;
  262.     m_rcText.right = m_rcButton.left;
  263.     m_rcDropdown = m_rcText;
  264.     OffsetRect( &m_rcDropdown, 0, (int) (0.90f * RectHeight( m_rcText )) );
  265.     m_rcDropdown.bottom += m_nDropHeight;
  266.     m_rcDropdown.right -= m_nSBWidth;
  267.     m_rcDropdownText = m_rcDropdown;
  268.     m_rcDropdownText.left += (int) (0.1f * RectWidth( m_rcDropdown ));
  269.     m_rcDropdownText.right -= (int) (0.1f * RectWidth( m_rcDropdown ));
  270.     m_rcDropdownText.top += (int) (0.1f * RectHeight( m_rcDropdown ));
  271.     m_rcDropdownText.bottom -= (int) (0.1f * RectHeight( m_rcDropdown ));
  272.     // Update the scrollbar's rects
  273.     m_ScrollBar.SetLocation( m_rcDropdown.right, m_rcDropdown.top+2 );
  274.     m_ScrollBar.SetSize( m_nSBWidth, RectHeight( m_rcDropdown )-2 );
  275.     DXUTFontNode* pFontNode = m_pDialog->GetManager()->GetFontNode( m_Elements.GetAt( 2 )->iFont );
  276.     if( pFontNode && pFontNode->nHeight )
  277.     {
  278.         m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) / pFontNode->nHeight );
  279.         // The selected item may have been scrolled off the page.
  280.         // Ensure that it is in page again.
  281.         m_ScrollBar.ShowItem( m_iSelected );
  282.     }
  283. }
  284. //--------------------------------------------------------------------------------------
  285. void CDXUTComboBox::OnFocusOut()
  286. {
  287.     CDXUTButton::OnFocusOut();
  288.     m_bOpened = false;
  289. }
  290. //--------------------------------------------------------------------------------------
  291. bool CDXUTComboBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  292. {
  293.     const DWORD REPEAT_MASK = (0x40000000);
  294.     if( !m_bEnabled || !m_bVisible )
  295.         return false;
  296.     // Let the scroll bar have a chance to handle it first
  297.     if( m_ScrollBar.HandleKeyboard( uMsg, wParam, lParam ) )
  298.         return true;
  299.     switch( uMsg )
  300.     {
  301.         case WM_KEYDOWN:
  302.         {
  303.             switch( wParam )
  304.             {
  305.                 case VK_RETURN:
  306.                     if( m_bOpened )
  307.                     {
  308.                         if( m_iSelected != m_iFocused )
  309.                         {
  310.                             m_iSelected = m_iFocused;
  311.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  312.                         }
  313.                         m_bOpened = false;
  314.                         
  315.                         if( !m_pDialog->m_bKeyboardInput )
  316.                             m_pDialog->ClearFocus();
  317.                         return true;
  318.                     }
  319.                     break;
  320.                 case VK_F4:
  321.                     // Filter out auto-repeats
  322.                     if( lParam & REPEAT_MASK )
  323.                         return true;
  324.                     m_bOpened = !m_bOpened;
  325.                     if( !m_bOpened )
  326.                     {
  327.                         m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  328.                         if( !m_pDialog->m_bKeyboardInput )
  329.                             m_pDialog->ClearFocus();
  330.                     }
  331.                     return true;
  332.                 case VK_LEFT:
  333.                 case VK_UP:
  334.                     if( m_iFocused > 0 )
  335.                     {
  336.                         m_iFocused--;
  337.                         m_iSelected = m_iFocused;
  338.                         if( !m_bOpened )
  339.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  340.                     }
  341.                     
  342.                     return true;
  343.                 case VK_RIGHT:
  344.                 case VK_DOWN:
  345.                     if( m_iFocused+1 < (int)GetNumItems() )
  346.                     {
  347.                         m_iFocused++;
  348.                         m_iSelected = m_iFocused;
  349.                         if( !m_bOpened )
  350.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  351.                     }
  352.                     return true;
  353.             }
  354.             break;
  355.         }
  356.     }
  357.     return false;
  358. }
  359. //--------------------------------------------------------------------------------------
  360. bool CDXUTComboBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  361. {
  362.     if( !m_bEnabled || !m_bVisible )
  363.         return false;
  364.     // Let the scroll bar handle it first.
  365.     if( m_ScrollBar.HandleMouse( uMsg, pt, wParam, lParam ) )
  366.         return true;
  367.     switch( uMsg )
  368.     {
  369.         case WM_MOUSEMOVE:
  370.         {
  371.             if( m_bOpened && PtInRect( &m_rcDropdown, pt ) )
  372.             {
  373.                 // Determine which item has been selected
  374.                 for( int i=0; i < m_Items.GetSize(); i++ )
  375.                 {
  376.                     DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  377.                     if( pItem -> bVisible &&
  378.                         PtInRect( &pItem->rcActive, pt ) )
  379.                     {
  380.                         m_iFocused = i;
  381.                     }
  382.                 }
  383.                 return true;
  384.             }
  385.             break;
  386.         }
  387.         case WM_LBUTTONDOWN:
  388.         case WM_LBUTTONDBLCLK:
  389.         {
  390.             if( ContainsPoint( pt ) )
  391.             {
  392.                 // Pressed while inside the control
  393.                 m_bPressed = true;
  394.                 SetCapture( DXUTGetHWND() );
  395.                 if( !m_bHasFocus )
  396.                     m_pDialog->RequestFocus( this );
  397.                 // Toggle dropdown
  398.                 if( m_bHasFocus )
  399.                 {
  400.                     m_bOpened = !m_bOpened;
  401.                 
  402.                     if( !m_bOpened )
  403.                     {
  404.                         if( !m_pDialog->m_bKeyboardInput )
  405.                             m_pDialog->ClearFocus();
  406.                     }
  407.                 }
  408.                 return true;
  409.             }
  410.             // Perhaps this click is within the dropdown
  411.             if( m_bOpened && PtInRect( &m_rcDropdown, pt ) )
  412.             {
  413.                 // Determine which item has been selected
  414.                 for( int i=m_ScrollBar.GetTrackPos(); i < m_Items.GetSize(); i++ )
  415.                 {
  416.                     DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  417.                     if( pItem -> bVisible &&
  418.                         PtInRect( &pItem->rcActive, pt ) )
  419.                     {
  420.                         m_iFocused = m_iSelected = i;
  421.                         m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  422.                         m_bOpened = false;
  423.                         
  424.                         if( !m_pDialog->m_bKeyboardInput )
  425.                             m_pDialog->ClearFocus();
  426.                         break;
  427.                     }
  428.                 }
  429.                 return true;
  430.             }
  431.             // Mouse click not on main control or in dropdown, fire an event if needed
  432.             if( m_bOpened )
  433.             {
  434.                 m_iFocused = m_iSelected;
  435.                 m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  436.                 m_bOpened = false;
  437.             }
  438.             // Make sure the control is no longer in a pressed state
  439.             m_bPressed = false;
  440.             // Release focus if appropriate
  441.             if( !m_pDialog->m_bKeyboardInput )
  442.             {
  443.                 m_pDialog->ClearFocus();
  444.             }
  445.             break;
  446.         }
  447.         case WM_LBUTTONUP:
  448.         {
  449.             if( m_bPressed && ContainsPoint( pt ) )
  450.             {
  451.                 // Button click
  452.                 m_bPressed = false;
  453.                 ReleaseCapture();
  454.                 return true;
  455.             }
  456.             break;
  457.         }
  458.         case WM_MOUSEWHEEL:
  459.         {
  460.             int zDelta = (short) HIWORD(wParam) / WHEEL_DELTA;
  461.             if( m_bOpened )
  462.             {
  463.                 UINT uLines;
  464.                 SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &uLines, 0 );
  465.                 m_ScrollBar.Scroll( -zDelta * uLines );
  466.             } else
  467.             {
  468.                 if( zDelta > 0 )
  469.                 {
  470.                     if( m_iFocused > 0 )
  471.                     {
  472.                         m_iFocused--;
  473.                         m_iSelected = m_iFocused;     
  474.                         
  475.                         if( !m_bOpened )
  476.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  477.                     }          
  478.                 }
  479.                 else
  480.                 {
  481.                     if( m_iFocused+1 < (int)GetNumItems() )
  482.                     {
  483.                         m_iFocused++;
  484.                         m_iSelected = m_iFocused;   
  485.                         if( !m_bOpened )
  486.                             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  487.                     }
  488.                 }
  489.             }
  490.             return true;
  491.         }
  492.     };
  493.     
  494.     return false;
  495. }
  496. //--------------------------------------------------------------------------------------
  497. void CDXUTComboBox::OnHotkey()
  498. {
  499.     if( m_bOpened )
  500.         return;
  501.     if( m_iSelected == -1 )
  502.         return;
  503.     if( m_pDialog->IsKeyboardInputEnabled() )
  504.         m_pDialog->RequestFocus( this );
  505.     m_iSelected++;
  506.     
  507.     if( m_iSelected >= (int) m_Items.GetSize() )
  508.         m_iSelected = 0;
  509.     m_iFocused = m_iSelected;
  510.     m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this );
  511. }
  512. //--------------------------------------------------------------------------------------
  513. void CDXUTComboBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  514. {
  515.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  516.     
  517.     if( !m_bOpened )
  518.         iState = DXUT_STATE_HIDDEN;
  519.     // Dropdown box
  520.     CDXUTElement* pElement = m_Elements.GetAt( 2 );
  521.     // If we have not initialized the scroll bar page size,
  522.     // do that now.
  523.     static bool bSBInit;
  524.     if( !bSBInit )
  525.     {
  526.         // Update the page size of the scroll bar
  527.         if( m_pDialog->GetManager()->GetFontNode( pElement->iFont )->nHeight )
  528.             m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) / m_pDialog->GetManager()->GetFontNode( pElement->iFont )->nHeight );
  529.         else
  530.             m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) );
  531.         bSBInit = true;
  532.     }
  533.     // Scroll bar
  534.     if( m_bOpened )
  535.         m_ScrollBar.Render( pd3dDevice, fElapsedTime );
  536.     // Blend current color
  537.     pElement->TextureColor.Blend( iState, fElapsedTime );
  538.     pElement->FontColor.Blend( iState, fElapsedTime );
  539.     m_pDialog->DrawSprite( pElement, &m_rcDropdown );
  540.     // Selection outline
  541.     CDXUTElement* pSelectionElement = m_Elements.GetAt( 3 );
  542.     pSelectionElement->TextureColor.Current = pElement->TextureColor.Current;
  543.     pSelectionElement->FontColor.Current = pSelectionElement->FontColor.States[ DXUT_STATE_NORMAL ];
  544.     DXUTFontNode* pFont = m_pDialog->GetFont( pElement->iFont );
  545.     if( pFont )
  546.     {
  547.         int curY = m_rcDropdownText.top;
  548.         int nRemainingHeight = RectHeight( m_rcDropdownText );
  549.         //WCHAR strDropdown[4096] = {0};
  550.         for( int i = m_ScrollBar.GetTrackPos(); i < m_Items.GetSize(); i++ )
  551.         {
  552.             DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  553.             // Make sure there's room left in the dropdown
  554.             nRemainingHeight -= pFont->nHeight;
  555.             if( nRemainingHeight < 0 )
  556.             {
  557.                 pItem->bVisible = false;
  558.                 continue;
  559.             }
  560.             SetRect( &pItem->rcActive, m_rcDropdownText.left, curY, m_rcDropdownText.right, curY + pFont->nHeight );
  561.             curY += pFont->nHeight;
  562.             
  563.             //debug
  564.             //int blue = 50 * i;
  565.             //m_pDialog->DrawRect( &pItem->rcActive, 0xFFFF0000 | blue );
  566.             pItem->bVisible = true;
  567.             if( m_bOpened )
  568.             {
  569.                 if( (int)i == m_iFocused )
  570.                 {
  571.                     RECT rc;
  572.                     SetRect( &rc, m_rcDropdown.left, pItem->rcActive.top-2, m_rcDropdown.right, pItem->rcActive.bottom+2 );
  573.                     m_pDialog->DrawSprite( pSelectionElement, &rc );
  574.                     m_pDialog->DrawText( pItem->strText, pSelectionElement, &pItem->rcActive );
  575.                 }
  576.                 else
  577.                 {
  578.                     m_pDialog->DrawText( pItem->strText, pElement, &pItem->rcActive );
  579.                 }
  580.             }
  581.         }
  582.     }
  583.     int nOffsetX = 0;
  584.     int nOffsetY = 0;
  585.     iState = DXUT_STATE_NORMAL;
  586.     
  587.     if( m_bVisible == false )
  588.         iState = DXUT_STATE_HIDDEN;
  589.     else if( m_bEnabled == false )
  590.         iState = DXUT_STATE_DISABLED;
  591.     else if( m_bPressed )
  592.     {
  593.         iState = DXUT_STATE_PRESSED;
  594.         nOffsetX = 1;
  595.         nOffsetY = 2;
  596.     }
  597.     else if( m_bMouseOver )
  598.     {
  599.         iState = DXUT_STATE_MOUSEOVER;
  600.         nOffsetX = -1;
  601.         nOffsetY = -2;
  602.     }
  603.     else if( m_bHasFocus )
  604.         iState = DXUT_STATE_FOCUS;
  605.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  606.     
  607.     // Button
  608.     pElement = m_Elements.GetAt( 1 );
  609.     
  610.     // Blend current color
  611.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  612.     
  613.     RECT rcWindow = m_rcButton;
  614.     OffsetRect( &rcWindow, nOffsetX, nOffsetY );
  615.     m_pDialog->DrawSprite( pElement, &rcWindow );
  616.     if( m_bOpened )
  617.         iState = DXUT_STATE_PRESSED;
  618.     // Main text box
  619.     //TODO: remove magic numbers
  620.     pElement = m_Elements.GetAt( 0 );
  621.     
  622.     // Blend current color
  623.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  624.     pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate );
  625.     m_pDialog->DrawSprite( pElement, &m_rcText);
  626.     
  627.     if( m_iSelected >= 0 && m_iSelected < (int) m_Items.GetSize() )
  628.     {
  629.         DXUTComboBoxItem* pItem = m_Items.GetAt( m_iSelected );
  630.         if( pItem != NULL )
  631.         {
  632.             m_pDialog->DrawText( pItem->strText, pElement, &m_rcText );
  633.         
  634.         }
  635.     }
  636. }
  637. //--------------------------------------------------------------------------------------
  638. HRESULT CDXUTComboBox::AddItem( const WCHAR* strText, void* pData )
  639. {
  640.     // Validate parameters
  641.     if( strText== NULL )
  642.     {
  643.         return E_INVALIDARG;
  644.     }
  645.     
  646.     // Create a new item and set the data
  647.     DXUTComboBoxItem* pItem = new DXUTComboBoxItem;
  648.     if( pItem == NULL )
  649.     {
  650.         return DXTRACE_ERR_MSGBOX( L"new", E_OUTOFMEMORY );
  651.     }
  652.     
  653.     ZeroMemory( pItem, sizeof(DXUTComboBoxItem) );
  654.     StringCchCopy( pItem->strText, 256, strText );
  655.     pItem->pData = pData;
  656.     m_Items.Add( pItem );
  657.     // Update the scroll bar with new range
  658.     m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  659.     // If this is the only item in the list, it's selected
  660.     if( GetNumItems() == 1 )
  661.     {
  662.         m_iSelected = 0;
  663.         m_iFocused = 0;
  664.         m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  665.     }
  666.     return S_OK;
  667. }
  668. //--------------------------------------------------------------------------------------
  669. void CDXUTComboBox::RemoveItem( UINT index )
  670. {
  671.     DXUTComboBoxItem* pItem = m_Items.GetAt( index );
  672.     SAFE_DELETE( pItem );
  673.     m_Items.Remove( index );
  674.     m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  675.     if( m_iSelected >= m_Items.GetSize() )
  676.         m_iSelected = m_Items.GetSize() - 1;
  677. }
  678. //--------------------------------------------------------------------------------------
  679. void CDXUTComboBox::RemoveAllItems()
  680. {
  681.     for( int i=0; i < m_Items.GetSize(); i++ )
  682.     {
  683.         DXUTComboBoxItem* pItem = m_Items.GetAt( i );
  684.         SAFE_DELETE( pItem );
  685.     }
  686.     m_Items.RemoveAll();
  687.     m_ScrollBar.SetTrackRange( 0, 1 );
  688.     m_iFocused = m_iSelected = -1;
  689. }
  690. //--------------------------------------------------------------------------------------
  691. bool CDXUTComboBox::ContainsItem( const WCHAR* strText, UINT iStart )
  692. {
  693.     return ( -1 != FindItem( strText, iStart ) );
  694. }
  695. //--------------------------------------------------------------------------------------
  696. int CDXUTComboBox::FindItem( const WCHAR* strText, UINT iStart )
  697. {
  698.     if( strText == NULL )
  699.         return -1;
  700.     for( int i = iStart; i < m_Items.GetSize(); i++ )
  701.     {
  702.         DXUTComboBoxItem* pItem = m_Items.GetAt(i);
  703.         if( 0 == wcscmp( pItem->strText, strText ) )
  704.         {
  705.             return i;
  706.         }
  707.     }
  708.     return -1;
  709. }
  710. //--------------------------------------------------------------------------------------
  711. void* CDXUTComboBox::GetSelectedData()
  712. {
  713.     if( m_iSelected < 0 )
  714.         return NULL;
  715.     DXUTComboBoxItem* pItem = m_Items.GetAt( m_iSelected );
  716.     return pItem->pData;
  717. }
  718. //--------------------------------------------------------------------------------------
  719. DXUTComboBoxItem* CDXUTComboBox::GetSelectedItem()
  720. {
  721.     if( m_iSelected < 0 )
  722.         return NULL;
  723.     return m_Items.GetAt( m_iSelected );
  724. }
  725. //--------------------------------------------------------------------------------------
  726. void* CDXUTComboBox::GetItemData( const WCHAR* strText )
  727. {
  728.     int index = FindItem( strText );
  729.     if( index == -1 )
  730.     {
  731.         return NULL;
  732.     }
  733.     DXUTComboBoxItem* pItem = m_Items.GetAt(index);
  734.     if( pItem == NULL )
  735.     {
  736.         DXTRACE_ERR( L"CGrowableArray::GetAt", E_FAIL );
  737.         return NULL;
  738.     }
  739.     return pItem->pData;
  740. }
  741. //--------------------------------------------------------------------------------------
  742. void* CDXUTComboBox::GetItemData( int nIndex )
  743. {
  744.     if( nIndex < 0 || nIndex >= m_Items.GetSize() )
  745.         return NULL;
  746.     return m_Items.GetAt( nIndex )->pData;
  747. }
  748. //--------------------------------------------------------------------------------------
  749. HRESULT CDXUTComboBox::SetSelectedByIndex( UINT index )
  750. {
  751.     if( index >= GetNumItems() )
  752.         return E_INVALIDARG;
  753.     m_iFocused = m_iSelected = index;
  754.     m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  755.     return S_OK;
  756. }
  757. //--------------------------------------------------------------------------------------
  758. HRESULT CDXUTComboBox::SetSelectedByText( const WCHAR* strText )
  759. {
  760.     if( strText == NULL )
  761.         return E_INVALIDARG;
  762.     int index = FindItem( strText );
  763.     if( index == -1 )
  764.         return E_FAIL;
  765.     m_iFocused = m_iSelected = index;
  766.     m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  767.     return S_OK;
  768. }
  769. //--------------------------------------------------------------------------------------
  770. HRESULT CDXUTComboBox::SetSelectedByData( void* pData )
  771. {
  772.     for( int i=0; i < m_Items.GetSize(); i++ )
  773.     {
  774.         DXUTComboBoxItem* pItem = m_Items.GetAt(i);
  775.         if( pItem->pData == pData )
  776.         {
  777.             m_iFocused = m_iSelected = i;
  778.             m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this );
  779.             return S_OK;
  780.         }
  781.     }
  782.     return E_FAIL;
  783. }
  784. //--------------------------------------------------------------------------------------
  785. CDXUTSlider::CDXUTSlider( CDXUTDialog *pDialog )
  786. {
  787.     m_Type = DXUT_CONTROL_SLIDER;
  788.     m_pDialog = pDialog;
  789.     m_nMin = 0;
  790.     m_nMax = 100;
  791.     m_nValue = 50;
  792.     m_bPressed = false;
  793. }
  794. //--------------------------------------------------------------------------------------
  795. BOOL CDXUTSlider::ContainsPoint( POINT pt ) 
  796.     return ( PtInRect( &m_rcBoundingBox, pt ) || 
  797.              PtInRect( &m_rcButton, pt ) ); 
  798. }
  799. //--------------------------------------------------------------------------------------
  800. void CDXUTSlider::UpdateRects()
  801. {
  802.     CDXUTControl::UpdateRects();
  803.     m_rcButton = m_rcBoundingBox;
  804.     m_rcButton.right = m_rcButton.left + RectHeight( m_rcButton );
  805.     OffsetRect( &m_rcButton, -RectWidth( m_rcButton )/2, 0 );
  806.     m_nButtonX = (int) ( (m_nValue - m_nMin) * (float)RectWidth( m_rcBoundingBox ) / (m_nMax - m_nMin) );
  807.     OffsetRect( &m_rcButton, m_nButtonX, 0 );
  808. }
  809. int CDXUTSlider::ValueFromPos( int x )
  810.     float fValuePerPixel = (float)(m_nMax - m_nMin) / RectWidth( m_rcBoundingBox );
  811.     return (int) (0.5f + m_nMin + fValuePerPixel * (x - m_rcBoundingBox.left)) ; 
  812. }
  813. //--------------------------------------------------------------------------------------
  814. bool CDXUTSlider::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  815. {
  816.     if( !m_bEnabled || !m_bVisible )
  817.         return false;
  818.     switch( uMsg )
  819.     {
  820.         case WM_KEYDOWN:
  821.         {
  822.             switch( wParam )
  823.             {
  824.                 case VK_HOME:
  825.                     SetValueInternal( m_nMin, true );
  826.                     return true;
  827.                 case VK_END:
  828.                     SetValueInternal( m_nMax, true );
  829.                     return true;
  830.                 case VK_LEFT:
  831.                 case VK_DOWN:
  832.                     SetValueInternal( m_nValue - 1, true );
  833.                     return true;
  834.                 case VK_RIGHT:
  835.                 case VK_UP:
  836.                     SetValueInternal( m_nValue + 1, true );
  837.                     return true;
  838.                 case VK_NEXT:
  839.                     SetValueInternal( m_nValue - ( 10 > (m_nMax - m_nMin) / 10 ? 10 : (m_nMax - m_nMin) / 10 ), true );
  840.                     return true;
  841.                 case VK_PRIOR:
  842.                     SetValueInternal( m_nValue + ( 10 > (m_nMax - m_nMin) / 10 ? 10 : (m_nMax - m_nMin) / 10 ), true );
  843.                     return true;
  844.             }
  845.             break;
  846.         }
  847.     }
  848.     
  849.     return false;
  850. }
  851. //--------------------------------------------------------------------------------------
  852. bool CDXUTSlider::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  853. {
  854.     if( !m_bEnabled || !m_bVisible )
  855.         return false;
  856.     switch( uMsg )
  857.     {
  858.         case WM_LBUTTONDOWN:
  859.         case WM_LBUTTONDBLCLK:
  860.         {
  861.             if( PtInRect( &m_rcButton, pt ) )
  862.             {
  863.                 // Pressed while inside the control
  864.                 m_bPressed = true;
  865.                 SetCapture( DXUTGetHWND() );
  866.                 m_nDragX = pt.x;
  867.                 //m_nDragY = pt.y;
  868.                 m_nDragOffset = m_nButtonX - m_nDragX;
  869.                 //m_nDragValue = m_nValue;
  870.                 if( !m_bHasFocus )
  871.                     m_pDialog->RequestFocus( this );
  872.                 return true;
  873.             }
  874.             if( PtInRect( &m_rcBoundingBox, pt ) )
  875.             {
  876.                 m_nDragX = pt.x;
  877.                 m_nDragOffset = 0;               
  878.                 m_bPressed = true;
  879.                 
  880.                 if( !m_bHasFocus )
  881.                     m_pDialog->RequestFocus( this );
  882.                 if( pt.x > m_nButtonX + m_x )
  883.                 {
  884.                     SetValueInternal( m_nValue + 1, true );
  885.                     return true;
  886.                 }
  887.                 if( pt.x < m_nButtonX + m_x )
  888.                 {
  889.                     SetValueInternal( m_nValue - 1, true );
  890.                     return true;
  891.                 }
  892.             }
  893.             break;
  894.         }
  895.         case WM_LBUTTONUP:
  896.         {
  897.             if( m_bPressed )
  898.             {
  899.                 m_bPressed = false;
  900.                 ReleaseCapture();
  901.                 m_pDialog->SendEvent( EVENT_SLIDER_VALUE_CHANGED, true, this );
  902.                 return true;
  903.             }
  904.             break;
  905.         }
  906.         case WM_MOUSEMOVE:
  907.         {
  908.             if( m_bPressed )
  909.             {
  910.                 SetValueInternal( ValueFromPos( m_x + pt.x + m_nDragOffset ), true );
  911.                 return true;
  912.             }
  913.             break;
  914.         }
  915.         case WM_MOUSEWHEEL:
  916.         {
  917.             int nScrollAmount = int((short)HIWORD(wParam)) / WHEEL_DELTA;
  918.             SetValueInternal( m_nValue - nScrollAmount, true );
  919.             return true;
  920.         }
  921.     };
  922.     
  923.     return false;
  924. }
  925. //--------------------------------------------------------------------------------------
  926. void CDXUTSlider::SetRange( int nMin, int nMax ) 
  927. {
  928.     m_nMin = nMin;
  929.     m_nMax = nMax;
  930.     SetValueInternal( m_nValue, false );
  931. }
  932. //--------------------------------------------------------------------------------------
  933. void CDXUTSlider::SetValueInternal( int nValue, bool bFromInput )
  934. {
  935.     // Clamp to range
  936.     nValue = __max( m_nMin, nValue );
  937.     nValue = __min( m_nMax, nValue );
  938.     
  939.     if( nValue == m_nValue )
  940.         return;
  941.     m_nValue = nValue;
  942.     UpdateRects();
  943.     m_pDialog->SendEvent( EVENT_SLIDER_VALUE_CHANGED, bFromInput, this );
  944. }
  945. //--------------------------------------------------------------------------------------
  946. void CDXUTSlider::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  947. {
  948.     int nOffsetX = 0;
  949.     int nOffsetY = 0;
  950.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  951.     if( m_bVisible == false )
  952.     {
  953.         iState = DXUT_STATE_HIDDEN;
  954.     }
  955.     else if( m_bEnabled == false )
  956.     {
  957.         iState = DXUT_STATE_DISABLED;
  958.     }
  959.     else if( m_bPressed )
  960.     {
  961.         iState = DXUT_STATE_PRESSED;
  962.         nOffsetX = 1;
  963.         nOffsetY = 2;
  964.     }
  965.     else if( m_bMouseOver )
  966.     {
  967.         iState = DXUT_STATE_MOUSEOVER;
  968.         
  969.         nOffsetX = -1;
  970.         nOffsetY = -2;
  971.     }
  972.     else if( m_bHasFocus )
  973.     {
  974.         iState = DXUT_STATE_FOCUS;
  975.     }
  976.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  977.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  978.     
  979.     // Blend current color
  980.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); 
  981.     m_pDialog->DrawSprite( pElement, &m_rcBoundingBox );
  982.     //TODO: remove magic numbers
  983.     pElement = m_Elements.GetAt( 1 );
  984.        
  985.     // Blend current color
  986.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  987.     m_pDialog->DrawSprite( pElement, &m_rcButton );
  988. }
  989. //--------------------------------------------------------------------------------------
  990. // CDXUTScrollBar class
  991. //--------------------------------------------------------------------------------------
  992. //--------------------------------------------------------------------------------------
  993. CDXUTScrollBar::CDXUTScrollBar( CDXUTDialog *pDialog )
  994. {
  995.     m_Type = DXUT_CONTROL_SCROLLBAR;
  996.     m_pDialog = pDialog;
  997.     m_bShowThumb = true;
  998.     m_bDrag = false;
  999.     SetRect( &m_rcUpButton, 0, 0, 0, 0 );
  1000.     SetRect( &m_rcDownButton, 0, 0, 0, 0 );
  1001.     SetRect( &m_rcTrack, 0, 0, 0, 0 );
  1002.     SetRect( &m_rcThumb, 0, 0, 0, 0 );
  1003.     m_nPosition = 0;
  1004.     m_nPageSize = 1;
  1005.     m_nStart = 0;
  1006.     m_nEnd = 1;
  1007.     m_Arrow = CLEAR;
  1008.     m_dArrowTS = 0.0;
  1009. }
  1010. //--------------------------------------------------------------------------------------
  1011. CDXUTScrollBar::~CDXUTScrollBar()
  1012. {
  1013. }
  1014. //--------------------------------------------------------------------------------------
  1015. void CDXUTScrollBar::UpdateRects()
  1016. {
  1017.     CDXUTControl::UpdateRects();
  1018.     // Make the buttons square
  1019.     SetRect( &m_rcUpButton, m_rcBoundingBox.left, m_rcBoundingBox.top,
  1020.                             m_rcBoundingBox.right, m_rcBoundingBox.top + RectWidth( m_rcBoundingBox ) );
  1021.     SetRect( &m_rcDownButton, m_rcBoundingBox.left, m_rcBoundingBox.bottom - RectWidth( m_rcBoundingBox ),
  1022.                               m_rcBoundingBox.right, m_rcBoundingBox.bottom );
  1023.     SetRect( &m_rcTrack, m_rcUpButton.left, m_rcUpButton.bottom,
  1024.                          m_rcDownButton.right, m_rcDownButton.top );
  1025.     m_rcThumb.left = m_rcUpButton.left;
  1026.     m_rcThumb.right = m_rcUpButton.right;
  1027.     UpdateThumbRect();
  1028. }
  1029. //--------------------------------------------------------------------------------------
  1030. // Compute the dimension of the scroll thumb
  1031. void CDXUTScrollBar::UpdateThumbRect()
  1032. {
  1033.     if( m_nEnd - m_nStart > m_nPageSize )
  1034.     {
  1035.         int nThumbHeight = __max( RectHeight( m_rcTrack ) * m_nPageSize / ( m_nEnd - m_nStart ), SCROLLBAR_MINTHUMBSIZE );
  1036.         int nMaxPosition = m_nEnd - m_nStart - m_nPageSize;
  1037.         m_rcThumb.top = m_rcTrack.top + ( m_nPosition - m_nStart ) * ( RectHeight( m_rcTrack ) - nThumbHeight )
  1038.                         / nMaxPosition;
  1039.         m_rcThumb.bottom = m_rcThumb.top + nThumbHeight;
  1040.         m_bShowThumb = true;
  1041.     } 
  1042.     else
  1043.     {
  1044.         // No content to scroll
  1045.         m_rcThumb.bottom = m_rcThumb.top;
  1046.         m_bShowThumb = false;
  1047.     }
  1048. }
  1049. //--------------------------------------------------------------------------------------
  1050. // Scroll() scrolls by nDelta items.  A positive value scrolls down, while a negative
  1051. // value scrolls up.
  1052. void CDXUTScrollBar::Scroll( int nDelta )
  1053. {
  1054.     // Perform scroll
  1055.     m_nPosition += nDelta;
  1056.     // Cap position
  1057.     Cap();
  1058.     // Update thumb position
  1059.     UpdateThumbRect();
  1060. }
  1061. //--------------------------------------------------------------------------------------
  1062. void CDXUTScrollBar::ShowItem( int nIndex )
  1063. {
  1064.     // Cap the index
  1065.     if( nIndex < 0 )
  1066.         nIndex = 0;
  1067.     if( nIndex >= m_nEnd )
  1068.         nIndex = m_nEnd - 1;
  1069.     // Adjust position
  1070.     if( m_nPosition > nIndex )
  1071.         m_nPosition = nIndex;
  1072.     else
  1073.     if( m_nPosition + m_nPageSize <= nIndex )
  1074.         m_nPosition = nIndex - m_nPageSize + 1;
  1075.     UpdateThumbRect();
  1076. }
  1077. //--------------------------------------------------------------------------------------
  1078. bool CDXUTScrollBar::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1079. {
  1080.     return false;
  1081. }
  1082. //--------------------------------------------------------------------------------------
  1083. bool CDXUTScrollBar::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  1084. {
  1085.     static int ThumbOffsetY;
  1086.     m_LastMouse = pt;
  1087.     switch( uMsg )
  1088.     {
  1089.         case WM_LBUTTONDOWN:
  1090.         case WM_LBUTTONDBLCLK:
  1091.         {
  1092.             // Check for click on up button
  1093.             if( PtInRect( &m_rcUpButton, pt ) )
  1094.             {
  1095.                 SetCapture( DXUTGetHWND() );
  1096.                 if( m_nPosition > m_nStart )
  1097.                     --m_nPosition;
  1098.                 UpdateThumbRect();
  1099.                 m_Arrow = CLICKED_UP;
  1100.                 m_dArrowTS = DXUTGetTime();
  1101.                 return true;
  1102.             }
  1103.             // Check for click on down button
  1104.             if( PtInRect( &m_rcDownButton, pt ) )
  1105.             {
  1106.                 SetCapture( DXUTGetHWND() );
  1107.                 if( m_nPosition + m_nPageSize < m_nEnd )
  1108.                     ++m_nPosition;
  1109.                 UpdateThumbRect();
  1110.                 m_Arrow = CLICKED_DOWN;
  1111.                 m_dArrowTS = DXUTGetTime();
  1112.                 return true;
  1113.             }
  1114.             // Check for click on thumb
  1115.             if( PtInRect( &m_rcThumb, pt ) )
  1116.             {
  1117.                 SetCapture( DXUTGetHWND() );
  1118.                 m_bDrag = true;
  1119.                 ThumbOffsetY = pt.y - m_rcThumb.top;
  1120.                 return true;
  1121.             }
  1122.             // Check for click on track
  1123.             if( m_rcThumb.left <= pt.x &&
  1124.                 m_rcThumb.right > pt.x )
  1125.             {
  1126.                 SetCapture( DXUTGetHWND() );
  1127.                 if( m_rcThumb.top > pt.y &&
  1128.                     m_rcTrack.top <= pt.y )
  1129.                 {
  1130.                     Scroll( -( m_nPageSize - 1 ) );
  1131.                     return true;
  1132.                 } else
  1133.                 if( m_rcThumb.bottom <= pt.y &&
  1134.                     m_rcTrack.bottom > pt.y )
  1135.                 {
  1136.                     Scroll( m_nPageSize - 1 );
  1137.                     return true;
  1138.                 }
  1139.             }
  1140.             break;
  1141.         }
  1142.         case WM_LBUTTONUP:
  1143.         {
  1144.             m_bDrag = false;
  1145.             ReleaseCapture();
  1146.             UpdateThumbRect();
  1147.             m_Arrow = CLEAR;
  1148.             break;
  1149.         }
  1150.         case WM_MOUSEMOVE:
  1151.         {
  1152.             if( m_bDrag )
  1153.             {
  1154.                 m_rcThumb.bottom += pt.y - ThumbOffsetY - m_rcThumb.top;
  1155.                 m_rcThumb.top = pt.y - ThumbOffsetY;
  1156.                 if( m_rcThumb.top < m_rcTrack.top )
  1157.                     OffsetRect( &m_rcThumb, 0, m_rcTrack.top - m_rcThumb.top );
  1158.                 else
  1159.                 if( m_rcThumb.bottom > m_rcTrack.bottom )
  1160.                     OffsetRect( &m_rcThumb, 0, m_rcTrack.bottom - m_rcThumb.bottom );
  1161.                 // Compute first item index based on thumb position
  1162.                 int nMaxFirstItem = m_nEnd - m_nStart - m_nPageSize;  // Largest possible index for first item
  1163.                 int nMaxThumb = RectHeight( m_rcTrack ) - RectHeight( m_rcThumb );  // Largest possible thumb position from the top
  1164.                 m_nPosition = m_nStart +
  1165.                               ( m_rcThumb.top - m_rcTrack.top +
  1166.                                 nMaxThumb / ( nMaxFirstItem * 2 ) ) * // Shift by half a row to avoid last row covered by only one pixel
  1167.                               nMaxFirstItem  / nMaxThumb;
  1168.                 return true;
  1169.             }
  1170.             break;
  1171.         }
  1172.     }
  1173.     return false;
  1174. }
  1175. //--------------------------------------------------------------------------------------
  1176. bool CDXUTScrollBar::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1177. {
  1178.     if( WM_CAPTURECHANGED == uMsg )
  1179.     {
  1180.         // The application just lost mouse capture. We may not have gotten
  1181.         // the WM_MOUSEUP message, so reset m_bDrag here.
  1182.         if( (HWND)lParam != DXUTGetHWND() )
  1183.             m_bDrag = false;
  1184.     }
  1185.     return false;
  1186. }
  1187. //--------------------------------------------------------------------------------------
  1188. void CDXUTScrollBar::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  1189. {
  1190.     // Check if the arrow button has been held for a while.
  1191.     // If so, update the thumb position to simulate repeated
  1192.     // scroll.
  1193.     if( m_Arrow != CLEAR )
  1194.     {
  1195.         double dCurrTime = DXUTGetTime();
  1196.         if( PtInRect( &m_rcUpButton, m_LastMouse ) )
  1197.         {
  1198.             switch( m_Arrow )
  1199.             {
  1200.                 case CLICKED_UP:
  1201.                     if( SCROLLBAR_ARROWCLICK_DELAY < dCurrTime - m_dArrowTS )
  1202.                     {
  1203.                         Scroll( -1 );
  1204.                         m_Arrow = HELD_UP;
  1205.                         m_dArrowTS = dCurrTime;
  1206.                     }
  1207.                     break;
  1208.                 case HELD_UP:
  1209.                     if( SCROLLBAR_ARROWCLICK_REPEAT < dCurrTime - m_dArrowTS )
  1210.                     {
  1211.                         Scroll( -1 );
  1212.                         m_dArrowTS = dCurrTime;
  1213.                     }
  1214.                     break;
  1215.             }
  1216.         } else
  1217.         if( PtInRect( &m_rcDownButton, m_LastMouse ) )
  1218.         {
  1219.             switch( m_Arrow )
  1220.             {
  1221.                 case CLICKED_DOWN:
  1222.                     if( SCROLLBAR_ARROWCLICK_DELAY < dCurrTime - m_dArrowTS )
  1223.                     {
  1224.                         Scroll( 1 );
  1225.                         m_Arrow = HELD_DOWN;
  1226.                         m_dArrowTS = dCurrTime;
  1227.                     }
  1228.                     break;
  1229.                 case HELD_DOWN:
  1230.                     if( SCROLLBAR_ARROWCLICK_REPEAT < dCurrTime - m_dArrowTS )
  1231.                     {
  1232.                         Scroll( 1 );
  1233.                         m_dArrowTS = dCurrTime;
  1234.                     }
  1235.                     break;
  1236.             }
  1237.         }
  1238.     }
  1239.     DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL;
  1240.     if( m_bVisible == false )
  1241.         iState = DXUT_STATE_HIDDEN;
  1242.     else if( m_bEnabled == false || m_bShowThumb == false )
  1243.         iState = DXUT_STATE_DISABLED;
  1244.     else if( m_bMouseOver )
  1245.         iState = DXUT_STATE_MOUSEOVER;
  1246.     else if( m_bHasFocus )
  1247.         iState = DXUT_STATE_FOCUS;
  1248.     float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f;
  1249.     // Background track layer
  1250.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  1251.     
  1252.     // Blend current color
  1253.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  1254.     m_pDialog->DrawSprite( pElement, &m_rcTrack );
  1255.     // Up Arrow
  1256.     pElement = m_Elements.GetAt( 1 );
  1257.     
  1258.     // Blend current color
  1259.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  1260.     m_pDialog->DrawSprite( pElement, &m_rcUpButton );
  1261.     // Down Arrow
  1262.     pElement = m_Elements.GetAt( 2 );
  1263.     
  1264.     // Blend current color
  1265.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  1266.     m_pDialog->DrawSprite( pElement, &m_rcDownButton );
  1267.     // Thumb button
  1268.     pElement = m_Elements.GetAt( 3 );
  1269.     
  1270.     // Blend current color
  1271.     pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate );
  1272.     m_pDialog->DrawSprite( pElement, &m_rcThumb );
  1273.  
  1274. }
  1275. //--------------------------------------------------------------------------------------
  1276. void CDXUTScrollBar::SetTrackRange( int nStart, int nEnd )
  1277. {
  1278.     m_nStart = nStart; m_nEnd = nEnd;
  1279.     Cap();
  1280.     UpdateThumbRect();
  1281. }
  1282. //--------------------------------------------------------------------------------------
  1283. void CDXUTScrollBar::Cap()  // Clips position at boundaries. Ensures it stays within legal range.
  1284. {
  1285.     if( m_nPosition < m_nStart ||
  1286.         m_nEnd - m_nStart <= m_nPageSize )
  1287.     {
  1288.         m_nPosition = m_nStart;
  1289.     }
  1290.     else
  1291.     if( m_nPosition + m_nPageSize > m_nEnd )
  1292.         m_nPosition = m_nEnd - m_nPageSize;
  1293. }
  1294. //--------------------------------------------------------------------------------------
  1295. // CDXUTListBox class
  1296. //--------------------------------------------------------------------------------------
  1297. //--------------------------------------------------------------------------------------
  1298. CDXUTListBox::CDXUTListBox( CDXUTDialog *pDialog ) :
  1299.     m_ScrollBar( pDialog )
  1300. {
  1301.     m_Type = DXUT_CONTROL_LISTBOX;
  1302.     m_pDialog = pDialog;
  1303.     m_dwStyle = 0;
  1304.     m_nSBWidth = 16;
  1305.     m_nSelected = -1;
  1306.     m_nSelStart = 0;
  1307.     m_bDrag = false;
  1308.     m_nBorder = 6;
  1309.     m_nMargin = 5;
  1310.     m_nTextHeight = 0;
  1311. }
  1312. //--------------------------------------------------------------------------------------
  1313. CDXUTListBox::~CDXUTListBox()
  1314. {
  1315.     RemoveAllItems();
  1316. }
  1317. //--------------------------------------------------------------------------------------
  1318. void CDXUTListBox::UpdateRects()
  1319. {
  1320.     CDXUTControl::UpdateRects();
  1321.     m_rcSelection = m_rcBoundingBox;
  1322.     m_rcSelection.right -= m_nSBWidth;
  1323.     InflateRect( &m_rcSelection, -m_nBorder, -m_nBorder );
  1324.     m_rcText = m_rcSelection;
  1325.     InflateRect( &m_rcText, -m_nMargin, 0 );
  1326.     // Update the scrollbar's rects
  1327.     m_ScrollBar.SetLocation( m_rcBoundingBox.right - m_nSBWidth, m_rcBoundingBox.top );
  1328.     m_ScrollBar.SetSize( m_nSBWidth, m_height );
  1329.     DXUTFontNode* pFontNode = m_pDialog->GetManager()->GetFontNode( m_Elements.GetAt( 0 )->iFont );
  1330.     if( pFontNode && pFontNode->nHeight )
  1331.     {
  1332.         m_ScrollBar.SetPageSize( RectHeight( m_rcText ) / pFontNode->nHeight );
  1333.         // The selected item may have been scrolled off the page.
  1334.         // Ensure that it is in page again.
  1335.         m_ScrollBar.ShowItem( m_nSelected );
  1336.     }
  1337. }
  1338. //--------------------------------------------------------------------------------------
  1339. HRESULT CDXUTListBox::AddItem( const WCHAR *wszText, void *pData )
  1340. {
  1341.     DXUTListBoxItem *pNewItem = new DXUTListBoxItem;
  1342.     if( !pNewItem )
  1343.         return E_OUTOFMEMORY;
  1344.     StringCchCopy( pNewItem->strText, 256, wszText );
  1345.     pNewItem->pData = pData;
  1346.     SetRect( &pNewItem->rcActive, 0, 0, 0, 0 );
  1347.     pNewItem->bSelected = false;
  1348.     HRESULT hr = m_Items.Add( pNewItem );
  1349.     if( FAILED(hr) )
  1350.     {
  1351.         SAFE_DELETE( pNewItem );
  1352.     }
  1353.     else
  1354.     {
  1355.         m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  1356.     }
  1357.     return hr;
  1358. }
  1359. //--------------------------------------------------------------------------------------
  1360. HRESULT CDXUTListBox::InsertItem( int nIndex, const WCHAR *wszText, void *pData )
  1361. {
  1362.     DXUTListBoxItem *pNewItem = new DXUTListBoxItem;
  1363.     if( !pNewItem )
  1364.         return E_OUTOFMEMORY;
  1365.     StringCchCopy( pNewItem->strText, 256, wszText );
  1366.     pNewItem->pData = pData;
  1367.     SetRect( &pNewItem->rcActive, 0, 0, 0, 0 );
  1368.     pNewItem->bSelected = false;
  1369.     HRESULT hr = m_Items.Insert( nIndex, pNewItem );
  1370.     if( SUCCEEDED( hr ) )
  1371.         m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  1372.     else
  1373.         SAFE_DELETE( pNewItem );
  1374.     return hr;
  1375. }
  1376. //--------------------------------------------------------------------------------------
  1377. void CDXUTListBox::RemoveItem( int nIndex )
  1378. {
  1379.     if( nIndex < 0 || nIndex >= (int)m_Items.GetSize() )
  1380.         return;
  1381.     DXUTListBoxItem *pItem = m_Items.GetAt( nIndex );
  1382.     delete pItem;
  1383.     m_Items.Remove( nIndex );
  1384.     m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() );
  1385.     if( m_nSelected >= (int)m_Items.GetSize() )
  1386.         m_nSelected = m_Items.GetSize() - 1;
  1387.     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1388. }
  1389. //--------------------------------------------------------------------------------------
  1390. void CDXUTListBox::RemoveItemByText( WCHAR *wszText )
  1391. {
  1392. }
  1393. //--------------------------------------------------------------------------------------
  1394. void CDXUTListBox::RemoveItemByData( void *pData )
  1395. {
  1396. }
  1397. //--------------------------------------------------------------------------------------
  1398. void CDXUTListBox::RemoveAllItems()
  1399. {
  1400.     for( int i = 0; i < m_Items.GetSize(); ++i )
  1401.     {
  1402.         DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1403.         delete pItem;
  1404.     }
  1405.     m_Items.RemoveAll();
  1406.     m_ScrollBar.SetTrackRange( 0, 1 );
  1407. }
  1408. //--------------------------------------------------------------------------------------
  1409. DXUTListBoxItem *CDXUTListBox::GetItem( int nIndex )
  1410. {
  1411.     if( nIndex < 0 || nIndex >= (int)m_Items.GetSize() )
  1412.         return NULL;
  1413.     return m_Items[nIndex];
  1414. }
  1415. //--------------------------------------------------------------------------------------
  1416. // For single-selection listbox, returns the index of the selected item.
  1417. // For multi-selection, returns the first selected item after the nPreviousSelected position.
  1418. // To search for the first selected item, the app passes -1 for nPreviousSelected.  For
  1419. // subsequent searches, the app passes the returned index back to GetSelectedIndex as.
  1420. // nPreviousSelected.
  1421. // Returns -1 on error or if no item is selected.
  1422. int CDXUTListBox::GetSelectedIndex( int nPreviousSelected )
  1423. {
  1424.     if( nPreviousSelected < -1 )
  1425.         return -1;
  1426.     if( m_dwStyle & MULTISELECTION )
  1427.     {
  1428.         // Multiple selection enabled. Search for the next item with the selected flag.
  1429.         for( int i = nPreviousSelected + 1; i < (int)m_Items.GetSize(); ++i )
  1430.         {
  1431.             DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1432.             if( pItem->bSelected )
  1433.                 return i;
  1434.         }
  1435.         return -1;
  1436.     }
  1437.     else
  1438.     {
  1439.         // Single selection
  1440.         return m_nSelected;
  1441.     }
  1442. }
  1443. //--------------------------------------------------------------------------------------
  1444. void CDXUTListBox::SelectItem( int nNewIndex )
  1445. {
  1446.     // If no item exists, do nothing.
  1447.     if( m_Items.GetSize() == 0 )
  1448.         return;
  1449.     int nOldSelected = m_nSelected;
  1450.     // Adjust m_nSelected
  1451.     m_nSelected = nNewIndex;
  1452.     // Perform capping
  1453.     if( m_nSelected < 0 )
  1454.         m_nSelected = 0;
  1455.     if( m_nSelected >= (int)m_Items.GetSize() )
  1456.         m_nSelected = m_Items.GetSize() - 1;
  1457.     if( nOldSelected != m_nSelected )
  1458.     {
  1459.         if( m_dwStyle & MULTISELECTION )
  1460.         {
  1461.             m_Items[m_nSelected]->bSelected = true;
  1462.         }
  1463.         // Update selection start
  1464.         m_nSelStart = m_nSelected;
  1465.         // Adjust scroll bar
  1466.         m_ScrollBar.ShowItem( m_nSelected );
  1467.     }
  1468.     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1469. }
  1470. //--------------------------------------------------------------------------------------
  1471. bool CDXUTListBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1472. {
  1473.     if( !m_bEnabled || !m_bVisible )
  1474.         return false;
  1475.     // Let the scroll bar have a chance to handle it first
  1476.     if( m_ScrollBar.HandleKeyboard( uMsg, wParam, lParam ) )
  1477.         return true;
  1478.     switch( uMsg )
  1479.     {
  1480.         case WM_KEYDOWN:
  1481.             switch( wParam )
  1482.             {
  1483.                 case VK_UP:
  1484.                 case VK_DOWN:
  1485.                 case VK_NEXT:
  1486.                 case VK_PRIOR:
  1487.                 case VK_HOME:
  1488.                 case VK_END:
  1489.                 {
  1490.                     // If no item exists, do nothing.
  1491.                     if( m_Items.GetSize() == 0 )
  1492.                         return true;
  1493.                     int nOldSelected = m_nSelected;
  1494.                     // Adjust m_nSelected
  1495.                     switch( wParam )
  1496.                     {
  1497.                         case VK_UP: --m_nSelected; break;
  1498.                         case VK_DOWN: ++m_nSelected; break;
  1499.                         case VK_NEXT: m_nSelected += m_ScrollBar.GetPageSize() - 1; break;
  1500.                         case VK_PRIOR: m_nSelected -= m_ScrollBar.GetPageSize() - 1; break;
  1501.                         case VK_HOME: m_nSelected = 0; break;
  1502.                         case VK_END: m_nSelected = m_Items.GetSize() - 1; break;
  1503.                     }
  1504.                     // Perform capping
  1505.                     if( m_nSelected < 0 )
  1506.                         m_nSelected = 0;
  1507.                     if( m_nSelected >= (int)m_Items.GetSize() )
  1508.                         m_nSelected = m_Items.GetSize() - 1;
  1509.                     if( nOldSelected != m_nSelected )
  1510.                     {
  1511.                         if( m_dwStyle & MULTISELECTION )
  1512.                         {
  1513.                             // Multiple selection
  1514.                             // Clear all selection
  1515.                             for( int i = 0; i < (int)m_Items.GetSize(); ++i )
  1516.                             {
  1517.                                 DXUTListBoxItem *pItem = m_Items[i];
  1518.                                 pItem->bSelected = false;
  1519.                             }
  1520.                             if( GetKeyState( VK_SHIFT ) < 0 )
  1521.                             {
  1522.                                 // Select all items from m_nSelStart to
  1523.                                 // m_nSelected
  1524.                                 int nEnd = __max( m_nSelStart, m_nSelected );
  1525.                                 for( int n = __min( m_nSelStart, m_nSelected ); n <= nEnd; ++n )
  1526.                                     m_Items[n]->bSelected = true;
  1527.                             }
  1528.                             else
  1529.                             {
  1530.                                 m_Items[m_nSelected]->bSelected = true;
  1531.                                 // Update selection start
  1532.                                 m_nSelStart = m_nSelected;
  1533.                             }
  1534.                         } else
  1535.                             m_nSelStart = m_nSelected;
  1536.                         // Adjust scroll bar
  1537.                         m_ScrollBar.ShowItem( m_nSelected );
  1538.                         // Send notification
  1539.                         m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1540.                     }
  1541.                     return true;
  1542.                 }
  1543.                 // Space is the hotkey for double-clicking an item.
  1544.                 //
  1545.                 case VK_SPACE:
  1546.                     m_pDialog->SendEvent( EVENT_LISTBOX_ITEM_DBLCLK, true, this );
  1547.                     return true;
  1548.             }
  1549.             break;
  1550.     }
  1551.     return false;
  1552. }
  1553. //--------------------------------------------------------------------------------------
  1554. bool CDXUTListBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  1555. {
  1556.     if( !m_bEnabled || !m_bVisible )
  1557.         return false;
  1558.     // First acquire focus
  1559.     if( WM_LBUTTONDOWN == uMsg )
  1560.         if( !m_bHasFocus )
  1561.             m_pDialog->RequestFocus( this );
  1562.     // Let the scroll bar handle it first.
  1563.     if( m_ScrollBar.HandleMouse( uMsg, pt, wParam, lParam ) )
  1564.         return true;
  1565.     switch( uMsg )
  1566.     {
  1567.         case WM_LBUTTONDOWN:
  1568.         case WM_LBUTTONDBLCLK:
  1569.             // Check for clicks in the text area
  1570.             if( m_Items.GetSize() > 0 && PtInRect( &m_rcSelection, pt ) )
  1571.             {
  1572.                 // Compute the index of the clicked item
  1573.                 int nClicked;
  1574.                 if( m_nTextHeight )
  1575.                     nClicked = m_ScrollBar.GetTrackPos() + ( pt.y - m_rcText.top ) / m_nTextHeight;
  1576.                 else
  1577.                     nClicked = -1;
  1578.                 // Only proceed if the click falls on top of an item.
  1579.                 if( nClicked >= m_ScrollBar.GetTrackPos() &&
  1580.                     nClicked < (int)m_Items.GetSize() &&
  1581.                     nClicked < m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() )
  1582.                 {
  1583.                     SetCapture( DXUTGetHWND() );
  1584.                     m_bDrag = true;
  1585.                     // If this is a double click, fire off an event and exit
  1586.                     // since the first click would have taken care of the selection
  1587.                     // updating.
  1588.                     if( uMsg == WM_LBUTTONDBLCLK )
  1589.                     {
  1590.                         m_pDialog->SendEvent( EVENT_LISTBOX_ITEM_DBLCLK, true, this );
  1591.                         return true;
  1592.                     }
  1593.                     m_nSelected = nClicked;
  1594.                     if( !( wParam & MK_SHIFT ) )
  1595.                         m_nSelStart = m_nSelected;
  1596.                     // If this is a multi-selection listbox, update per-item
  1597.                     // selection data.
  1598.                     if( m_dwStyle & MULTISELECTION )
  1599.                     {
  1600.                         // Determine behavior based on the state of Shift and Ctrl
  1601.                         DXUTListBoxItem *pSelItem = m_Items.GetAt( m_nSelected );
  1602.                         if( ( wParam & (MK_SHIFT|MK_CONTROL) ) == MK_CONTROL )
  1603.                         {
  1604.                             // Control click. Reverse the selection of this item.
  1605.                             pSelItem->bSelected = !pSelItem->bSelected;
  1606.                         } else
  1607.                         if( ( wParam & (MK_SHIFT|MK_CONTROL) ) == MK_SHIFT )
  1608.                         {
  1609.                             // Shift click. Set the selection for all items
  1610.                             // from last selected item to the current item.
  1611.                             // Clear everything else.
  1612.                             int nBegin = __min( m_nSelStart, m_nSelected );
  1613.                             int nEnd = __max( m_nSelStart, m_nSelected );
  1614.                             for( int i = 0; i < nBegin; ++i )
  1615.                             {
  1616.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1617.                                 pItem->bSelected = false;
  1618.                             }
  1619.                             for( int i = nEnd + 1; i < (int)m_Items.GetSize(); ++i )
  1620.                             {
  1621.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1622.                                 pItem->bSelected = false;
  1623.                             }
  1624.                             for( int i = nBegin; i <= nEnd; ++i )
  1625.                             {
  1626.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1627.                                 pItem->bSelected = true;
  1628.                             }
  1629.                         } else
  1630.                         if( ( wParam & (MK_SHIFT|MK_CONTROL) ) == ( MK_SHIFT|MK_CONTROL ) )
  1631.                         {
  1632.                             // Control-Shift-click.
  1633.                             // The behavior is:
  1634.                             //   Set all items from m_nSelStart to m_nSelected to
  1635.                             //     the same state as m_nSelStart, not including m_nSelected.
  1636.                             //   Set m_nSelected to selected.
  1637.                             int nBegin = __min( m_nSelStart, m_nSelected );
  1638.                             int nEnd = __max( m_nSelStart, m_nSelected );
  1639.                             // The two ends do not need to be set here.
  1640.                             bool bLastSelected = m_Items.GetAt( m_nSelStart )->bSelected;
  1641.                             for( int i = nBegin + 1; i < nEnd; ++i )
  1642.                             {
  1643.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1644.                                 pItem->bSelected = bLastSelected;
  1645.                             }
  1646.                             pSelItem->bSelected = true;
  1647.                             // Restore m_nSelected to the previous value
  1648.                             // This matches the Windows behavior
  1649.                             m_nSelected = m_nSelStart;
  1650.                         } else
  1651.                         {
  1652.                             // Simple click.  Clear all items and select the clicked
  1653.                             // item.
  1654.                             for( int i = 0; i < (int)m_Items.GetSize(); ++i )
  1655.                             {
  1656.                                 DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1657.                                 pItem->bSelected = false;
  1658.                             }
  1659.                             pSelItem->bSelected = true;
  1660.                         }
  1661.                     }  // End of multi-selection case
  1662.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1663.                 }
  1664.                 return true;
  1665.             }
  1666.             break;
  1667.         case WM_LBUTTONUP:
  1668.         {
  1669.             ReleaseCapture();
  1670.             m_bDrag = false;
  1671.             if( m_nSelected != -1 )
  1672.             {
  1673.                 // Set all items between m_nSelStart and m_nSelected to
  1674.                 // the same state as m_nSelStart
  1675.                 int nEnd = __max( m_nSelStart, m_nSelected );
  1676.                 for( int n = __min( m_nSelStart, m_nSelected ) + 1; n < nEnd; ++n )
  1677.                     m_Items[n]->bSelected = m_Items[m_nSelStart]->bSelected;
  1678.                 m_Items[m_nSelected]->bSelected = m_Items[m_nSelStart]->bSelected;
  1679.                 // If m_nSelStart and m_nSelected are not the same,
  1680.                 // the user has dragged the mouse to make a selection.
  1681.                 // Notify the application of this.
  1682.                 if( m_nSelStart != m_nSelected )
  1683.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1684.                 m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION_END, true, this );
  1685.             }
  1686.             return false;
  1687.         }
  1688.         case WM_MOUSEMOVE:
  1689.             if( m_bDrag )
  1690.             {
  1691.                 // Compute the index of the item below cursor
  1692.                 int nItem;
  1693.                 if( m_nTextHeight )
  1694.                     nItem = m_ScrollBar.GetTrackPos() + ( pt.y - m_rcText.top ) / m_nTextHeight;
  1695.                 else
  1696.                     nItem = -1;
  1697.                 // Only proceed if the cursor is on top of an item.
  1698.                 if( nItem >= (int)m_ScrollBar.GetTrackPos() &&
  1699.                     nItem < (int)m_Items.GetSize() &&
  1700.                     nItem < m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() )
  1701.                 {
  1702.                     m_nSelected = nItem;
  1703.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1704.                 } else
  1705.                 if( nItem < (int)m_ScrollBar.GetTrackPos() )
  1706.                 {
  1707.                     // User drags the mouse above window top
  1708.                     m_ScrollBar.Scroll( -1 );
  1709.                     m_nSelected = m_ScrollBar.GetTrackPos();
  1710.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1711.                 } else
  1712.                 if( nItem >= m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() )
  1713.                 {
  1714.                     // User drags the mouse below window bottom
  1715.                     m_ScrollBar.Scroll( 1 );
  1716.                     m_nSelected = __min( (int)m_Items.GetSize(), m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() ) - 1;
  1717.                     m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this );
  1718.                 }
  1719.             }
  1720.             break;
  1721.         case WM_MOUSEWHEEL:
  1722.         {
  1723.             UINT uLines;
  1724.             SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &uLines, 0 );
  1725.             int nScrollAmount = int((short)HIWORD(wParam)) / WHEEL_DELTA * uLines;
  1726.             m_ScrollBar.Scroll( -nScrollAmount );
  1727.             return true;
  1728.         }
  1729.     }
  1730.     return false;
  1731. }
  1732. //--------------------------------------------------------------------------------------
  1733. bool CDXUTListBox::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1734. {
  1735.     if( WM_CAPTURECHANGED == uMsg )
  1736.     {
  1737.         // The application just lost mouse capture. We may not have gotten
  1738.         // the WM_MOUSEUP message, so reset m_bDrag here.
  1739.         if( (HWND)lParam != DXUTGetHWND() )
  1740.             m_bDrag = false;
  1741.     }
  1742.     return false;
  1743. }
  1744. //--------------------------------------------------------------------------------------
  1745. void CDXUTListBox::Render( IDirect3DDevice9* pd3dDevice, float fElapsedTime )
  1746. {
  1747.     if( m_bVisible == false )
  1748.         return;
  1749.     CDXUTElement* pElement = m_Elements.GetAt( 0 );
  1750.     pElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  1751.     pElement->FontColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  1752.     CDXUTElement* pSelElement = m_Elements.GetAt( 1 );
  1753.     pSelElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  1754.     pSelElement->FontColor.Blend( DXUT_STATE_NORMAL, fElapsedTime );
  1755.     m_pDialog->DrawSprite( pElement, &m_rcBoundingBox );
  1756.     // Render the text
  1757.     if( m_Items.GetSize() > 0 )
  1758.     {
  1759.         // Find out the height of a single line of text
  1760.         RECT rc = m_rcText;
  1761.         RECT rcSel = m_rcSelection;
  1762.         rc.bottom = rc.top + m_pDialog->GetManager()->GetFontNode( pElement->iFont )->nHeight;
  1763.         // Update the line height formation
  1764.         m_nTextHeight = rc.bottom - rc.top;
  1765.         static bool bSBInit;
  1766.         if( !bSBInit )
  1767.         {
  1768.             // Update the page size of the scroll bar
  1769.             if( m_nTextHeight )
  1770.                 m_ScrollBar.SetPageSize( RectHeight( m_rcText ) / m_nTextHeight );
  1771.             else
  1772.                 m_ScrollBar.SetPageSize( RectHeight( m_rcText ) );
  1773.             bSBInit = true;
  1774.         }
  1775.         rc.right = m_rcText.right;
  1776.         for( int i = m_ScrollBar.GetTrackPos(); i < (int)m_Items.GetSize(); ++i )
  1777.         {
  1778.             if( rc.bottom > m_rcText.bottom )
  1779.                 break;
  1780.             DXUTListBoxItem *pItem = m_Items.GetAt( i );
  1781.             // Determine if we need to render this item with the
  1782.             // selected element.
  1783.             bool bSelectedStyle = false;
  1784.             if( !( m_dwStyle & MULTISELECTION ) && i == m_nSelected )
  1785.                 bSelectedStyle = true;
  1786.             else
  1787.             if( m_dwStyle & MULTISELECTION )
  1788.             {
  1789.                 if( m_bDrag &&
  1790.                     ( ( i >= m_nSelected && i < m_nSelStart ) ||
  1791.                       ( i <= m_nSelected && i > m_nSelStart ) ) )
  1792.                     bSelectedStyle = m_Items[m_nSelStart]->bSelected;
  1793.                 else
  1794.                 if( pItem->bSelected )
  1795.                     bSelectedStyle = true;
  1796.             }
  1797.             if( bSelectedStyle )
  1798.             {
  1799.                 rcSel.top = rc.top; rcSel.bottom = rc.bottom;
  1800.                 m_pDialog->DrawSprite( pSelElement, &rcSel );
  1801.                 m_pDialog->DrawText( pItem->strText, pSelElement, &rc );
  1802.             }
  1803.             else
  1804.                 m_pDialog->DrawText( pItem->strText, pElement, &rc );
  1805.             OffsetRect( &rc, 0, m_nTextHeight );
  1806.         }
  1807.     }
  1808.     // Render the scroll bar
  1809.     m_ScrollBar.Render( pd3dDevice, fElapsedTime );
  1810. }
  1811. // Static member initialization
  1812. HINSTANCE CUniBuffer::s_hDll = NULL;
  1813. HRESULT (WINAPI *CUniBuffer::_ScriptApplyDigitSubstitution)( const SCRIPT_DIGITSUBSTITUTE*, SCRIPT_CONTROL*, SCRIPT_STATE* ) = Dummy_ScriptApplyDigitSubstitution;
  1814. HRESULT (WINAPI *CUniBuffer::_ScriptStringAnalyse)( HDC, const void *, int, int, int, DWORD, int, SCRIPT_CONTROL*, SCRIPT_STATE*, const int*, SCRIPT_TABDEF*, const BYTE*, SCRIPT_STRING_ANALYSIS* ) = Dummy_ScriptStringAnalyse;
  1815. HRESULT (WINAPI *CUniBuffer::_ScriptStringCPtoX)( SCRIPT_STRING_ANALYSIS, int, BOOL, int* ) = Dummy_ScriptStringCPtoX;
  1816. HRESULT (WINAPI *CUniBuffer::_ScriptStringXtoCP)( SCRIPT_STRING_ANALYSIS, int, int*, int* ) = Dummy_ScriptStringXtoCP;
  1817. HRESULT (WINAPI *CUniBuffer::_ScriptStringFree)( SCRIPT_STRING_ANALYSIS* ) = Dummy_ScriptStringFree;
  1818. const SCRIPT_LOGATTR* (WINAPI *CUniBuffer::_ScriptString_pLogAttr)( SCRIPT_STRING_ANALYSIS ) = Dummy_ScriptString_pLogAttr;
  1819. const int* (WINAPI *CUniBuffer::_ScriptString_pcOutChars)( SCRIPT_STRING_ANALYSIS ) = Dummy_ScriptString_pcOutChars;
  1820. bool CDXUTEditBox::s_bHideCaret;   // If true, we don't render the caret.
  1821. //--------------------------------------------------------------------------------------
  1822. // CDXUTEditBox class
  1823. //--------------------------------------------------------------------------------------
  1824. // When scrolling, EDITBOX_SCROLLEXTENT is reciprocal of the amount to scroll.
  1825. // If EDITBOX_SCROLLEXTENT = 4, then we scroll 1/4 of the control each time.
  1826. #define EDITBOX_SCROLLEXTENT 4
  1827. //--------------------------------------------------------------------------------------
  1828. CDXUTEditBox::CDXUTEditBox( CDXUTDialog *pDialog )
  1829. {
  1830.     m_Type = DXUT_CONTROL_EDITBOX;
  1831.     m_pDialog = pDialog;
  1832.     m_nBorder = 5;  // Default border width
  1833.     m_nSpacing = 4;  // Default spacing
  1834.     m_bCaretOn = true;
  1835.     m_dfBlink = GetCaretBlinkTime() * 0.001f;
  1836.     m_dfLastBlink = DXUTGetGlobalTimer()->GetAbsoluteTime();
  1837.     s_bHideCaret = false;
  1838.     m_nFirstVisible = 0;
  1839.     m_TextColor = D3DCOLOR_ARGB( 255, 16, 16, 16 );
  1840.     m_SelTextColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
  1841.     m_SelBkColor = D3DCOLOR_ARGB( 255, 40, 50, 92 );
  1842.     m_CaretColor = D3DCOLOR_ARGB( 255, 0, 0, 0 );
  1843.     m_nCaret = m_nSelStart = 0;
  1844.     m_bInsertMode = true;
  1845.     m_bMouseDrag = false;
  1846. }
  1847. //--------------------------------------------------------------------------------------
  1848. CDXUTEditBox::~CDXUTEditBox()
  1849. {
  1850. }
  1851. //--------------------------------------------------------------------------------------
  1852. // PlaceCaret: Set the caret to a character position, and adjust the scrolling if
  1853. //             necessary.
  1854. //--------------------------------------------------------------------------------------
  1855. void CDXUTEditBox::PlaceCaret( int nCP )
  1856. {
  1857.     assert( nCP >= 0 && nCP <= m_Buffer.GetTextSize() );
  1858.     m_nCaret = nCP;
  1859.     // Obtain the X offset of the character.
  1860.     int nX1st, nX, nX2;
  1861.     m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st );  // 1st visible char
  1862.     m_Buffer.CPtoX( nCP, FALSE, &nX );  // LEAD
  1863.     // If nCP is the NULL terminator, get the leading edge instead of trailing.
  1864.     if( nCP == m_Buffer.GetTextSize() )
  1865.         nX2 = nX;
  1866.     else
  1867.         m_Buffer.CPtoX( nCP, TRUE, &nX2 );  // TRAIL
  1868.     // If the left edge of the char is smaller than the left edge of the 1st visible char,
  1869.     // we need to scroll left until this char is visible.
  1870.     if( nX < nX1st )
  1871.     {
  1872.         // Simply make the first visible character the char at the new caret position.
  1873.         m_nFirstVisible = nCP;
  1874.     }
  1875.     else
  1876.     // If the right of the character is bigger than the offset of the control's
  1877.     // right edge, we need to scroll right to this character.
  1878.     if( nX2 > nX1st + RectWidth( m_rcText ) )
  1879.     {
  1880.         // Compute the X of the new left-most pixel
  1881.         int nXNewLeft = nX2 - RectWidth( m_rcText );
  1882.         // Compute the char position of this character
  1883.         int nCPNew1st, nNewTrail;
  1884.         m_Buffer.XtoCP( nXNewLeft, &nCPNew1st, &nNewTrail );
  1885.         // If this coordinate is not on a character border,
  1886.         // start from the next character so that the caret
  1887.         // position does not fall outside the text rectangle.
  1888.         int nXNew1st;
  1889.         m_Buffer.CPtoX( nCPNew1st, FALSE, &nXNew1st );
  1890.         if( nXNew1st < nXNewLeft )
  1891.             ++nCPNew1st;
  1892.         m_nFirstVisible = nCPNew1st;
  1893.     }
  1894. }
  1895. //--------------------------------------------------------------------------------------
  1896. void CDXUTEditBox::ClearText()
  1897. {
  1898.     m_Buffer.Clear();
  1899.     m_nFirstVisible = 0;
  1900.     PlaceCaret( 0 );
  1901.     m_nSelStart = 0;
  1902. }
  1903. //--------------------------------------------------------------------------------------
  1904. void CDXUTEditBox::SetText( LPCWSTR wszText, bool bSelected )
  1905. {
  1906.     assert( wszText != NULL );
  1907.     m_Buffer.SetText( wszText );
  1908.     m_nFirstVisible = 0;
  1909.     // Move the caret to the end of the text
  1910.     PlaceCaret( m_Buffer.GetTextSize() );
  1911.     m_nSelStart = bSelected ? 0 : m_nCaret;
  1912. }
  1913. //--------------------------------------------------------------------------------------
  1914. HRESULT CDXUTEditBox::GetTextCopy( LPWSTR strDest, UINT bufferCount )
  1915. {
  1916.     assert( strDest );
  1917.     StringCchCopy( strDest, bufferCount, m_Buffer.GetBuffer() );
  1918.     return S_OK;
  1919. }
  1920. //--------------------------------------------------------------------------------------
  1921. void CDXUTEditBox::DeleteSelectionText()
  1922. {
  1923.     int nFirst = __min( m_nCaret, m_nSelStart );
  1924.     int nLast = __max( m_nCaret, m_nSelStart );
  1925.     // Update caret and selection
  1926.     PlaceCaret( nFirst );
  1927.     m_nSelStart = m_nCaret;
  1928.     // Remove the characters
  1929.     for( int i = nFirst; i < nLast; ++i )
  1930.         m_Buffer.RemoveChar( nFirst );
  1931. }
  1932. //--------------------------------------------------------------------------------------
  1933. void CDXUTEditBox::UpdateRects()
  1934. {
  1935.     CDXUTControl::UpdateRects();
  1936.     // Update the text rectangle
  1937.     m_rcText = m_rcBoundingBox;
  1938.     // First inflate by m_nBorder to compute render rects
  1939.     InflateRect( &m_rcText, -m_nBorder, -m_nBorder );
  1940.     // Update the render rectangles
  1941.     m_rcRender[0] = m_rcText;
  1942.     SetRect( &m_rcRender[1], m_rcBoundingBox.left, m_rcBoundingBox.top, m_rcText.left, m_rcText.top );
  1943.     SetRect( &m_rcRender[2], m_rcText.left, m_rcBoundingBox.top, m_rcText.right, m_rcText.top );
  1944.     SetRect( &m_rcRender[3], m_rcText.right, m_rcBoundingBox.top, m_rcBoundingBox.right, m_rcText.top );
  1945.     SetRect( &m_rcRender[4], m_rcBoundingBox.left, m_rcText.top, m_rcText.left, m_rcText.bottom );
  1946.     SetRect( &m_rcRender[5], m_rcText.right, m_rcText.top, m_rcBoundingBox.right, m_rcText.bottom );
  1947.     SetRect( &m_rcRender[6], m_rcBoundingBox.left, m_rcText.bottom, m_rcText.left, m_rcBoundingBox.bottom );
  1948.     SetRect( &m_rcRender[7], m_rcText.left, m_rcText.bottom, m_rcText.right, m_rcBoundingBox.bottom );
  1949.     SetRect( &m_rcRender[8], m_rcText.right, m_rcText.bottom, m_rcBoundingBox.right, m_rcBoundingBox.bottom );
  1950.     // Inflate further by m_nSpacing
  1951.     InflateRect( &m_rcText, -m_nSpacing, -m_nSpacing );
  1952. }
  1953. void CDXUTEditBox::CopyToClipboard()
  1954. {
  1955.     // Copy the selection text to the clipboard
  1956.     if( m_nCaret != m_nSelStart && OpenClipboard( NULL ) )
  1957.     {
  1958.         EmptyClipboard();
  1959.         HGLOBAL hBlock = GlobalAlloc( GMEM_MOVEABLE, sizeof(WCHAR) * ( m_Buffer.GetTextSize() + 1 ) );
  1960.         if( hBlock )
  1961.         {
  1962.             WCHAR *pwszText = (WCHAR*)GlobalLock( hBlock );
  1963.             if( pwszText )
  1964.             {
  1965.                 int nFirst = __min( m_nCaret, m_nSelStart );
  1966.                 int nLast = __max( m_nCaret, m_nSelStart );
  1967.                 if( nLast - nFirst > 0 )
  1968.                     CopyMemory( pwszText, m_Buffer.GetBuffer() + nFirst, (nLast - nFirst) * sizeof(WCHAR) );
  1969.                 pwszText[nLast - nFirst] = L'';  // Terminate it
  1970.                 GlobalUnlock( hBlock );
  1971.             }
  1972.             SetClipboardData( CF_UNICODETEXT, hBlock );
  1973.         }
  1974.         CloseClipboard();
  1975.         // We must not free the object until CloseClipboard is called.
  1976.         if( hBlock )
  1977.             GlobalFree( hBlock );
  1978.     }
  1979. }
  1980. void CDXUTEditBox::PasteFromClipboard()
  1981. {
  1982.     DeleteSelectionText();
  1983.     if( OpenClipboard( NULL ) )
  1984.     {
  1985.         HANDLE handle = GetClipboardData( CF_UNICODETEXT );
  1986.         if( handle )
  1987.         {
  1988.             // Convert the ANSI string to Unicode, then
  1989.             // insert to our buffer.
  1990.             WCHAR *pwszText = (WCHAR*)GlobalLock( handle );
  1991.             if( pwszText )
  1992.             {
  1993.                 // Copy all characters up to null.
  1994.                 if( m_Buffer.InsertString( m_nCaret, pwszText ) )
  1995.                     PlaceCaret( m_nCaret + lstrlenW( pwszText ) );
  1996.                 m_nSelStart = m_nCaret;
  1997.                 GlobalUnlock( handle );
  1998.             }
  1999.         }
  2000.         CloseClipboard();
  2001.     }
  2002. }
  2003. //--------------------------------------------------------------------------------------
  2004. bool CDXUTEditBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam )
  2005. {
  2006.     if( !m_bEnabled || !m_bVisible )
  2007.         return false;
  2008.     bool bHandled = false;
  2009.     switch( uMsg )
  2010.     {
  2011.         case WM_KEYDOWN:
  2012.         {
  2013.             switch( wParam )
  2014.             {
  2015.                 case VK_TAB:
  2016.                     // We don't process Tab in case keyboard input is enabled and the user
  2017.                     // wishes to Tab to other controls.
  2018.                     break;
  2019.                 case VK_HOME:
  2020.                     PlaceCaret( 0 );
  2021.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  2022.                         // Shift is not down. Update selection
  2023.                         // start along with the caret.
  2024.                         m_nSelStart = m_nCaret;
  2025.                     ResetCaretBlink();
  2026.                     bHandled = true;
  2027.                     break;
  2028.                 case VK_END:
  2029.                     PlaceCaret( m_Buffer.GetTextSize() );
  2030.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  2031.                         // Shift is not down. Update selection
  2032.                         // start along with the caret.
  2033.                         m_nSelStart = m_nCaret;
  2034.                     ResetCaretBlink();
  2035.                     bHandled = true;
  2036.                     break;
  2037.                 case VK_INSERT:
  2038.                     if( GetKeyState( VK_CONTROL ) < 0 )
  2039.                     {
  2040.                         // Control Insert. Copy to clipboard
  2041.                         CopyToClipboard();
  2042.                     } else
  2043.                     if( GetKeyState( VK_SHIFT ) < 0 )
  2044.                     {
  2045.                         // Shift Insert. Paste from clipboard
  2046.                         PasteFromClipboard();
  2047.                     } else
  2048.                     {
  2049.                         // Toggle caret insert mode
  2050.                         m_bInsertMode = !m_bInsertMode;
  2051.                     }
  2052.                     break;
  2053.                 case VK_DELETE:
  2054.                     // Check if there is a text selection.
  2055.                     if( m_nCaret != m_nSelStart )
  2056.                     {
  2057.                         DeleteSelectionText();
  2058.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  2059.                     }
  2060.                     else
  2061.                     {
  2062.                         // Deleting one character
  2063.                         if( m_Buffer.RemoveChar( m_nCaret ) )
  2064.                             m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  2065.                     }
  2066.                     ResetCaretBlink();
  2067.                     bHandled = true;
  2068.                     break;
  2069.                 case VK_LEFT:
  2070.                     if( GetKeyState( VK_CONTROL ) < 0 )
  2071.                     {
  2072.                         // Control is down. Move the caret to a new item
  2073.                         // instead of a character.
  2074.                         m_Buffer.GetPriorItemPos( m_nCaret, &m_nCaret );
  2075.                         PlaceCaret( m_nCaret );
  2076.                     }
  2077.                     else
  2078.                     if( m_nCaret > 0 )
  2079.                         PlaceCaret( m_nCaret - 1 );
  2080.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  2081.                         // Shift is not down. Update selection
  2082.                         // start along with the caret.
  2083.                         m_nSelStart = m_nCaret;
  2084.                     ResetCaretBlink();
  2085.                     bHandled = true;
  2086.                     break;
  2087.                 case VK_RIGHT:
  2088.                     if( GetKeyState( VK_CONTROL ) < 0 )
  2089.                     {
  2090.                         // Control is down. Move the caret to a new item
  2091.                         // instead of a character.
  2092.                         m_Buffer.GetNextItemPos( m_nCaret, &m_nCaret );
  2093.                         PlaceCaret( m_nCaret );
  2094.                     }
  2095.                     else
  2096.                     if( m_nCaret < m_Buffer.GetTextSize() )
  2097.                         PlaceCaret( m_nCaret + 1 );
  2098.                     if( GetKeyState( VK_SHIFT ) >= 0 )
  2099.                         // Shift is not down. Update selection
  2100.                         // start along with the caret.
  2101.                         m_nSelStart = m_nCaret;
  2102.                     ResetCaretBlink();
  2103.                     bHandled = true;
  2104.                     break;
  2105.                 case VK_UP:
  2106.                 case VK_DOWN:
  2107.                     // Trap up and down arrows so that the dialog
  2108.                     // does not switch focus to another control.
  2109.                     bHandled = true;
  2110.                     break;
  2111.                 default:
  2112.                     bHandled = wParam != VK_ESCAPE;  // Let the application handle Esc.
  2113.             }
  2114.         }
  2115.     }
  2116.     return bHandled;
  2117. }
  2118. //--------------------------------------------------------------------------------------
  2119. bool CDXUTEditBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam )
  2120. {
  2121.     if( !m_bEnabled || !m_bVisible )
  2122.         return false;
  2123.     switch( uMsg )
  2124.     {
  2125.         case WM_LBUTTONDOWN:
  2126.         case WM_LBUTTONDBLCLK:
  2127.         {
  2128.             if( !m_bHasFocus )
  2129.                 m_pDialog->RequestFocus( this );
  2130.             if( !ContainsPoint( pt ) )
  2131.                 return false;
  2132.             m_bMouseDrag = true;
  2133.             SetCapture( DXUTGetHWND() );
  2134.             // Determine the character corresponding to the coordinates.
  2135.             int nCP, nTrail, nX1st;
  2136.             m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st );  // X offset of the 1st visible char
  2137.             if( SUCCEEDED( m_Buffer.XtoCP( pt.x - m_rcText.left + nX1st, &nCP, &nTrail ) ) )
  2138.             {
  2139.                 // Cap at the NULL character.
  2140.                 if( nTrail && nCP < m_Buffer.GetTextSize() )
  2141.                     PlaceCaret( nCP + 1 );
  2142.                 else
  2143.                     PlaceCaret( nCP );
  2144.                 m_nSelStart = m_nCaret;
  2145.                 ResetCaretBlink();
  2146.             }
  2147.             return true;
  2148.         }
  2149.         case WM_LBUTTONUP:
  2150.             ReleaseCapture();
  2151.             m_bMouseDrag = false;
  2152.             break;
  2153.         case WM_MOUSEMOVE:
  2154.             if( m_bMouseDrag )
  2155.             {
  2156.                 // Determine the character corresponding to the coordinates.
  2157.                 int nCP, nTrail, nX1st;
  2158.                 m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st );  // X offset of the 1st visible char
  2159.                 if( SUCCEEDED( m_Buffer.XtoCP( pt.x - m_rcText.left + nX1st, &nCP, &nTrail ) ) )
  2160.                 {
  2161.                     // Cap at the NULL character.
  2162.                     if( nTrail && nCP < m_Buffer.GetTextSize() )
  2163.                         PlaceCaret( nCP + 1 );
  2164.                     else
  2165.                         PlaceCaret( nCP );
  2166.                 }
  2167.             }
  2168.             break;
  2169.     }
  2170.     return false;
  2171. }
  2172. //--------------------------------------------------------------------------------------
  2173. void CDXUTEditBox::OnFocusIn()
  2174. {
  2175.     CDXUTControl::OnFocusIn();
  2176.     ResetCaretBlink();
  2177. }
  2178. //--------------------------------------------------------------------------------------
  2179. bool CDXUTEditBox::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  2180. {
  2181.     if( !m_bEnabled || !m_bVisible )
  2182.         return false;
  2183.     switch( uMsg )
  2184.     {
  2185.         // Make sure that while editing, the keyup and keydown messages associated with 
  2186.         // WM_CHAR messages don't go to any non-focused controls or cameras
  2187.         case WM_KEYUP:
  2188.         case WM_KEYDOWN:
  2189.             return true;
  2190.         case WM_CHAR:
  2191.         {
  2192.             switch( (WCHAR)wParam )
  2193.             {
  2194.                 // Backspace
  2195.                 case VK_BACK:
  2196.                 {
  2197.                     // If there's a selection, treat this
  2198.                     // like a delete key.
  2199.                     if( m_nCaret != m_nSelStart )
  2200.                     {
  2201.                         DeleteSelectionText();
  2202.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  2203.                     }
  2204.                     else
  2205.                     if( m_nCaret > 0 )
  2206.                     {
  2207.                         // Move the caret, then delete the char.
  2208.                         PlaceCaret( m_nCaret - 1 );
  2209.                         m_nSelStart = m_nCaret;
  2210.                         m_Buffer.RemoveChar( m_nCaret );
  2211.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  2212.                     }
  2213.                     ResetCaretBlink();
  2214.                     break;
  2215.                 }
  2216.                 case 24:        // Ctrl-X Cut
  2217.                 case VK_CANCEL: // Ctrl-C Copy
  2218.                 {
  2219.                     CopyToClipboard();
  2220.                     // If the key is Ctrl-X, delete the selection too.
  2221.                     if( (WCHAR)wParam == 24 )
  2222.                     {
  2223.                         DeleteSelectionText();
  2224.                         m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  2225.                     }
  2226.                     break;
  2227.                 }
  2228.                 // Ctrl-V Paste
  2229.                 case 22:
  2230.                 {
  2231.                     PasteFromClipboard();
  2232.                     m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this );
  2233.                     break;
  2234.                 }
  2235.                 // Ctrl-A Select All
  2236.                 case 1:
  2237.                     if( m_nSelStart == m_nCaret )
  2238.                     {
  2239.                         m_nSelStart = 0;
  2240.                         PlaceCaret( m_Buffer.GetTextSize() );
  2241.                     }
  2242.                     break;
  2243.                 case VK_RETURN: