Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1041 lines
29 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #define PROTECTED_THINGS_DISABLE
  8. #include "vgui/Cursor.h"
  9. #include "vgui/IInput.h"
  10. #include "vgui/ILocalize.h"
  11. #include "vgui/IScheme.h"
  12. #include "vgui/ISurface.h"
  13. #include "vgui/IPanel.h"
  14. #include "KeyValues.h"
  15. #include "vgui_controls/ComboBox.h"
  16. #include "vgui_controls/Menu.h"
  17. #include "vgui_controls/MenuItem.h"
  18. #include "vgui_controls/TextImage.h"
  19. #include <ctype.h>
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. using namespace vgui;
  23. namespace vgui
  24. {
  25. ComboBoxButton::ComboBoxButton(ComboBox *parent, const char *panelName, const char *text) : Button(parent, panelName, text)
  26. {
  27. SetButtonActivationType(ACTIVATE_ONPRESSED);
  28. }
  29. void ComboBoxButton::ApplySchemeSettings(IScheme *pScheme)
  30. {
  31. Button::ApplySchemeSettings(pScheme);
  32. SetFont(pScheme->GetFont("Marlett", IsProportional()));
  33. SetContentAlignment(Label::a_west);
  34. #ifdef OSX
  35. SetTextInset(-3, 0);
  36. #else
  37. SetTextInset(3, 0);
  38. #endif
  39. SetDefaultBorder(pScheme->GetBorder("ScrollBarButtonBorder"));
  40. // arrow changes color but the background doesnt.
  41. SetDefaultColor(GetSchemeColor("ComboBoxButton.ArrowColor", pScheme), GetSchemeColor("ComboBoxButton.BgColor", pScheme));
  42. SetArmedColor(GetSchemeColor("ComboBoxButton.ArmedArrowColor", pScheme), GetSchemeColor("ComboBoxButton.BgColor", pScheme));
  43. SetDepressedColor(GetSchemeColor("ComboBoxButton.ArmedArrowColor", pScheme), GetSchemeColor("ComboBoxButton.BgColor", pScheme));
  44. m_DisabledBgColor = GetSchemeColor("ComboBoxButton.DisabledBgColor", pScheme);
  45. }
  46. IBorder * ComboBoxButton::GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
  47. {
  48. return NULL;
  49. // return Button::GetBorder(depressed, armed, selected, keyfocus);
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Purpose: Dim the arrow on the button when exiting the box
  53. // only if the menu is closed, so let the parent handle this.
  54. //-----------------------------------------------------------------------------
  55. void ComboBoxButton::OnCursorExited()
  56. {
  57. // want the arrow to go grey when we exit the box if the menu is not open
  58. CallParentFunction(new KeyValues("CursorExited"));
  59. }
  60. } // namespace vgui
  61. vgui::Panel *ComboBox_Factory()
  62. {
  63. return new ComboBox( NULL, NULL, 5, true );
  64. }
  65. DECLARE_BUILD_FACTORY_CUSTOM( ComboBox, ComboBox_Factory );
  66. //-----------------------------------------------------------------------------
  67. // Purpose: Constructor
  68. // Input : parent - parent class
  69. // panelName
  70. // numLines - number of lines in dropdown menu
  71. // allowEdit - whether combobox is editable or not
  72. //-----------------------------------------------------------------------------
  73. ComboBox::ComboBox(Panel *parent, const char *panelName, int numLines, bool allowEdit ) : TextEntry(parent, panelName)
  74. {
  75. SetEditable(allowEdit);
  76. SetHorizontalScrolling(false); // do not scroll, always Start at the beginning of the text.
  77. // create the drop-down menu
  78. m_pDropDown = new Menu(this, NULL);
  79. m_pDropDown->AddActionSignalTarget(this);
  80. m_pDropDown->SetTypeAheadMode( Menu::TYPE_AHEAD_MODE );
  81. // button to Activate menu
  82. m_pButton = new ComboBoxButton(this, "Button", "u");
  83. m_pButton->SetCommand("ButtonClicked");
  84. m_pButton->AddActionSignalTarget(this);
  85. SetNumberOfEditLines(numLines);
  86. m_bHighlight = false;
  87. m_iDirection = Menu::DOWN;
  88. m_iOpenOffsetY = 0;
  89. m_bPreventTextChangeMessage = false;
  90. m_szBorderOverride[0] = '\0';
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose: Destructor
  94. //-----------------------------------------------------------------------------
  95. ComboBox::~ComboBox()
  96. {
  97. m_pDropDown->DeletePanel();
  98. m_pButton->DeletePanel();
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: Set the number of items in the dropdown menu.
  102. // Input : numLines - number of items in dropdown menu
  103. //-----------------------------------------------------------------------------
  104. void ComboBox::SetNumberOfEditLines( int numLines )
  105. {
  106. m_pDropDown->SetNumberOfVisibleItems( numLines );
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose: Add an item to the drop down
  110. // Input : char *itemText - name of dropdown menu item
  111. //-----------------------------------------------------------------------------
  112. int ComboBox::AddItem(const char *itemText, const KeyValues *userData)
  113. {
  114. // when the menu item is selected it will send the custom message "SetText"
  115. return m_pDropDown->AddMenuItem( itemText, new KeyValues("SetText", "text", itemText), this, userData );
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Purpose: Add an item to the drop down
  119. // Input : char *itemText - name of dropdown menu item
  120. //-----------------------------------------------------------------------------
  121. int ComboBox::AddItem(const wchar_t *itemText, const KeyValues *userData)
  122. {
  123. // add the element to the menu
  124. // when the menu item is selected it will send the custom message "SetText"
  125. KeyValues *kv = new KeyValues("SetText");
  126. kv->SetWString("text", itemText);
  127. // get an ansi version for the menuitem name
  128. char ansi[128];
  129. g_pVGuiLocalize->ConvertUnicodeToANSI(itemText, ansi, sizeof(ansi));
  130. return m_pDropDown->AddMenuItem(ansi, kv, this, userData);
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Removes a single item
  134. //-----------------------------------------------------------------------------
  135. void ComboBox::DeleteItem( int itemID )
  136. {
  137. if ( !m_pDropDown->IsValidMenuID(itemID))
  138. return;
  139. m_pDropDown->DeleteItem( itemID );
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose: Updates a current item to the drop down
  143. // Input : char *itemText - name of dropdown menu item
  144. //-----------------------------------------------------------------------------
  145. bool ComboBox::UpdateItem(int itemID, const char *itemText, const KeyValues *userData)
  146. {
  147. if ( !m_pDropDown->IsValidMenuID(itemID))
  148. return false;
  149. // when the menu item is selected it will send the custom message "SetText"
  150. m_pDropDown->UpdateMenuItem(itemID, itemText, new KeyValues("SetText", "text", itemText), userData);
  151. InvalidateLayout();
  152. return true;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: Updates a current item to the drop down
  156. // Input : wchar_t *itemText - name of dropdown menu item
  157. //-----------------------------------------------------------------------------
  158. bool ComboBox::UpdateItem(int itemID, const wchar_t *itemText, const KeyValues *userData)
  159. {
  160. if ( !m_pDropDown->IsValidMenuID(itemID))
  161. return false;
  162. // when the menu item is selected it will send the custom message "SetText"
  163. KeyValues *kv = new KeyValues("SetText");
  164. kv->SetWString("text", itemText);
  165. m_pDropDown->UpdateMenuItem(itemID, itemText, kv, userData);
  166. InvalidateLayout();
  167. return true;
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose: Updates a current item to the drop down
  171. // Input : wchar_t *itemText - name of dropdown menu item
  172. //-----------------------------------------------------------------------------
  173. bool ComboBox::IsItemIDValid( int itemID )
  174. {
  175. return m_pDropDown->IsValidMenuID(itemID);
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose:
  179. //-----------------------------------------------------------------------------
  180. void ComboBox::SetItemEnabled(const char *itemText, bool state)
  181. {
  182. m_pDropDown->SetItemEnabled(itemText, state);
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose:
  186. //-----------------------------------------------------------------------------
  187. void ComboBox::SetItemEnabled(int itemID, bool state)
  188. {
  189. m_pDropDown->SetItemEnabled(itemID, state);
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose: Remove all items from the drop down menu
  193. //-----------------------------------------------------------------------------
  194. void ComboBox::RemoveAll()
  195. {
  196. m_pDropDown->DeleteAllItems();
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose:
  200. //-----------------------------------------------------------------------------
  201. int ComboBox::GetItemCount() const
  202. {
  203. return m_pDropDown->GetItemCount();
  204. }
  205. int ComboBox::GetItemIDFromRow( int row )
  206. {
  207. // valid from [0, GetItemCount)
  208. return m_pDropDown->GetMenuID( row );
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose: Activate the item in the menu list, as if that menu item had been selected by the user
  212. // Input : itemID - itemID from AddItem in list of dropdown items
  213. //-----------------------------------------------------------------------------
  214. void ComboBox::ActivateItem(int itemID)
  215. {
  216. m_pDropDown->ActivateItem(itemID);
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Activate the item in the menu list, as if that menu item had been selected by the user
  220. // Input : itemID - itemID from AddItem in list of dropdown items
  221. //-----------------------------------------------------------------------------
  222. void ComboBox::ActivateItemByRow(int row)
  223. {
  224. m_pDropDown->ActivateItemByRow(row);
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose: Activate the item in the menu list, without sending a TextChanged message
  228. // Input : row - row to activate
  229. //-----------------------------------------------------------------------------
  230. void ComboBox::SilentActivateItemByRow(int row)
  231. {
  232. int itemID = GetItemIDFromRow( row );
  233. if ( itemID >= 0 )
  234. {
  235. SilentActivateItem( itemID );
  236. }
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose: Activate the item in the menu list, without sending a TextChanged message
  240. // Input : itemID - itemID from AddItem in list of dropdown items
  241. //-----------------------------------------------------------------------------
  242. void ComboBox::SilentActivateItem(int itemID)
  243. {
  244. m_pDropDown->SilentActivateItem(itemID);
  245. // Now manually call our set text, with a wrapper to ensure we don't send the Text Changed message
  246. wchar_t name[ 256 ];
  247. GetItemText( itemID, name, sizeof( name ) );
  248. m_bPreventTextChangeMessage = true;
  249. OnSetText( name );
  250. m_bPreventTextChangeMessage = false;
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Purpose: Allows a custom menu to be used with the combo box
  254. //-----------------------------------------------------------------------------
  255. void ComboBox::SetMenu( Menu *menu )
  256. {
  257. if ( m_pDropDown )
  258. {
  259. m_pDropDown->MarkForDeletion();
  260. }
  261. m_pDropDown = menu;
  262. if ( m_pDropDown )
  263. {
  264. m_pDropDown->SetParent( this );
  265. }
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Purpose: Layout the format of the combo box for drawing on screen
  269. //-----------------------------------------------------------------------------
  270. void ComboBox::PerformLayout()
  271. {
  272. int wide, tall;
  273. GetPaintSize(wide, tall);
  274. BaseClass::PerformLayout();
  275. HFont buttonFont = m_pButton->GetFont();
  276. int fontTall = surface()->GetFontTall( buttonFont );
  277. int buttonSize = min( tall, fontTall );
  278. int buttonY = ( ( tall - 1 ) - buttonSize ) / 2;
  279. // Some dropdown button icons in our games are wider than they are taller. We need to factor that in.
  280. int button_wide, button_tall;
  281. m_pButton->GetContentSize(button_wide, button_tall);
  282. button_wide = max( buttonSize, button_wide );
  283. m_pButton->SetBounds( wide - button_wide, buttonY, button_wide, buttonSize );
  284. if ( IsEditable() )
  285. {
  286. SetCursor(dc_ibeam);
  287. }
  288. else
  289. {
  290. SetCursor(dc_arrow);
  291. }
  292. m_pButton->SetEnabled(IsEnabled());
  293. DoMenuLayout();
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose:
  297. //-----------------------------------------------------------------------------
  298. void ComboBox::DoMenuLayout()
  299. {
  300. m_pDropDown->PositionRelativeToPanel( this, m_iDirection, m_iOpenOffsetY );
  301. // reset the width of the drop down menu to be the width of the combo box
  302. m_pDropDown->SetFixedWidth(GetWide());
  303. m_pDropDown->ForceCalculateWidth();
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: Sorts the items in the list
  307. //-----------------------------------------------------------------------------
  308. void ComboBox::SortItems( void )
  309. {
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Purpose: return the index of the last selected item
  313. //-----------------------------------------------------------------------------
  314. int ComboBox::GetActiveItem()
  315. {
  316. return m_pDropDown->GetActiveItem();
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose:
  320. //-----------------------------------------------------------------------------
  321. KeyValues *ComboBox::GetActiveItemUserData()
  322. {
  323. return m_pDropDown->GetItemUserData(GetActiveItem());
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose:
  327. //-----------------------------------------------------------------------------
  328. KeyValues *ComboBox::GetItemUserData(int itemID)
  329. {
  330. return m_pDropDown->GetItemUserData(itemID);
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Purpose: data accessor
  334. //-----------------------------------------------------------------------------
  335. void ComboBox::GetItemText( int itemID, wchar_t *text, int bufLenInBytes )
  336. {
  337. m_pDropDown->GetItemText( itemID, text, bufLenInBytes );
  338. }
  339. void ComboBox::GetItemText( int itemID, char *text, int bufLenInBytes )
  340. {
  341. m_pDropDown->GetItemText( itemID, text, bufLenInBytes );
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose:
  345. // Output : Returns true on success, false on failure.
  346. //-----------------------------------------------------------------------------
  347. bool ComboBox::IsDropdownVisible()
  348. {
  349. return m_pDropDown->IsVisible();
  350. }
  351. //-----------------------------------------------------------------------------
  352. // Purpose:
  353. // Input : *inResourceData -
  354. //-----------------------------------------------------------------------------
  355. void ComboBox::ApplySchemeSettings(IScheme *pScheme)
  356. {
  357. BaseClass::ApplySchemeSettings(pScheme);
  358. SetBorder( pScheme->GetBorder( m_szBorderOverride[0] ? m_szBorderOverride : "ComboBoxBorder" ) );
  359. }
  360. void ComboBox::ApplySettings( KeyValues *pInResourceData )
  361. {
  362. BaseClass::ApplySettings( pInResourceData );
  363. const char *pBorderOverride = pInResourceData->GetString( "border_override", NULL );
  364. if ( pBorderOverride )
  365. {
  366. V_strncpy( m_szBorderOverride, pBorderOverride, sizeof( m_szBorderOverride ) );
  367. }
  368. KeyValues *pKVButton = pInResourceData->FindKey( "Button" );
  369. if ( pKVButton && m_pButton )
  370. {
  371. m_pButton->ApplySettings( pKVButton );
  372. }
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Purpose: Set the visiblity of the drop down menu button.
  376. //-----------------------------------------------------------------------------
  377. void ComboBox::SetDropdownButtonVisible(bool state)
  378. {
  379. m_pButton->SetVisible(state);
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Purpose: overloads TextEntry MousePressed
  383. //-----------------------------------------------------------------------------
  384. void ComboBox::OnMousePressed(MouseCode code)
  385. {
  386. if ( !m_pDropDown )
  387. return;
  388. if ( !IsEnabled() )
  389. return;
  390. // make sure it's getting pressed over us (it may not be due to mouse capture)
  391. if ( !IsCursorOver() )
  392. {
  393. HideMenu();
  394. return;
  395. }
  396. if ( IsEditable() )
  397. {
  398. BaseClass::OnMousePressed(code);
  399. HideMenu();
  400. }
  401. else
  402. {
  403. // clicking on a non-editable text box just activates the drop down menu
  404. RequestFocus();
  405. DoClick();
  406. }
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Purpose: Double-click acts the same as a single-click
  410. //-----------------------------------------------------------------------------
  411. void ComboBox::OnMouseDoublePressed(MouseCode code)
  412. {
  413. if (IsEditable())
  414. {
  415. BaseClass::OnMouseDoublePressed(code);
  416. }
  417. else
  418. {
  419. OnMousePressed(code);
  420. }
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose: Called when a command is received from the menu
  424. // Changes the label text to be that of the command
  425. // Input : char *command -
  426. //-----------------------------------------------------------------------------
  427. void ComboBox::OnCommand( const char *command )
  428. {
  429. if (!stricmp(command, "ButtonClicked"))
  430. {
  431. // hide / show the menu underneath
  432. DoClick();
  433. }
  434. Panel::OnCommand(command);
  435. }
  436. //-----------------------------------------------------------------------------
  437. // Purpose:
  438. //-----------------------------------------------------------------------------
  439. void ComboBox::OnSetText(const wchar_t *newtext)
  440. {
  441. // see if the combobox text has changed, and if so, post a message detailing the new text
  442. const wchar_t *text = newtext;
  443. // check if the new text is a localized string, if so undo it
  444. if (*text == '#')
  445. {
  446. char cbuf[255];
  447. g_pVGuiLocalize->ConvertUnicodeToANSI(text, cbuf, 255);
  448. // try lookup in localization tables
  449. StringIndex_t unlocalizedTextSymbol = g_pVGuiLocalize->FindIndex(cbuf + 1);
  450. if (unlocalizedTextSymbol != INVALID_LOCALIZE_STRING_INDEX)
  451. {
  452. // we have a new text value
  453. text = g_pVGuiLocalize->GetValueByIndex(unlocalizedTextSymbol);
  454. }
  455. }
  456. wchar_t wbuf[255];
  457. GetText(wbuf, 254);
  458. if ( wcscmp(wbuf, text) )
  459. {
  460. // text has changed
  461. SetText(text);
  462. // fire off that things have changed
  463. if ( !m_bPreventTextChangeMessage )
  464. {
  465. PostActionSignal(new KeyValues("TextChanged", "text", text));
  466. }
  467. Repaint();
  468. }
  469. // close the box
  470. HideMenu();
  471. }
  472. //-----------------------------------------------------------------------------
  473. // Purpose: hides the menu
  474. //-----------------------------------------------------------------------------
  475. void ComboBox::HideMenu(void)
  476. {
  477. if ( !m_pDropDown )
  478. return;
  479. // hide the menu
  480. m_pDropDown->SetVisible(false);
  481. Repaint();
  482. OnHideMenu(m_pDropDown);
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: shows the menu
  486. //-----------------------------------------------------------------------------
  487. void ComboBox::ShowMenu(void)
  488. {
  489. if ( !m_pDropDown )
  490. return;
  491. // hide the menu
  492. m_pDropDown->SetVisible(false);
  493. DoClick();
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Purpose: Called when the window loses focus; hides the menu
  497. //-----------------------------------------------------------------------------
  498. void ComboBox::OnKillFocus()
  499. {
  500. SelectNoText();
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Purpose: Called when the menu is closed
  504. //-----------------------------------------------------------------------------
  505. void ComboBox::OnMenuClose()
  506. {
  507. HideMenu();
  508. if ( HasFocus() )
  509. {
  510. SelectAllText(false);
  511. }
  512. else if ( m_bHighlight )
  513. {
  514. m_bHighlight = false;
  515. // we want the text to be highlighted when we request the focus
  516. // SelectAllOnFirstFocus(true);
  517. RequestFocus();
  518. }
  519. // if cursor is in this box or the arrow box
  520. else if ( IsCursorOver() )// make sure it's getting pressed over us (it may not be due to mouse capture)
  521. {
  522. SelectAllText(false);
  523. OnCursorEntered();
  524. // Get focus so the box will unhighlight if we click somewhere else.
  525. RequestFocus();
  526. }
  527. else
  528. {
  529. m_pButton->SetArmed(false);
  530. }
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Purpose: Handles hotkey accesses
  534. // FIXME: make this open different directions as necessary see menubutton.
  535. //-----------------------------------------------------------------------------
  536. void ComboBox::DoClick()
  537. {
  538. // menu is already visible, hide the menu
  539. if ( m_pDropDown->IsVisible() )
  540. {
  541. HideMenu();
  542. return;
  543. }
  544. // do nothing if menu is not enabled
  545. if ( !m_pDropDown->IsEnabled() )
  546. {
  547. return;
  548. }
  549. // force the menu to Think
  550. m_pDropDown->PerformLayout();
  551. // make sure we're at the top of the draw order (and therefore our children as well)
  552. // RequestFocus();
  553. // We want the item that is shown in the combo box to show as selected
  554. int itemToSelect = -1;
  555. int i;
  556. wchar_t comboBoxContents[255];
  557. GetText(comboBoxContents, 255);
  558. for ( i = 0 ; i < m_pDropDown->GetItemCount() ; i++ )
  559. {
  560. wchar_t menuItemName[255];
  561. int menuID = m_pDropDown->GetMenuID(i);
  562. m_pDropDown->GetMenuItem(menuID)->GetText(menuItemName, 255);
  563. if (!wcscmp(menuItemName, comboBoxContents))
  564. {
  565. itemToSelect = i;
  566. break;
  567. }
  568. }
  569. // if we found a match, highlight it on opening the menu
  570. if ( itemToSelect >= 0 )
  571. {
  572. m_pDropDown->SetCurrentlyHighlightedItem( m_pDropDown->GetMenuID(itemToSelect) );
  573. }
  574. // reset the dropdown's position
  575. DoMenuLayout();
  576. // make sure we're at the top of the draw order (and therefore our children as well)
  577. // this important to make sure the menu will be drawn in the foreground
  578. MoveToFront();
  579. // !KLUDGE! Force alpha to solid. Otherwise,
  580. // we run into weird VGUI problems with pops
  581. // and the stencil test
  582. Color c = m_pDropDown->GetBgColor();
  583. c[3] = 255;
  584. m_pDropDown->SetBgColor( c );
  585. // notify
  586. OnShowMenu(m_pDropDown);
  587. // show the menu
  588. m_pDropDown->SetVisible(true);
  589. // bring to focus
  590. m_pDropDown->RequestFocus();
  591. // no text is highlighted when the menu is opened
  592. SelectNoText();
  593. // highlight the arrow while menu is open
  594. m_pButton->SetArmed(true);
  595. Repaint();
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Purpose: Brighten the arrow on the button when entering the box
  599. //-----------------------------------------------------------------------------
  600. void ComboBox::OnCursorEntered()
  601. {
  602. // want the arrow to go white when we enter the box
  603. m_pButton->OnCursorEntered();
  604. TextEntry::OnCursorEntered();
  605. }
  606. //-----------------------------------------------------------------------------
  607. // Purpose: Dim the arrow on the button when exiting the box
  608. //-----------------------------------------------------------------------------
  609. void ComboBox::OnCursorExited()
  610. {
  611. // want the arrow to go grey when we exit the box if the menu is not open
  612. if ( !m_pDropDown->IsVisible() )
  613. {
  614. m_pButton->SetArmed(false);
  615. TextEntry::OnCursorExited();
  616. }
  617. }
  618. //-----------------------------------------------------------------------------
  619. // Purpose:
  620. //-----------------------------------------------------------------------------
  621. #ifdef _X360
  622. void ComboBox::OnMenuItemSelected()
  623. {
  624. m_bHighlight = true;
  625. // For editable cbs, fill in the text field from whatever is chosen from the dropdown...
  626. //=============================================================================
  627. // HPE_BEGIN:
  628. // [pfreese] The text for the combo box should be updated regardless of its
  629. // editable state, and in any case, the member variable below was never
  630. // correctly initialized.
  631. //=============================================================================
  632. // if ( m_bAllowEdit )
  633. //=============================================================================
  634. // HPE_END
  635. //=============================================================================
  636. {
  637. int idx = GetActiveItem();
  638. if ( idx >= 0 )
  639. {
  640. wchar_t name[ 256 ];
  641. GetItemText( idx, name, sizeof( name ) );
  642. OnSetText( name );
  643. }
  644. }
  645. Repaint();
  646. // go to the next control
  647. if(!NavigateDown())
  648. {
  649. NavigateUp();
  650. }
  651. }
  652. #else
  653. void ComboBox::OnMenuItemSelected()
  654. {
  655. m_bHighlight = true;
  656. // For editable cbs, fill in the text field from whatever is chosen from the dropdown...
  657. //if ( m_bAllowEdit )
  658. {
  659. int idx = GetActiveItem();
  660. if ( idx >= 0 )
  661. {
  662. wchar_t name[ 256 ];
  663. GetItemText( idx, name, sizeof( name ) );
  664. OnSetText( name );
  665. }
  666. }
  667. Repaint();
  668. }
  669. #endif
  670. //-----------------------------------------------------------------------------
  671. // Purpose:
  672. //-----------------------------------------------------------------------------
  673. void ComboBox::OnSizeChanged(int wide, int tall)
  674. {
  675. BaseClass::OnSizeChanged( wide, tall);
  676. // set the drawwidth.
  677. int bwide, btall;
  678. PerformLayout();
  679. m_pButton->GetSize( bwide, btall);
  680. SetDrawWidth( wide - bwide );
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Purpose:
  684. //-----------------------------------------------------------------------------
  685. #ifdef _X360
  686. void ComboBox::OnSetFocus()
  687. {
  688. BaseClass::OnSetFocus();
  689. GotoTextEnd();
  690. SelectAllText(true);
  691. }
  692. #else
  693. void ComboBox::OnSetFocus()
  694. {
  695. BaseClass::OnSetFocus();
  696. GotoTextEnd();
  697. SelectAllText(false);
  698. }
  699. #endif
  700. //-----------------------------------------------------------------------------
  701. // Purpose:
  702. //-----------------------------------------------------------------------------
  703. #ifdef _X360
  704. void ComboBox::OnKeyCodePressed(KeyCode code)
  705. {
  706. switch ( GetBaseButtonCode( code ) )
  707. {
  708. case KEY_XBUTTON_A:
  709. DoClick();
  710. break;
  711. case KEY_XBUTTON_UP:
  712. case KEY_XSTICK1_UP:
  713. case KEY_XSTICK2_UP:
  714. if(m_pDropDown->IsVisible())
  715. {
  716. MoveAlongMenuItemList(-1);
  717. }
  718. else
  719. {
  720. BaseClass::OnKeyCodePressed(code);
  721. }
  722. break;
  723. case KEY_XBUTTON_DOWN:
  724. case KEY_XSTICK1_DOWN:
  725. case KEY_XSTICK2_DOWN:
  726. if(m_pDropDown->IsVisible())
  727. {
  728. MoveAlongMenuItemList(1);
  729. }
  730. else
  731. {
  732. BaseClass::OnKeyCodePressed(code);
  733. }
  734. break;
  735. default:
  736. BaseClass::OnKeyCodePressed(code);
  737. break;
  738. }
  739. }
  740. #endif
  741. //-----------------------------------------------------------------------------
  742. // Purpose: Handles up/down arrows
  743. //-----------------------------------------------------------------------------
  744. void ComboBox::OnKeyCodeTyped(KeyCode code)
  745. {
  746. bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT));
  747. if (alt)
  748. {
  749. switch (code)
  750. {
  751. case KEY_UP:
  752. case KEY_DOWN:
  753. {
  754. DoClick();
  755. break;
  756. }
  757. default:
  758. {
  759. BaseClass::OnKeyCodeTyped(code);
  760. break;
  761. }
  762. }
  763. }
  764. else
  765. {
  766. switch (code)
  767. {
  768. case KEY_HOME:
  769. case KEY_END:
  770. case KEY_PAGEUP:
  771. case KEY_PAGEDOWN:
  772. case KEY_UP:
  773. case KEY_DOWN:
  774. {
  775. int itemSelected = m_pDropDown->GetCurrentlyHighlightedItem();
  776. m_pDropDown->OnKeyCodeTyped(code);
  777. int itemToSelect = m_pDropDown->GetCurrentlyHighlightedItem();
  778. if ( itemToSelect != itemSelected )
  779. {
  780. SelectMenuItem(itemToSelect);
  781. }
  782. break;
  783. }
  784. case KEY_ENTER:
  785. {
  786. int itemToSelect = m_pDropDown->GetCurrentlyHighlightedItem();
  787. m_pDropDown->ActivateItem(itemToSelect);
  788. break;
  789. }
  790. default:
  791. {
  792. BaseClass::OnKeyCodeTyped(code);
  793. break;
  794. }
  795. }
  796. }
  797. }
  798. //-----------------------------------------------------------------------------
  799. // Purpose: handles key input
  800. //-----------------------------------------------------------------------------
  801. void ComboBox::OnKeyTyped(wchar_t unichar)
  802. {
  803. if ( IsEditable() || unichar == '\t') // don't play with key presses in edit mode
  804. {
  805. BaseClass::OnKeyTyped( unichar );
  806. return;
  807. }
  808. int itemSelected = m_pDropDown->GetCurrentlyHighlightedItem();
  809. m_pDropDown->OnKeyTyped(unichar);
  810. int itemToSelect = m_pDropDown->GetCurrentlyHighlightedItem();
  811. if ( itemToSelect != itemSelected )
  812. {
  813. SelectMenuItem(itemToSelect);
  814. }
  815. else
  816. {
  817. BaseClass::OnKeyTyped( unichar );
  818. }
  819. }
  820. void ComboBox::SelectMenuItem(int itemToSelect)
  821. {
  822. // if we found this item, then we scroll up or down
  823. if ( itemToSelect >= 0 && itemToSelect < m_pDropDown->GetItemCount() )
  824. {
  825. wchar_t menuItemName[255];
  826. int menuID = m_pDropDown->GetMenuID(itemToSelect);
  827. m_pDropDown->GetMenuItem(menuID)->GetText(menuItemName, 254);
  828. OnSetText(menuItemName);
  829. SelectAllText(false);
  830. }
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Purpose:
  834. //-----------------------------------------------------------------------------
  835. void ComboBox::MoveAlongMenuItemList(int direction)
  836. {
  837. // We want the item that is shown in the combo box to show as selected
  838. int itemToSelect = -1;
  839. wchar_t menuItemName[255];
  840. int i;
  841. wchar_t comboBoxContents[255];
  842. GetText(comboBoxContents, 254);
  843. for ( i = 0 ; i < m_pDropDown->GetItemCount() ; i++ )
  844. {
  845. int menuID = m_pDropDown->GetMenuID(i);
  846. m_pDropDown->GetMenuItem(menuID)->GetText(menuItemName, 254);
  847. if ( !wcscmp(menuItemName, comboBoxContents) )
  848. {
  849. itemToSelect = i;
  850. break;
  851. }
  852. }
  853. if ( itemToSelect >= 0 )
  854. {
  855. int newItem = itemToSelect + direction;
  856. if ( newItem < 0 )
  857. {
  858. newItem = 0;
  859. }
  860. else if ( newItem >= m_pDropDown->GetItemCount() )
  861. {
  862. newItem = m_pDropDown->GetItemCount() - 1;
  863. }
  864. SelectMenuItem(newItem);
  865. }
  866. }
  867. void ComboBox::MoveToFirstMenuItem()
  868. {
  869. SelectMenuItem(0);
  870. }
  871. void ComboBox::MoveToLastMenuItem()
  872. {
  873. SelectMenuItem(m_pDropDown->GetItemCount() - 1);
  874. }
  875. //-----------------------------------------------------------------------------
  876. // Purpose: Sets the direction from the menu button the menu should open
  877. //-----------------------------------------------------------------------------
  878. void ComboBox::SetOpenDirection(Menu::MenuDirection_e direction)
  879. {
  880. m_iDirection = direction;
  881. }
  882. void ComboBox::SetFont( HFont font )
  883. {
  884. BaseClass::SetFont( font );
  885. m_pDropDown->SetFont( font );
  886. }
  887. void ComboBox::SetUseFallbackFont( bool bState, HFont hFallback )
  888. {
  889. BaseClass::SetUseFallbackFont( bState, hFallback );
  890. m_pDropDown->SetUseFallbackFont( bState, hFallback );
  891. }