Counter Strike : Global Offensive Source Code
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.

1085 lines
26 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <assert.h>
  8. #include <ctype.h>
  9. #ifdef _PS3
  10. #include <wctype.h>
  11. #endif
  12. #include <vgui/MouseCode.h>
  13. #include <vgui/KeyCode.h>
  14. #include <keyvalues.h>
  15. #include <vgui/ISurface.h>
  16. #include <vgui/IVGui.h>
  17. #include <vgui/IInput.h>
  18. #include <vgui/IPanel.h>
  19. #include <vgui/ILocalize.h>
  20. #include <vgui_controls/Controls.h>
  21. #include <vgui_controls/ScrollBar.h>
  22. #include <vgui_controls/ImageList.h>
  23. #include <vgui_controls/ImagePanel.h>
  24. #include <vgui_controls/Label.h>
  25. #include <vgui_controls/TextImage.h>
  26. #include <vgui_controls/ListViewPanel.h>
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include <tier0/memdbgon.h>
  29. using namespace vgui;
  30. enum
  31. {
  32. WINDOW_BORDER_WIDTH=2 // the width of the window's border
  33. };
  34. namespace vgui
  35. {
  36. class ListViewItem : public Label
  37. {
  38. DECLARE_CLASS_SIMPLE( ListViewItem, Label );
  39. public:
  40. ListViewItem(Panel *parent) : Label(parent, NULL, "")
  41. {
  42. m_pListViewPanel = (ListViewPanel*) parent;
  43. m_pData = NULL;
  44. m_bSelected = false;
  45. SetPaintBackgroundEnabled(true);
  46. }
  47. ~ListViewItem()
  48. {
  49. if (m_pData)
  50. {
  51. m_pData->deleteThis();
  52. m_pData = NULL;
  53. }
  54. }
  55. void SetData(const KeyValues *data)
  56. {
  57. if (m_pData)
  58. {
  59. m_pData->deleteThis();
  60. }
  61. m_pData = data->MakeCopy();
  62. }
  63. virtual void OnMousePressed( MouseCode code)
  64. {
  65. m_pListViewPanel->OnItemMousePressed(this, code);
  66. }
  67. virtual void OnMouseDoublePressed( MouseCode code)
  68. {
  69. // double press should only select the item
  70. m_pListViewPanel->OnItemMouseDoublePressed(this, code);
  71. }
  72. KeyValues *GetData()
  73. {
  74. return m_pData;
  75. }
  76. void SetSelected(bool bSelected)
  77. {
  78. if (bSelected == m_bSelected)
  79. return;
  80. m_bSelected = bSelected;
  81. if (bSelected)
  82. {
  83. RequestFocus();
  84. }
  85. UpdateImage();
  86. InvalidateLayout();
  87. Repaint();
  88. }
  89. virtual void PerformLayout()
  90. {
  91. TextImage *textImage = GetTextImage();
  92. if (m_bSelected)
  93. {
  94. VPANEL focus = input()->GetFocus();
  95. // if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
  96. if (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())))
  97. {
  98. textImage->SetColor(m_ArmedFgColor2);
  99. }
  100. else
  101. {
  102. textImage->SetColor(m_FgColor2);
  103. }
  104. }
  105. else
  106. {
  107. textImage->SetColor(GetFgColor());
  108. }
  109. BaseClass::PerformLayout();
  110. Repaint();
  111. }
  112. virtual void PaintBackground()
  113. {
  114. int wide, tall;
  115. GetSize(wide, tall);
  116. if ( m_bSelected )
  117. {
  118. VPANEL focus = input()->GetFocus();
  119. // if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
  120. if (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())))
  121. {
  122. surface()->DrawSetColor(m_ArmedBgColor);
  123. }
  124. else
  125. {
  126. surface()->DrawSetColor(m_SelectionBG2Color);
  127. }
  128. }
  129. else
  130. {
  131. surface()->DrawSetColor(GetBgColor());
  132. }
  133. surface()->DrawFilledRect(0, 0, wide, tall);
  134. }
  135. virtual void ApplySchemeSettings(IScheme *pScheme)
  136. {
  137. BaseClass::ApplySchemeSettings(pScheme);
  138. m_ArmedFgColor2 = GetSchemeColor("ListPanel.SelectedTextColor", pScheme);
  139. m_ArmedBgColor = GetSchemeColor("ListPanel.SelectedBgColor", pScheme);
  140. m_FgColor1 = GetSchemeColor("ListPanel.TextColor", pScheme);
  141. m_FgColor2 = GetSchemeColor("ListPanel.SelectedTextColor", pScheme);
  142. m_BgColor = GetSchemeColor("ListPanel.BgColor", GetBgColor(), pScheme);
  143. m_BgColor = GetSchemeColor("ListPanel.TextBgColor", m_BgColor, pScheme);
  144. m_SelectionBG2Color = GetSchemeColor("ListPanel.SelectedOutOfFocusBgColor", pScheme);
  145. SetBgColor(m_BgColor);
  146. SetFgColor(m_FgColor1);
  147. UpdateImage();
  148. }
  149. void UpdateImage()
  150. {
  151. if ( m_pListViewPanel->m_pImageList )
  152. {
  153. int imageIndex = 0;
  154. if ( m_bSelected )
  155. {
  156. imageIndex = m_pData->GetInt("imageSelected", 0);
  157. }
  158. if ( imageIndex == 0 )
  159. {
  160. imageIndex = m_pData->GetInt("image", 0);
  161. }
  162. if ( m_pListViewPanel->m_pImageList->IsValidIndex(imageIndex) )
  163. {
  164. SetImageAtIndex(0, m_pListViewPanel->m_pImageList->GetImage(imageIndex), 0);
  165. }
  166. else
  167. {
  168. // use the default
  169. SetImageAtIndex(0, m_pListViewPanel->m_pImageList->GetImage(1), 0);
  170. }
  171. SizeToContents();
  172. InvalidateLayout();
  173. }
  174. }
  175. private:
  176. Color m_FgColor1;
  177. Color m_FgColor2;
  178. Color m_BgColor;
  179. Color m_ArmedFgColor2;
  180. Color m_ArmedBgColor;
  181. Color m_SelectionBG2Color;
  182. //IBorder *_keyFocusBorder; // maybe in the future when I'm the 'active' but not selected item, I'll have a border
  183. KeyValues *m_pData;
  184. ListViewPanel *m_pListViewPanel;
  185. bool m_bSelected;
  186. };
  187. }
  188. static bool DefaultSortFunc(KeyValues *kv1, KeyValues *kv2)
  189. {
  190. const char *string1 = kv1->GetString("text");
  191. const char *string2 = kv2->GetString("text");
  192. return Q_stricmp(string1, string2) < 0;
  193. }
  194. DECLARE_BUILD_FACTORY( ListViewPanel );
  195. //-----------------------------------------------------------------------------
  196. // Purpose: Constructor
  197. //-----------------------------------------------------------------------------
  198. ListViewPanel::ListViewPanel(Panel *parent, const char *panelName) : Panel(parent, panelName)
  199. {
  200. m_iRowHeight = 20;
  201. m_bNeedsSort = false;
  202. m_hFont = NULL;
  203. m_pImageList = NULL;
  204. m_bDeleteImageListWhenDone = false;
  205. m_pSortFunc = DefaultSortFunc;
  206. m_ShiftStartItemID = -1;
  207. m_hbar = new ScrollBar(this, "HorizScrollBar", false);
  208. m_hbar->AddActionSignalTarget(this);
  209. m_hbar->SetVisible(false);
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose:
  213. //-----------------------------------------------------------------------------
  214. ListViewPanel::~ListViewPanel()
  215. {
  216. DeleteAllItems();
  217. delete m_hbar;
  218. if ( m_bDeleteImageListWhenDone )
  219. {
  220. delete m_pImageList;
  221. m_pImageList = NULL;
  222. }
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose:
  226. //-----------------------------------------------------------------------------
  227. int ListViewPanel::AddItem(const KeyValues *data, bool bScrollToItem, bool bSortOnAdd)
  228. {
  229. ListViewItem *pNewItem = new ListViewItem(this);
  230. pNewItem->SetData(data);
  231. if (m_hFont)
  232. {
  233. pNewItem->SetFont(m_hFont);
  234. }
  235. int itemID = m_DataItems.AddToTail(pNewItem);
  236. ApplyItemChanges(itemID);
  237. m_SortedItems.AddToTail(itemID);
  238. if ( bSortOnAdd )
  239. {
  240. m_bNeedsSort = true;
  241. }
  242. InvalidateLayout();
  243. if ( bScrollToItem )
  244. {
  245. ScrollToItem(itemID);
  246. }
  247. return itemID;
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose:
  251. //-----------------------------------------------------------------------------
  252. void ListViewPanel::ScrollToItem(int itemID)
  253. {
  254. if (!m_hbar->IsVisible())
  255. {
  256. return;
  257. }
  258. int val = m_hbar->GetValue();
  259. int wide, tall;
  260. GetSize( wide, tall );
  261. int maxWidth = GetItemsMaxWidth();
  262. int maxColVisible = wide / maxWidth;
  263. int itemsPerCol = GetItemsPerColumn();
  264. int itemIndex = m_SortedItems.Find(itemID);
  265. int desiredCol = itemIndex / itemsPerCol;
  266. if (desiredCol < val || desiredCol >= (val + maxColVisible) )
  267. {
  268. m_hbar->SetValue(desiredCol);
  269. }
  270. InvalidateLayout();
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose:
  274. //-----------------------------------------------------------------------------
  275. int ListViewPanel::GetItemCount()
  276. {
  277. return m_DataItems.Count();
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. //-----------------------------------------------------------------------------
  282. KeyValues *ListViewPanel::GetItem(int itemID)
  283. {
  284. if ( !m_DataItems.IsValidIndex(itemID) )
  285. return NULL;
  286. return m_DataItems[itemID]->GetData();
  287. }
  288. //-----------------------------------------------------------------------------
  289. // Purpose: Get ItemID from position in panel - valid from [0, GetItemCount)
  290. //-----------------------------------------------------------------------------
  291. int ListViewPanel::GetItemIDFromPos(int iPos)
  292. {
  293. if ( m_SortedItems.IsValidIndex(iPos) )
  294. {
  295. return m_SortedItems[iPos];
  296. }
  297. else
  298. {
  299. return m_DataItems.InvalidIndex();
  300. }
  301. }
  302. //-----------------------------------------------------------------------------
  303. // Purpose:
  304. //-----------------------------------------------------------------------------
  305. void ListViewPanel::ApplyItemChanges(int itemID)
  306. {
  307. if ( !m_DataItems.IsValidIndex(itemID) )
  308. return;
  309. KeyValues *kv = m_DataItems[itemID]->GetData();
  310. ListViewItem *pLabel = m_DataItems[itemID];
  311. pLabel->SetText(kv->GetString("text"));
  312. pLabel->SetTextImageIndex(1);
  313. pLabel->SetImagePreOffset(1, 5);
  314. TextImage *pTextImage = pLabel->GetTextImage();
  315. pTextImage->ResizeImageToContent();
  316. pLabel->UpdateImage();
  317. pLabel->SizeToContents();
  318. pLabel->InvalidateLayout();
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose:
  322. //-----------------------------------------------------------------------------
  323. void ListViewPanel::RemoveItem(int itemID)
  324. {
  325. if ( !m_DataItems.IsValidIndex(itemID) )
  326. return;
  327. m_DataItems[itemID]->MarkForDeletion();
  328. // mark the keyValues for deletion
  329. m_DataItems.Remove(itemID);
  330. m_SortedItems.FindAndRemove(itemID);
  331. m_SelectedItems.FindAndRemove(itemID);
  332. InvalidateLayout();
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Purpose:
  336. //-----------------------------------------------------------------------------
  337. void ListViewPanel::DeleteAllItems()
  338. {
  339. FOR_EACH_LL( m_DataItems, index )
  340. {
  341. m_DataItems[index]->MarkForDeletion();
  342. }
  343. m_DataItems.RemoveAll();
  344. m_SortedItems.RemoveAll();
  345. m_SelectedItems.RemoveAll();
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose:
  349. //-----------------------------------------------------------------------------
  350. int ListViewPanel::InvalidItemID()
  351. {
  352. return m_DataItems.InvalidIndex();
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Purpose:
  356. //-----------------------------------------------------------------------------
  357. bool ListViewPanel::IsValidItemID(int itemID)
  358. {
  359. return m_DataItems.IsValidIndex(itemID);
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose:
  363. //-----------------------------------------------------------------------------
  364. void ListViewPanel::SetSortFunc(ListViewSortFunc_t func)
  365. {
  366. if ( func )
  367. {
  368. m_pSortFunc = func;
  369. SortList();
  370. }
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose:
  374. //-----------------------------------------------------------------------------
  375. void ListViewPanel::SortList()
  376. {
  377. m_SortedItems.RemoveAll();
  378. // find all the items in this section
  379. for( int i = m_DataItems.Head(); i != m_DataItems.InvalidIndex(); i = m_DataItems.Next( i ) )
  380. {
  381. // insert the items sorted
  382. if (m_pSortFunc)
  383. {
  384. int insertionPoint;
  385. for (insertionPoint = 0; insertionPoint < m_SortedItems.Count(); insertionPoint++)
  386. {
  387. if ( m_pSortFunc(m_DataItems[i]->GetData(), m_DataItems[m_SortedItems[insertionPoint]]->GetData() ) )
  388. break;
  389. }
  390. if (insertionPoint == m_SortedItems.Count())
  391. {
  392. m_SortedItems.AddToTail(i);
  393. }
  394. else
  395. {
  396. m_SortedItems.InsertBefore(insertionPoint, i);
  397. }
  398. }
  399. else
  400. {
  401. // just add to the end
  402. m_SortedItems.AddToTail(i);
  403. }
  404. }
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Purpose:
  408. //-----------------------------------------------------------------------------
  409. void ListViewPanel::SetImageList(ImageList *imageList, bool deleteImageListWhenDone)
  410. {
  411. // get rid of existing list image if there's one and we're supposed to get rid of it
  412. if ( m_pImageList && m_bDeleteImageListWhenDone )
  413. {
  414. delete m_pImageList;
  415. m_pImageList = NULL;
  416. }
  417. m_bDeleteImageListWhenDone = deleteImageListWhenDone;
  418. m_pImageList = imageList;
  419. FOR_EACH_LL( m_DataItems, i )
  420. {
  421. m_DataItems[i]->UpdateImage();
  422. }
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Purpose:
  426. //-----------------------------------------------------------------------------
  427. void ListViewPanel::SetFont(HFont font)
  428. {
  429. Assert( font );
  430. if ( !font )
  431. return;
  432. m_hFont = font;
  433. m_iRowHeight = surface()->GetFontTall(font) + 1;
  434. FOR_EACH_LL( m_DataItems, i )
  435. {
  436. m_DataItems[i]->SetFont(m_hFont);
  437. TextImage *pTextImage = m_DataItems[i]->GetTextImage();
  438. pTextImage->ResizeImageToContent();
  439. m_DataItems[i]->SizeToContents();
  440. }
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. //-----------------------------------------------------------------------------
  445. int ListViewPanel::GetSelectedItemsCount()
  446. {
  447. return m_SelectedItems.Count();
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Purpose:
  451. //-----------------------------------------------------------------------------
  452. int ListViewPanel::GetSelectedItem(int selectionIndex)
  453. {
  454. if ( m_SelectedItems.IsValidIndex(selectionIndex) )
  455. return m_SelectedItems[selectionIndex];
  456. return -1;
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose:
  460. //-----------------------------------------------------------------------------
  461. void ListViewPanel::ClearSelectedItems()
  462. {
  463. int i;
  464. for (i = 0 ; i < m_SelectedItems.Count(); i++)
  465. {
  466. if ( m_DataItems.IsValidIndex(m_SelectedItems[i]) )
  467. {
  468. m_DataItems[m_SelectedItems[i]]->SetSelected(false);
  469. }
  470. }
  471. m_SelectedItems.RemoveAll();
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Purpose:
  475. //-----------------------------------------------------------------------------
  476. void ListViewPanel::AddSelectedItem(int itemID)
  477. {
  478. if ( m_SelectedItems.Find(itemID) == -1 )
  479. {
  480. m_SelectedItems.AddToTail(itemID);
  481. m_DataItems[itemID]->SetSelected(true);
  482. m_LastSelectedItemID = itemID;
  483. m_ShiftStartItemID = itemID;
  484. PostActionSignal(new KeyValues("ListViewItemSelected"));
  485. }
  486. }
  487. //-----------------------------------------------------------------------------
  488. // Purpose:
  489. //-----------------------------------------------------------------------------
  490. void ListViewPanel::SetSingleSelectedItem(int itemID)
  491. {
  492. ClearSelectedItems();
  493. AddSelectedItem(itemID);
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Purpose:
  497. //-----------------------------------------------------------------------------
  498. void ListViewPanel::OnMouseWheeled(int delta)
  499. {
  500. int val = m_hbar->GetValue();
  501. val -= delta;
  502. m_hbar->SetValue(val);
  503. }
  504. //-----------------------------------------------------------------------------
  505. // Purpose:
  506. //-----------------------------------------------------------------------------
  507. void ListViewPanel::OnSizeChanged(int wide, int tall)
  508. {
  509. BaseClass::OnSizeChanged(wide, tall);
  510. InvalidateLayout();
  511. Repaint();
  512. }
  513. //-----------------------------------------------------------------------------
  514. // Purpose:
  515. //-----------------------------------------------------------------------------
  516. int ListViewPanel::GetItemsMaxWidth()
  517. {
  518. int maxWidth = 0;
  519. FOR_EACH_LL( m_DataItems, i )
  520. {
  521. int labelWide, labelTall;
  522. m_DataItems[i]->GetSize(labelWide, labelTall);
  523. if (labelWide > maxWidth)
  524. {
  525. maxWidth = labelWide + 25;
  526. }
  527. }
  528. return maxWidth;
  529. }
  530. //-----------------------------------------------------------------------------
  531. // Purpose:
  532. //-----------------------------------------------------------------------------
  533. void ListViewPanel::PerformLayout()
  534. {
  535. if (m_bNeedsSort)
  536. {
  537. SortList();
  538. }
  539. if ( m_DataItems.Count() == 0 )
  540. return;
  541. int wide, tall;
  542. GetSize(wide, tall);
  543. int maxWidth = GetItemsMaxWidth();
  544. if (maxWidth < 24)
  545. {
  546. maxWidth = 24;
  547. }
  548. int maxColVisible = wide / maxWidth;
  549. m_hbar->SetVisible(false);
  550. int itemsPerCol = GetItemsPerColumn();
  551. if (itemsPerCol < 1)
  552. {
  553. itemsPerCol = 1;
  554. }
  555. int cols = ( GetItemCount() + (itemsPerCol - 1) ) / itemsPerCol;
  556. int startItem = 0;
  557. if ( cols > maxColVisible)
  558. {
  559. m_hbar->SetVisible(true);
  560. // recalulate # per column now that we've made the hbar visible
  561. itemsPerCol = GetItemsPerColumn();
  562. cols = ( GetItemCount() + (itemsPerCol - 1) ) / (itemsPerCol > 0 ? itemsPerCol : 1 );
  563. m_hbar->SetEnabled(false);
  564. m_hbar->SetRangeWindow( maxColVisible );
  565. m_hbar->SetRange( 0, cols);
  566. m_hbar->SetButtonPressedScrollValue( 1 );
  567. m_hbar->SetPos(0, tall - (m_hbar->GetTall()+WINDOW_BORDER_WIDTH));
  568. m_hbar->SetSize(wide - (WINDOW_BORDER_WIDTH*2), m_hbar->GetTall());
  569. m_hbar->InvalidateLayout();
  570. int val = m_hbar->GetValue();
  571. startItem += val*itemsPerCol;
  572. }
  573. else
  574. {
  575. m_hbar->SetVisible(false);
  576. }
  577. int lastItemVisible = startItem + (( maxColVisible + 1 )* itemsPerCol) - 1;
  578. int itemsThisCol = 0;
  579. int x = 0;
  580. int y = 0;
  581. int i;
  582. for ( i = 0 ; i < m_SortedItems.Count() ; i++ )
  583. {
  584. if ( i >= startItem && i <= lastItemVisible )
  585. {
  586. m_DataItems[ m_SortedItems[i] ]->SetVisible(true);
  587. m_DataItems[ m_SortedItems[i] ]->SetPos(x, y);
  588. itemsThisCol++;
  589. if ( itemsThisCol == itemsPerCol )
  590. {
  591. y = 0;
  592. x += maxWidth;
  593. itemsThisCol = 0;
  594. }
  595. else
  596. {
  597. y += m_iRowHeight;
  598. }
  599. }
  600. else
  601. {
  602. m_DataItems[ m_SortedItems[i] ]->SetVisible(false);
  603. }
  604. }
  605. }
  606. //-----------------------------------------------------------------------------
  607. // Purpose:
  608. //-----------------------------------------------------------------------------
  609. void ListViewPanel::Paint()
  610. {
  611. BaseClass::Paint();
  612. }
  613. //-----------------------------------------------------------------------------
  614. // Purpose:
  615. //-----------------------------------------------------------------------------
  616. void ListViewPanel::ApplySchemeSettings(IScheme *pScheme)
  617. {
  618. BaseClass::ApplySchemeSettings(pScheme);
  619. SetBgColor(GetSchemeColor("ListPanel.BgColor", pScheme));
  620. SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
  621. m_LabelFgColor = GetSchemeColor("ListPanel.TextColor", pScheme);
  622. m_SelectionFgColor = GetSchemeColor("ListPanel.SelectedTextColor", m_LabelFgColor, pScheme);
  623. m_hFont = pScheme->GetFont("Default", IsProportional());
  624. SetFont(m_hFont);
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Purpose:
  628. //-----------------------------------------------------------------------------
  629. void ListViewPanel::OnMousePressed( MouseCode code)
  630. {
  631. if (code == MOUSE_LEFT || code == MOUSE_RIGHT)
  632. {
  633. ClearSelectedItems();
  634. RequestFocus();
  635. }
  636. // check for context menu open
  637. if (code == MOUSE_RIGHT)
  638. {
  639. // post it, but with the invalid row
  640. PostActionSignal(new KeyValues("OpenContextMenu", "itemID", -1));
  641. }
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Purpose:
  645. //-----------------------------------------------------------------------------
  646. void ListViewPanel::OnShiftSelect(int itemID)
  647. {
  648. // if we dont' have a valid selected ItemID - then we just choose the first item
  649. if ( !m_DataItems.IsValidIndex(m_ShiftStartItemID) )
  650. {
  651. m_ShiftStartItemID = m_DataItems.Head();
  652. }
  653. // find out if the just pressed item is "earlier" or is the 'last selected item'
  654. int lowerPos = -1, upperPos = -1;
  655. int i;
  656. for ( i = 0 ; i < m_SortedItems.Count() ; i++ )
  657. {
  658. if ( m_SortedItems[i] == itemID )
  659. {
  660. lowerPos = i;
  661. upperPos = m_SortedItems.Find(m_ShiftStartItemID);
  662. break;
  663. }
  664. else if ( m_SortedItems[i] == m_ShiftStartItemID )
  665. {
  666. lowerPos = m_SortedItems.Find(m_ShiftStartItemID);
  667. upperPos = i;
  668. break;
  669. }
  670. }
  671. assert(lowerPos <= upperPos);
  672. if ( !input()->IsKeyDown(KEY_LCONTROL) && !input()->IsKeyDown(KEY_RCONTROL) )
  673. {
  674. ClearSelectedItems();
  675. }
  676. for ( i = lowerPos ; i <= upperPos ; i ++)
  677. {
  678. // do not use AddSelectedItem because we don't want to switch the shiftStartItemID
  679. m_DataItems[ m_SortedItems[i] ]->SetSelected(true);
  680. m_SelectedItems.AddToTail(m_SortedItems[i]);
  681. m_LastSelectedItemID = itemID;
  682. }
  683. }
  684. //-----------------------------------------------------------------------------
  685. // Purpose:
  686. //-----------------------------------------------------------------------------
  687. void ListViewPanel::OnItemMousePressed(ListViewItem* pItem, MouseCode code)
  688. {
  689. int itemID = m_DataItems.Find(pItem);
  690. if (!m_DataItems.IsValidIndex(itemID))
  691. return;
  692. // check for context menu open
  693. if (code == MOUSE_RIGHT)
  694. {
  695. // if this is a new item - unselect everything else
  696. if ( m_SelectedItems.Find(itemID) == -1)
  697. {
  698. ClearSelectedItems();
  699. AddSelectedItem(itemID);
  700. }
  701. PostActionSignal(new KeyValues("OpenContextMenu", "itemID", itemID));
  702. }
  703. else
  704. {
  705. if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) )
  706. {
  707. OnShiftSelect(itemID);
  708. }
  709. else if ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) )
  710. {
  711. if ( m_SelectedItems.Find(itemID) != -1)
  712. {
  713. m_SelectedItems.FindAndRemove(itemID);
  714. pItem->SetSelected(false);
  715. // manually select these since we 'last' clicked on these items
  716. m_ShiftStartItemID = itemID;
  717. m_LastSelectedItemID = itemID;
  718. m_DataItems[itemID]->RequestFocus();
  719. }
  720. else
  721. {
  722. AddSelectedItem(itemID);
  723. }
  724. }
  725. else
  726. {
  727. ClearSelectedItems();
  728. AddSelectedItem(itemID);
  729. }
  730. }
  731. }
  732. //-----------------------------------------------------------------------------
  733. // Purpose:
  734. //-----------------------------------------------------------------------------
  735. void ListViewPanel::OnMouseDoublePressed( MouseCode code)
  736. {
  737. }
  738. //-----------------------------------------------------------------------------
  739. // Purpose:
  740. //-----------------------------------------------------------------------------
  741. void ListViewPanel::OnItemMouseDoublePressed(ListViewItem* pItem, MouseCode code)
  742. {
  743. if (code == MOUSE_LEFT)
  744. {
  745. OnKeyCodeTyped(KEY_ENTER);
  746. }
  747. }
  748. //-----------------------------------------------------------------------------
  749. // Purpose:
  750. //-----------------------------------------------------------------------------
  751. void ListViewPanel::FinishKeyPress(int itemID)
  752. {
  753. if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) )
  754. {
  755. OnShiftSelect(itemID);
  756. }
  757. else if ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) )
  758. {
  759. m_DataItems[itemID]->RequestFocus();
  760. m_LastSelectedItemID = itemID;
  761. }
  762. else
  763. {
  764. SetSingleSelectedItem(itemID);
  765. }
  766. ScrollToItem(itemID);
  767. }
  768. //-----------------------------------------------------------------------------
  769. // Purpose:
  770. //-----------------------------------------------------------------------------
  771. void ListViewPanel::OnKeyCodeTyped( KeyCode code )
  772. {
  773. if ( m_DataItems.Count() == 0 )
  774. return;
  775. switch (code)
  776. {
  777. case KEY_HOME:
  778. {
  779. if (m_SortedItems.Count() > 0)
  780. {
  781. int itemID = m_SortedItems[0];
  782. FinishKeyPress(itemID);
  783. }
  784. break;
  785. }
  786. case KEY_END:
  787. {
  788. if (m_DataItems.Count() > 0)
  789. {
  790. int itemID = m_SortedItems[ m_SortedItems.Count() - 1 ];
  791. FinishKeyPress(itemID);
  792. }
  793. break;
  794. }
  795. case KEY_UP:
  796. {
  797. int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
  798. itemPos--;
  799. if (itemPos < 0)
  800. itemPos = 0;
  801. FinishKeyPress(m_SortedItems[itemPos]);
  802. break;
  803. }
  804. case KEY_DOWN:
  805. {
  806. int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
  807. itemPos++;
  808. if (itemPos >= m_DataItems.Count())
  809. itemPos = m_DataItems.Count() - 1;
  810. FinishKeyPress(m_SortedItems[itemPos]);
  811. break;
  812. }
  813. case KEY_LEFT:
  814. {
  815. int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
  816. itemPos -= GetItemsPerColumn();
  817. if (itemPos < 0)
  818. {
  819. itemPos = 0;
  820. }
  821. FinishKeyPress(m_SortedItems[itemPos]);
  822. break;
  823. }
  824. case KEY_RIGHT:
  825. {
  826. int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
  827. itemPos += GetItemsPerColumn();
  828. if (itemPos >= m_SortedItems.Count())
  829. {
  830. itemPos = m_SortedItems.Count() - 1;
  831. }
  832. FinishKeyPress(m_SortedItems[itemPos]);
  833. break;
  834. }
  835. case KEY_PAGEUP:
  836. {
  837. int wide, tall;
  838. GetSize(wide, tall);
  839. int maxWidth = GetItemsMaxWidth();
  840. if (maxWidth == 0)
  841. {
  842. maxWidth = wide;
  843. }
  844. int maxColVisible = wide / maxWidth;
  845. int delta = maxColVisible * GetItemsPerColumn();
  846. int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
  847. itemPos -= delta;
  848. if (itemPos < 0)
  849. {
  850. itemPos = 0;
  851. }
  852. FinishKeyPress(m_SortedItems[itemPos]);
  853. break;
  854. }
  855. case KEY_PAGEDOWN:
  856. {
  857. int wide, tall;
  858. GetSize(wide, tall);
  859. int maxWidth = GetItemsMaxWidth();
  860. if (maxWidth == 0)
  861. {
  862. maxWidth = wide;
  863. }
  864. int maxColVisible = wide / maxWidth;
  865. int delta = maxColVisible * GetItemsPerColumn();
  866. int itemPos = m_SortedItems.Find( m_LastSelectedItemID );
  867. itemPos += delta;
  868. if (itemPos >= m_SortedItems.Count())
  869. {
  870. itemPos = m_SortedItems.Count() - 1;
  871. }
  872. FinishKeyPress(m_SortedItems[itemPos]);
  873. break;
  874. }
  875. default:
  876. {
  877. BaseClass::OnKeyCodeTyped(code);
  878. break;
  879. }
  880. }
  881. }
  882. //-----------------------------------------------------------------------------
  883. // Purpose:
  884. //-----------------------------------------------------------------------------
  885. void ListViewPanel::OnKeyTyped(wchar_t unichar)
  886. {
  887. if (!iswcntrl(unichar))
  888. {
  889. wchar_t uniString[2];
  890. uniString[0] = unichar;
  891. uniString[1] = 0;
  892. char buf[2];
  893. g_pVGuiLocalize->ConvertUnicodeToANSI(uniString, buf, sizeof(buf));
  894. int i;
  895. int itemPos = m_SortedItems.Find(m_LastSelectedItemID);
  896. if ( m_SortedItems.IsValidIndex(itemPos))
  897. {
  898. itemPos++;
  899. // start from the item AFTER our last selected Item and go to end
  900. for ( i = itemPos ; i != m_SortedItems.Count(); i++)
  901. {
  902. KeyValues *kv = m_DataItems[ m_SortedItems[i] ]->GetData();
  903. const char *pszText = kv->GetString("text");
  904. if (!strnicmp(pszText, buf, 1))
  905. {
  906. // select the next of this letter
  907. SetSingleSelectedItem(m_SortedItems[i]);
  908. ScrollToItem(m_SortedItems[i]);
  909. return;
  910. }
  911. }
  912. // if the after this item we couldn't fine an item with the same letter, fall through and just start from the beginning of list to the last selected item
  913. }
  914. for ( i = 0 ; i < m_SortedItems.Count() ; i++ )
  915. {
  916. // we've gone all the way around - break - if we had a valid index, this is one more that last selectedItem, if not it's an illegal index
  917. if ( i == itemPos)
  918. break;
  919. KeyValues *kv = m_DataItems[ m_SortedItems[i] ]->GetData();
  920. const char *pszText = kv->GetString("text");
  921. if (!strnicmp(pszText, buf, 1))
  922. {
  923. SetSingleSelectedItem(m_SortedItems[i]);
  924. ScrollToItem(m_SortedItems[i]);
  925. return;
  926. }
  927. }
  928. }
  929. else
  930. BaseClass::OnKeyTyped(unichar);
  931. }
  932. //-----------------------------------------------------------------------------
  933. // Purpose:
  934. //-----------------------------------------------------------------------------
  935. void ListViewPanel::OnSliderMoved()
  936. {
  937. InvalidateLayout();
  938. Repaint();
  939. }
  940. //-----------------------------------------------------------------------------
  941. // Purpose:
  942. //-----------------------------------------------------------------------------
  943. int ListViewPanel::GetItemsPerColumn()
  944. {
  945. int wide, tall;
  946. GetSize(wide, tall);
  947. if ( m_hbar->IsVisible() )
  948. {
  949. tall -= m_hbar->GetTall();
  950. }
  951. return tall / m_iRowHeight; // should round down
  952. }