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.

2271 lines
64 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdio.h>
  8. #include <vgui/IInput.h>
  9. #include <vgui/IPanel.h>
  10. #include <vgui/ILocalize.h>
  11. #include <vgui/IScheme.h>
  12. #include <vgui/ISurface.h>
  13. #include <KeyValues.h>
  14. #include <vgui/MouseCode.h>
  15. #include <vgui_controls/SectionedListPanel.h>
  16. #include <vgui_controls/Button.h>
  17. #include <vgui_controls/Controls.h>
  18. #include <vgui_controls/Label.h>
  19. #include <vgui_controls/ScrollBar.h>
  20. #include <vgui_controls/TextImage.h>
  21. #include <vgui_controls/ImageList.h>
  22. #include "utlvector.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include <tier0/memdbgon.h>
  25. using namespace vgui;
  26. namespace vgui
  27. {
  28. //-----------------------------------------------------------------------------
  29. // Purpose: header label that separates and names each section
  30. //-----------------------------------------------------------------------------
  31. SectionedListPanelHeader::SectionedListPanelHeader(SectionedListPanel *parent, const char *name, int sectionID) : Label(parent, name, "")
  32. {
  33. m_pListPanel = parent;
  34. m_iSectionID = sectionID;
  35. SetTextImageIndex(-1);
  36. ClearImages();
  37. SetPaintBackgroundEnabled( false );
  38. m_bDrawDividerBar = true;
  39. }
  40. SectionedListPanelHeader::SectionedListPanelHeader(SectionedListPanel *parent, const wchar_t *name, int sectionID) : Label(parent, "SectionHeader", "")
  41. {
  42. SetText(name);
  43. SetVisible(false);
  44. m_pListPanel = parent;
  45. m_iSectionID = sectionID;
  46. SetTextImageIndex(-1);
  47. ClearImages();
  48. m_bDrawDividerBar = true;
  49. }
  50. void SectionedListPanelHeader::ApplySchemeSettings(IScheme *pScheme)
  51. {
  52. BaseClass::ApplySchemeSettings(pScheme);
  53. SetFgColor(GetSchemeColor("SectionedListPanel.HeaderTextColor", pScheme));
  54. m_SectionDividerColor = GetSchemeColor("SectionedListPanel.DividerColor", pScheme);
  55. SetBgColor(GetSchemeColor("SectionedListPanelHeader.BgColor", GetBgColor(), pScheme));
  56. SetFont(pScheme->GetFont("DefaultVerySmall", IsProportional()));
  57. ClearImages();
  58. HFont hFont = m_pListPanel->GetHeaderFont();
  59. if ( hFont != INVALID_FONT )
  60. {
  61. SetFont( hFont );
  62. }
  63. else
  64. {
  65. SetFont(pScheme->GetFont("DefaultVerySmall", IsProportional()));
  66. }
  67. }
  68. void SectionedListPanelHeader::Paint()
  69. {
  70. BaseClass::Paint();
  71. if ( m_bDrawDividerBar )
  72. {
  73. int x, y, wide, tall;
  74. GetBounds(x, y, wide, tall);
  75. y = (tall - 2); // draw the line under the panel
  76. surface()->DrawSetColor(m_SectionDividerColor);
  77. surface()->DrawFilledRect(1, y, GetWide() - 2, y + 1);
  78. }
  79. }
  80. void SectionedListPanelHeader::SetColor(Color col)
  81. {
  82. m_SectionDividerColor = col;
  83. SetFgColor(col);
  84. }
  85. void SectionedListPanelHeader::SetDividerColor(Color col )
  86. {
  87. m_SectionDividerColor = col;
  88. }
  89. void SectionedListPanelHeader::PerformLayout()
  90. {
  91. BaseClass::PerformLayout();
  92. // set up the text in the header
  93. int colCount = m_pListPanel->GetColumnCountBySection(m_iSectionID);
  94. if (colCount != GetImageCount())
  95. {
  96. // rebuild the image list
  97. for (int i = 0; i < colCount; i++)
  98. {
  99. int columnFlags = m_pListPanel->GetColumnFlagsBySection(m_iSectionID, i);
  100. IImage *image = NULL;
  101. if (columnFlags & SectionedListPanel::HEADER_IMAGE)
  102. {
  103. //!! need some kind of image reference
  104. image = NULL;
  105. }
  106. else
  107. {
  108. TextImage *textImage = new TextImage("");
  109. textImage->SetFont(GetFont());
  110. HFont fallback = m_pListPanel->GetColumnFallbackFontBySection( m_iSectionID, i );
  111. if ( INVALID_FONT != fallback )
  112. {
  113. textImage->SetUseFallbackFont( true, fallback );
  114. }
  115. textImage->SetColor(GetFgColor());
  116. image = textImage;
  117. }
  118. SetImageAtIndex(i, image, 0);
  119. }
  120. }
  121. for (int repeat = 0; repeat <= 1; repeat++)
  122. {
  123. int xpos = 0;
  124. for (int i = 0; i < colCount; i++)
  125. {
  126. int columnFlags = m_pListPanel->GetColumnFlagsBySection(m_iSectionID, i);
  127. int columnWidth = m_pListPanel->GetColumnWidthBySection(m_iSectionID, i);
  128. int maxWidth = columnWidth;
  129. IImage *image = GetImageAtIndex(i);
  130. if (!image)
  131. {
  132. xpos += columnWidth;
  133. continue;
  134. }
  135. // set the image position within the label
  136. int contentWide, wide, tall;
  137. image->GetContentSize(wide, tall);
  138. contentWide = wide;
  139. // see if we can draw over the next few column headers (if we're left-aligned)
  140. if (!(columnFlags & SectionedListPanel::COLUMN_RIGHT))
  141. {
  142. for (int j = i + 1; j < colCount; j++)
  143. {
  144. // see if this column header has anything for a header
  145. int iwide = 0, itall = 0;
  146. if (GetImageAtIndex(j))
  147. {
  148. GetImageAtIndex(j)->GetContentSize(iwide, itall);
  149. }
  150. if (iwide == 0)
  151. {
  152. // it's a blank header, ok to draw over it
  153. maxWidth += m_pListPanel->GetColumnWidthBySection(m_iSectionID, j);
  154. }
  155. }
  156. }
  157. if (maxWidth >= 0)
  158. {
  159. wide = maxWidth;
  160. }
  161. if (columnFlags & SectionedListPanel::COLUMN_RIGHT)
  162. {
  163. SetImageBounds(i, xpos + wide - contentWide, wide - SectionedListPanel::COLUMN_DATA_GAP);
  164. }
  165. else
  166. {
  167. SetImageBounds(i, xpos, wide - SectionedListPanel::COLUMN_DATA_GAP);
  168. }
  169. xpos += columnWidth;
  170. if (!(columnFlags & SectionedListPanel::HEADER_IMAGE))
  171. {
  172. Assert(dynamic_cast<TextImage *>(image) != NULL);
  173. TextImage *textImage = (TextImage *)image;
  174. textImage->SetFont(GetFont());
  175. textImage->SetText(m_pListPanel->GetColumnTextBySection(m_iSectionID, i));
  176. textImage->ResizeImageToContentMaxWidth( maxWidth );
  177. }
  178. }
  179. }
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Purpose: Individual items in the list
  183. //-----------------------------------------------------------------------------
  184. class CItemButton : public Label
  185. {
  186. DECLARE_CLASS_SIMPLE( CItemButton, Label );
  187. public:
  188. CItemButton(SectionedListPanel *parent, int itemID) : Label(parent, NULL, "< item >")
  189. {
  190. m_pListPanel = parent;
  191. m_iID = itemID;
  192. m_pData = NULL;
  193. Clear();
  194. m_nHorizFillInset = 0;
  195. }
  196. ~CItemButton()
  197. {
  198. // free all the keyvalues
  199. if (m_pData)
  200. {
  201. m_pData->deleteThis();
  202. }
  203. // clear any section data
  204. SetSectionID(-1);
  205. }
  206. void Clear()
  207. {
  208. m_bSelected = false;
  209. m_bOverrideColors = false;
  210. m_iSectionID = -1;
  211. SetPaintBackgroundEnabled( false );
  212. SetTextImageIndex(-1);
  213. ClearImages();
  214. }
  215. int GetID()
  216. {
  217. return m_iID;
  218. }
  219. void SetID(int itemID)
  220. {
  221. m_iID = itemID;
  222. }
  223. int GetSectionID()
  224. {
  225. return m_iSectionID;
  226. }
  227. void SetSectionID(int sectionID)
  228. {
  229. if (sectionID != m_iSectionID)
  230. {
  231. // free any existing textimage list
  232. ClearImages();
  233. // delete any images we've created
  234. for (int i = 0; i < m_TextImages.Count(); i++)
  235. {
  236. delete m_TextImages[i];
  237. }
  238. m_TextImages.RemoveAll();
  239. // mark the list as needing rebuilding
  240. InvalidateLayout();
  241. }
  242. m_iSectionID = sectionID;
  243. }
  244. void SetData(const KeyValues *data)
  245. {
  246. if (m_pData)
  247. {
  248. m_pData->deleteThis();
  249. }
  250. m_pData = data->MakeCopy();
  251. InvalidateLayout();
  252. }
  253. KeyValues *GetData()
  254. {
  255. return m_pData;
  256. }
  257. virtual void PerformLayout()
  258. {
  259. // get our button text
  260. int colCount = m_pListPanel->GetColumnCountBySection(m_iSectionID);
  261. if (!m_pData || colCount < 1)
  262. {
  263. SetText("< unset >");
  264. }
  265. else
  266. {
  267. if (colCount != GetImageCount())
  268. {
  269. // rebuild the image list
  270. for (int i = 0; i < colCount; i++)
  271. {
  272. int columnFlags = m_pListPanel->GetColumnFlagsBySection(m_iSectionID, i);
  273. if (!(columnFlags & SectionedListPanel::COLUMN_IMAGE))
  274. {
  275. TextImage *image = new TextImage("");
  276. m_TextImages.AddToTail(image);
  277. image->SetFont( GetFont() );
  278. HFont fallback = m_pListPanel->GetColumnFallbackFontBySection( m_iSectionID, i );
  279. if ( INVALID_FONT != fallback )
  280. {
  281. image->SetUseFallbackFont( true, fallback );
  282. }
  283. SetImageAtIndex(i, image, 0);
  284. }
  285. }
  286. {for ( int i = GetImageCount(); i < colCount; i++ ) // make sure we have enough image slots
  287. {
  288. AddImage( NULL, 0 );
  289. }}
  290. }
  291. // set the text for each column
  292. int xpos = 0;
  293. for (int i = 0; i < colCount; i++)
  294. {
  295. const char *keyname = m_pListPanel->GetColumnNameBySection(m_iSectionID, i);
  296. int columnFlags = m_pListPanel->GetColumnFlagsBySection(m_iSectionID, i);
  297. int maxWidth = m_pListPanel->GetColumnWidthBySection(m_iSectionID, i);
  298. IImage *image = NULL;
  299. if (columnFlags & SectionedListPanel::COLUMN_IMAGE)
  300. {
  301. // lookup which image is being referred to
  302. if (m_pListPanel->m_pImageList)
  303. {
  304. int imageIndex = m_pData->GetInt(keyname, 0);
  305. if (m_pListPanel->m_pImageList->IsValidIndex(imageIndex))
  306. {
  307. // 0 is always the blank image
  308. if (imageIndex > 0)
  309. {
  310. image = m_pListPanel->m_pImageList->GetImage(imageIndex);
  311. SetImageAtIndex(i, image, 0);
  312. }
  313. }
  314. else
  315. {
  316. // this is mildly valid (CGamesList hits it because of the way it uses the image indices)
  317. // Assert(!("Image index out of range for ImageList in SectionedListPanel"));
  318. }
  319. }
  320. else
  321. {
  322. Assert(!("Images columns used in SectionedListPanel with no ImageList set"));
  323. }
  324. }
  325. else
  326. {
  327. TextImage *textImage = dynamic_cast<TextImage *>(GetImageAtIndex(i));
  328. if (textImage)
  329. {
  330. const wchar* pwszOverride = m_pData->GetWString( keyname, NULL );
  331. if ( pwszOverride && pwszOverride[0] != '#' )
  332. {
  333. textImage->SetText( pwszOverride );
  334. }
  335. else
  336. {
  337. textImage->SetText(m_pData->GetString(keyname, ""));
  338. }
  339. textImage->ResizeImageToContentMaxWidth( maxWidth );
  340. // set the text color based on the selection state - if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
  341. VPANEL focus = input()->GetFocus();
  342. if ( !m_bOverrideColors )
  343. {
  344. if (IsSelected() && !m_pListPanel->IsInEditMode())
  345. {
  346. if (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())))
  347. {
  348. textImage->SetColor(m_ArmedFgColor2);
  349. }
  350. else
  351. {
  352. textImage->SetColor(m_OutOfFocusSelectedTextColor);
  353. }
  354. }
  355. else if (columnFlags & SectionedListPanel::COLUMN_BRIGHT)
  356. {
  357. textImage->SetColor(m_ArmedFgColor1);
  358. }
  359. else
  360. {
  361. textImage->SetColor(m_FgColor2);
  362. }
  363. }
  364. else
  365. {
  366. // custom colors
  367. if (IsSelected() && (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent()))))
  368. {
  369. textImage->SetColor(m_ArmedFgColor2);
  370. }
  371. else
  372. {
  373. Color *clrOverride = m_pListPanel->GetColorOverrideForCell(m_iSectionID, m_iID, i);
  374. textImage->SetColor( (clrOverride != NULL) ? *clrOverride : GetFgColor());
  375. }
  376. }
  377. }
  378. image = textImage;
  379. }
  380. // set the image position within the label
  381. int imageWide = 0, tall = 0;
  382. int wide;
  383. if (image)
  384. {
  385. image->GetContentSize(imageWide, tall);
  386. }
  387. if (maxWidth >= 0)
  388. {
  389. wide = maxWidth;
  390. }
  391. else
  392. {
  393. wide = imageWide;
  394. }
  395. if (i == 0 && !(columnFlags & SectionedListPanel::COLUMN_IMAGE))
  396. {
  397. // first column has an extra indent
  398. SetImageBounds(i, xpos + SectionedListPanel::COLUMN_DATA_INDENT, wide - (SectionedListPanel::COLUMN_DATA_INDENT + SectionedListPanel::COLUMN_DATA_GAP));
  399. }
  400. else
  401. {
  402. if (columnFlags & SectionedListPanel::COLUMN_CENTER)
  403. {
  404. int offSet = (wide / 2) - (imageWide / 2);
  405. SetImageBounds(i, xpos + offSet, wide - offSet - SectionedListPanel::COLUMN_DATA_GAP);
  406. }
  407. else if (columnFlags & SectionedListPanel::COLUMN_RIGHT)
  408. {
  409. SetImageBounds(i, xpos + wide - imageWide, wide - SectionedListPanel::COLUMN_DATA_GAP);
  410. }
  411. else
  412. {
  413. SetImageBounds(i, xpos, wide - SectionedListPanel::COLUMN_DATA_GAP);
  414. }
  415. }
  416. xpos += wide;
  417. }
  418. }
  419. BaseClass::PerformLayout();
  420. }
  421. virtual void ApplySchemeSettings(IScheme *pScheme)
  422. {
  423. BaseClass::ApplySchemeSettings(pScheme);
  424. m_ArmedFgColor1 = GetSchemeColor("SectionedListPanel.BrightTextColor", pScheme);
  425. m_ArmedFgColor2 = GetSchemeColor("SectionedListPanel.SelectedTextColor", pScheme);
  426. m_OutOfFocusSelectedTextColor = GetSchemeColor("SectionedListPanel.OutOfFocusSelectedTextColor", pScheme);
  427. m_ArmedBgColor = GetSchemeColor("SectionedListPanel.SelectedBgColor", pScheme);
  428. m_FgColor2 = GetSchemeColor("SectionedListPanel.TextColor", pScheme);
  429. m_BgColor = GetSchemeColor("SectionedListPanel.BgColor", GetBgColor(), pScheme);
  430. m_SelectionBG2Color = GetSchemeColor("SectionedListPanel.OutOfFocusSelectedBgColor", pScheme);
  431. HFont hFont = m_pListPanel->GetRowFont();
  432. if ( hFont != INVALID_FONT )
  433. {
  434. SetFont( hFont );
  435. }
  436. else
  437. {
  438. const char *fontName = pScheme->GetResourceString( "SectionedListPanel.Font" );
  439. HFont font = pScheme->GetFont(fontName, IsProportional());
  440. if ( font != INVALID_FONT )
  441. {
  442. SetFont( font );
  443. }
  444. }
  445. ClearImages();
  446. }
  447. virtual void PaintBackground()
  448. {
  449. int wide, tall;
  450. GetSize(wide, tall);
  451. if (IsSelected() && !m_pListPanel->IsInEditMode())
  452. {
  453. VPANEL focus = input()->GetFocus();
  454. // if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
  455. if (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())))
  456. {
  457. surface()->DrawSetColor(m_ArmedBgColor);
  458. }
  459. else
  460. {
  461. surface()->DrawSetColor(m_SelectionBG2Color);
  462. }
  463. }
  464. else
  465. {
  466. surface()->DrawSetColor(GetBgColor());
  467. }
  468. surface()->DrawFilledRect(0, m_nHorizFillInset, wide, tall - m_nHorizFillInset);
  469. }
  470. virtual void Paint()
  471. {
  472. BaseClass::Paint();
  473. if ( !m_bShowColumns )
  474. return;
  475. // Debugging code to show column widths
  476. int wide, tall;
  477. GetSize(wide, tall);
  478. surface()->DrawSetColor( 255,255,255,255 );
  479. surface()->DrawOutlinedRect(0, 0, wide, tall);
  480. int colCount = m_pListPanel->GetColumnCountBySection(m_iSectionID);
  481. if (m_pData && colCount >= 0)
  482. {
  483. int xpos = 0;
  484. for (int i = 0; i < colCount; i++)
  485. {
  486. const char *keyname = m_pListPanel->GetColumnNameBySection(m_iSectionID, i);
  487. int columnFlags = m_pListPanel->GetColumnFlagsBySection(m_iSectionID, i);
  488. int maxWidth = m_pListPanel->GetColumnWidthBySection(m_iSectionID, i);
  489. IImage *image = NULL;
  490. if (columnFlags & SectionedListPanel::COLUMN_IMAGE)
  491. {
  492. // lookup which image is being referred to
  493. if (m_pListPanel->m_pImageList)
  494. {
  495. int imageIndex = m_pData->GetInt(keyname, 0);
  496. if (m_pListPanel->m_pImageList->IsValidIndex(imageIndex))
  497. {
  498. if (imageIndex > 0)
  499. {
  500. image = m_pListPanel->m_pImageList->GetImage(imageIndex);
  501. }
  502. }
  503. }
  504. }
  505. else
  506. {
  507. image = GetImageAtIndex(i);
  508. }
  509. int imageWide = 0;
  510. if (image)
  511. {
  512. image->GetContentSize(imageWide, tall);
  513. }
  514. if (maxWidth >= 0)
  515. {
  516. wide = maxWidth;
  517. }
  518. else
  519. {
  520. wide = imageWide;
  521. }
  522. xpos += wide;//max(maxWidth,wide);
  523. surface()->DrawOutlinedRect( xpos, 0, xpos, GetTall() );
  524. }
  525. }
  526. }
  527. virtual void OnMousePressed(MouseCode code)
  528. {
  529. if ( m_pListPanel && m_pListPanel->IsClickable() && IsEnabled() )
  530. {
  531. if (code == MOUSE_LEFT)
  532. {
  533. m_pListPanel->PostActionSignal(new KeyValues("ItemLeftClick", "itemID", m_iID));
  534. }
  535. if (code == MOUSE_RIGHT)
  536. {
  537. KeyValues *msg = new KeyValues("ItemContextMenu", "itemID", m_iID);
  538. msg->SetPtr("SubPanel", this);
  539. m_pListPanel->PostActionSignal(msg);
  540. }
  541. m_pListPanel->SetSelectedItem(this);
  542. }
  543. }
  544. void SetSelected(bool state)
  545. {
  546. if (m_bSelected != state)
  547. {
  548. if (state)
  549. {
  550. RequestFocus();
  551. }
  552. m_bSelected = state;
  553. SetPaintBackgroundEnabled( state );
  554. InvalidateLayout();
  555. Repaint();
  556. }
  557. }
  558. bool IsSelected()
  559. {
  560. return m_bSelected;
  561. }
  562. virtual void OnSetFocus()
  563. {
  564. InvalidateLayout(); // force the layout to be redone so we can change text color according to focus
  565. BaseClass::OnSetFocus();
  566. }
  567. virtual void OnKillFocus()
  568. {
  569. InvalidateLayout(); // force the layout to be redone so we can change text color according to focus
  570. BaseClass::OnSetFocus();
  571. }
  572. virtual void OnMouseDoublePressed(MouseCode code)
  573. {
  574. //=============================================================================
  575. // HPE_BEGIN:
  576. // [tj] Only do this if clicking is enabled.
  577. //=============================================================================
  578. if (m_pListPanel && m_pListPanel->IsClickable())
  579. {
  580. if (code == MOUSE_LEFT)
  581. {
  582. m_pListPanel->PostActionSignal(new KeyValues("ItemDoubleLeftClick", "itemID", m_iID));
  583. // post up an enter key being hit
  584. m_pListPanel->OnKeyCodeTyped(KEY_ENTER);
  585. }
  586. else
  587. {
  588. OnMousePressed(code);
  589. }
  590. m_pListPanel->SetSelectedItem(this);
  591. }
  592. //=============================================================================
  593. // HPE_END
  594. //=============================================================================
  595. }
  596. void GetCellBounds(int column, int &xpos, int &columnWide)
  597. {
  598. xpos = 0, columnWide = 0;
  599. int colCount = m_pListPanel->GetColumnCountBySection(m_iSectionID);
  600. for (int i = 0; i < colCount; i++)
  601. {
  602. int maxWidth = m_pListPanel->GetColumnWidthBySection(m_iSectionID, i);
  603. IImage *image = GetImageAtIndex(i);
  604. if (!image)
  605. continue;
  606. // set the image position within the label
  607. int wide, tall;
  608. image->GetContentSize(wide, tall);
  609. if (maxWidth >= 0)
  610. {
  611. wide = maxWidth;
  612. }
  613. if (i == column)
  614. {
  615. // found the cell size, bail
  616. columnWide = wide;
  617. return;
  618. }
  619. xpos += wide;
  620. }
  621. }
  622. //=============================================================================
  623. // HPE_BEGIN:
  624. // [menglish] gets the local coordinates of a cell using the max width for every column
  625. //=============================================================================
  626. void GetMaxCellBounds(int column, int &xpos, int &columnWide)
  627. {
  628. xpos = 0, columnWide = 0;
  629. int colCount = m_pListPanel->GetColumnCountBySection(m_iSectionID);
  630. for (int i = 0; i < colCount; i++)
  631. {
  632. int maxWidth = m_pListPanel->GetColumnWidthBySection(m_iSectionID, i);
  633. if (i == column)
  634. {
  635. // found the cell size, bail
  636. columnWide = maxWidth;
  637. return;
  638. }
  639. xpos += maxWidth;
  640. }
  641. }
  642. //=============================================================================
  643. // HPE_END
  644. //=============================================================================
  645. virtual void SetOverrideColors( bool state )
  646. {
  647. m_bOverrideColors = state;
  648. }
  649. void SetShowColumns( bool bShow )
  650. {
  651. m_bShowColumns = bShow;
  652. }
  653. void SetItemBgHorizFillInset( int nHorizFillInset ){ m_nHorizFillInset = nHorizFillInset; }
  654. private:
  655. SectionedListPanel *m_pListPanel;
  656. int m_iID;
  657. int m_iSectionID;
  658. KeyValues *m_pData;
  659. Color m_FgColor2;
  660. Color m_BgColor;
  661. Color m_ArmedFgColor1;
  662. Color m_ArmedFgColor2;
  663. Color m_OutOfFocusSelectedTextColor;
  664. Color m_ArmedBgColor;
  665. Color m_SelectionBG2Color;
  666. CUtlVector<vgui::TextImage *> m_TextImages;
  667. bool m_bSelected;
  668. bool m_bOverrideColors;
  669. bool m_bShowColumns;
  670. int m_nHorizFillInset;
  671. };
  672. }; // namespace vgui
  673. DECLARE_BUILD_FACTORY( SectionedListPanel );
  674. //-----------------------------------------------------------------------------
  675. // Purpose: Constructor
  676. //-----------------------------------------------------------------------------
  677. SectionedListPanel::SectionedListPanel(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
  678. {
  679. m_pScrollBar = new ScrollBar(this, "SectionedScrollBar", true);
  680. m_pScrollBar->SetVisible(false);
  681. m_pScrollBar->AddActionSignalTarget(this);
  682. m_iEditModeItemID = 0;
  683. m_iEditModeColumn = 0;
  684. m_bSortNeeded = false;
  685. m_bVerticalScrollbarEnabled = true;
  686. m_iLineSpacing = DEFAULT_LINE_SPACING;
  687. m_iLineGap = 0;
  688. m_iSectionGap = DEFAULT_SECTION_GAP;
  689. m_pImageList = NULL;
  690. m_bDeleteImageListWhenDone = false;
  691. m_hHeaderFont = INVALID_FONT;
  692. m_hRowFont = INVALID_FONT;
  693. //=============================================================================
  694. // HPE_BEGIN:
  695. //=============================================================================
  696. // [tj] Default clickability to true so existing controls aren't affected.
  697. m_clickable = true;
  698. // [tj] draw section headers by default so existing controls aren't affected.
  699. m_bDrawSectionHeaders = true;
  700. //=============================================================================
  701. // HPE_END
  702. //=============================================================================
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose: Destructor
  706. //-----------------------------------------------------------------------------
  707. SectionedListPanel::~SectionedListPanel()
  708. {
  709. }
  710. //-----------------------------------------------------------------------------
  711. // Purpose: Sorts the list
  712. //-----------------------------------------------------------------------------
  713. void SectionedListPanel::ReSortList()
  714. {
  715. m_SortedItems.RemoveAll();
  716. int sectionStart = 0;
  717. // layout the buttons
  718. for (int sectionIndex = 0; sectionIndex < m_Sections.Size(); sectionIndex++)
  719. {
  720. section_t &section = m_Sections[sectionIndex];
  721. sectionStart = m_SortedItems.Count();
  722. // find all the items in this section
  723. for( int i = m_Items.Head(); i != m_Items.InvalidIndex(); i = m_Items.Next( i ) )
  724. {
  725. if (m_Items[i]->GetSectionID() == m_Sections[sectionIndex].m_iID)
  726. {
  727. // insert the items sorted
  728. if (section.m_pSortFunc)
  729. {
  730. int insertionPoint = sectionStart;
  731. for (;insertionPoint < m_SortedItems.Count(); insertionPoint++)
  732. {
  733. if (section.m_pSortFunc(this, i, m_SortedItems[insertionPoint]->GetID()))
  734. break;
  735. }
  736. if (insertionPoint == m_SortedItems.Count())
  737. {
  738. m_SortedItems.AddToTail(m_Items[i]);
  739. }
  740. else
  741. {
  742. m_SortedItems.InsertBefore(insertionPoint, m_Items[i]);
  743. }
  744. }
  745. else
  746. {
  747. // just add to the end
  748. m_SortedItems.AddToTail(m_Items[i]);
  749. }
  750. }
  751. }
  752. }
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Purpose: iterates through and sets up the position of all the sections and items
  756. //-----------------------------------------------------------------------------
  757. void SectionedListPanel::PerformLayout()
  758. {
  759. // lazy resort the list
  760. if (m_bSortNeeded)
  761. {
  762. ReSortList();
  763. m_bSortNeeded = false;
  764. }
  765. BaseClass::PerformLayout();
  766. LayoutPanels(m_iContentHeight);
  767. int cx, cy, cwide, ctall;
  768. GetBounds(cx, cy, cwide, ctall);
  769. if (m_iContentHeight > ctall && m_bVerticalScrollbarEnabled)
  770. {
  771. m_pScrollBar->SetVisible(true);
  772. m_pScrollBar->MoveToFront();
  773. m_pScrollBar->SetPos(cwide - m_pScrollBar->GetWide() - 2, 0);
  774. m_pScrollBar->SetSize(m_pScrollBar->GetWide(), ctall - 2);
  775. m_pScrollBar->SetRangeWindow(ctall);
  776. m_pScrollBar->SetRange(0, m_iContentHeight);
  777. m_pScrollBar->InvalidateLayout();
  778. m_pScrollBar->Repaint();
  779. // since we're just about to make the scrollbar visible, we need to re-layout
  780. // the buttons since they depend on the scrollbar size
  781. LayoutPanels(m_iContentHeight);
  782. }
  783. else
  784. {
  785. m_pScrollBar->SetValue(0);
  786. bool bWasVisible = m_pScrollBar->IsVisible();
  787. m_pScrollBar->SetVisible(false);
  788. // When we hide the scrollbar, we need to layout the buttons because they'll have more width to work with
  789. if ( bWasVisible )
  790. {
  791. LayoutPanels(m_iContentHeight);
  792. }
  793. }
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Purpose: lays out the sections and rows in the panel
  797. //-----------------------------------------------------------------------------
  798. void SectionedListPanel::LayoutPanels(int &contentTall)
  799. {
  800. int tall = GetSectionTall();
  801. int x = 5, wide = GetWide() - 10;
  802. int y = 5;
  803. if (m_pScrollBar->IsVisible())
  804. {
  805. y -= m_pScrollBar->GetValue();
  806. wide -= m_pScrollBar->GetWide();
  807. }
  808. int iStart = -1;
  809. int iEnd = -1;
  810. // layout the buttons
  811. bool bFirstVisibleSection = true;
  812. for (int sectionIndex = 0; sectionIndex < m_Sections.Size(); sectionIndex++)
  813. {
  814. section_t &section = m_Sections[sectionIndex];
  815. iStart = -1;
  816. iEnd = -1;
  817. for (int i = 0; i < m_SortedItems.Count(); i++)
  818. {
  819. if (m_SortedItems[i]->GetSectionID() == m_Sections[sectionIndex].m_iID)
  820. {
  821. if (iStart == -1)
  822. iStart = i;
  823. iEnd = i;
  824. }
  825. }
  826. // don't draw this section at all if there are no items in it
  827. if (iStart == -1 && !section.m_bAlwaysVisible)
  828. {
  829. section.m_pHeader->SetVisible(false);
  830. continue;
  831. }
  832. // Skip down a bit if this is not the first section to be drawn
  833. if ( bFirstVisibleSection )
  834. bFirstVisibleSection = false;
  835. else
  836. y += m_iSectionGap;
  837. //=============================================================================
  838. // HPE_BEGIN:
  839. // [tj] Only draw the header if it is enabled
  840. //=============================================================================
  841. int nMinNextSectionY = y + section.m_iMinimumHeight;
  842. if (m_bDrawSectionHeaders)
  843. {
  844. // draw the header
  845. section.m_pHeader->SetBounds(x, y, wide, tall);
  846. section.m_pHeader->SetVisible(true);
  847. y += tall;
  848. }
  849. else
  850. {
  851. section.m_pHeader->SetVisible(false);
  852. }
  853. //=============================================================================
  854. // HPE_END
  855. //=============================================================================
  856. if (iStart == -1 && section.m_bAlwaysVisible)
  857. {
  858. }
  859. else
  860. {
  861. // arrange all the items in this section underneath
  862. for (int i = iStart; i <= iEnd; i++)
  863. {
  864. CItemButton *item = m_SortedItems[i]; //items[i];
  865. item->SetBounds(x, y, wide, m_iLineSpacing);
  866. // setup edit mode
  867. if (m_hEditModePanel.Get() && m_iEditModeItemID == item->GetID())
  868. {
  869. int cx, cwide;
  870. item->GetCellBounds(1, cx, cwide);
  871. m_hEditModePanel->SetBounds(cx, y, cwide, tall);
  872. }
  873. y += m_iLineSpacing + m_iLineGap;
  874. }
  875. }
  876. // Add space, if needed to fulfill minimum requested content height
  877. if ( y < nMinNextSectionY )
  878. y = nMinNextSectionY;
  879. }
  880. // calculate height
  881. contentTall = y;
  882. if (m_pScrollBar->IsVisible())
  883. {
  884. contentTall += m_pScrollBar->GetValue();
  885. }
  886. }
  887. //-----------------------------------------------------------------------------
  888. // Purpose: Ensures that the specified item is visible in the display
  889. //-----------------------------------------------------------------------------
  890. void SectionedListPanel::ScrollToItem(int iItem)
  891. {
  892. int tall = GetSectionTall();
  893. int itemX, itemY ;
  894. int nCurrentValue = m_pScrollBar->GetValue();
  895. // find out where the item is
  896. m_Items[iItem]->GetPos(itemX, itemY);
  897. // add in the current scrollbar position
  898. itemY += nCurrentValue;
  899. // compare that in the list
  900. int cx, cy, cwide, ctall;
  901. GetBounds(cx, cy, cwide, ctall);
  902. if (m_iContentHeight > ctall)
  903. {
  904. if (itemY < nCurrentValue)
  905. {
  906. // scroll up
  907. m_pScrollBar->SetValue(itemY);
  908. }
  909. else if (itemY > nCurrentValue + ctall - tall)
  910. {
  911. // scroll down
  912. m_pScrollBar->SetValue(itemY - ctall + tall);
  913. }
  914. else
  915. {
  916. // keep the current value
  917. }
  918. }
  919. else
  920. {
  921. // area isn't big enough, just remove the scrollbar
  922. m_pScrollBar->SetValue(0);
  923. }
  924. // reset scrollbar
  925. Repaint();
  926. }
  927. //-----------------------------------------------------------------------------
  928. // Purpose: sets background color & border
  929. //-----------------------------------------------------------------------------
  930. void SectionedListPanel::ApplySchemeSettings(IScheme *pScheme)
  931. {
  932. BaseClass::ApplySchemeSettings(pScheme);
  933. SetBgColor(GetSchemeColor("SectionedListPanel.BgColor", GetBgColor(), pScheme));
  934. SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
  935. FOR_EACH_LL( m_Items, j )
  936. {
  937. m_Items[j]->SetShowColumns( m_bShowColumns );
  938. }
  939. }
  940. //-----------------------------------------------------------------------------
  941. // Purpose:
  942. //-----------------------------------------------------------------------------
  943. void SectionedListPanel::SetHeaderFont( HFont hFont )
  944. {
  945. m_hHeaderFont = hFont;
  946. }
  947. //-----------------------------------------------------------------------------
  948. // Purpose:
  949. //-----------------------------------------------------------------------------
  950. HFont SectionedListPanel::GetHeaderFont( void ) const
  951. {
  952. return m_hHeaderFont;
  953. }
  954. //-----------------------------------------------------------------------------
  955. // Purpose:
  956. //-----------------------------------------------------------------------------
  957. void SectionedListPanel::SetRowFont( HFont hFont )
  958. {
  959. m_hRowFont = hFont;
  960. }
  961. //-----------------------------------------------------------------------------
  962. // Purpose:
  963. //-----------------------------------------------------------------------------
  964. HFont SectionedListPanel::GetRowFont( void ) const
  965. {
  966. return m_hRowFont;
  967. }
  968. //-----------------------------------------------------------------------------
  969. // Purpose:
  970. //-----------------------------------------------------------------------------
  971. void SectionedListPanel::ApplySettings(KeyValues *inResourceData)
  972. {
  973. BaseClass::ApplySettings(inResourceData);
  974. m_iLineSpacing = inResourceData->GetInt("linespacing", 0);
  975. if (!m_iLineSpacing)
  976. {
  977. m_iLineSpacing = DEFAULT_LINE_SPACING;
  978. }
  979. if (IsProportional())
  980. {
  981. m_iLineSpacing = scheme()->GetProportionalScaledValueEx(GetScheme(), m_iLineSpacing);
  982. }
  983. m_iSectionGap = inResourceData->GetInt("sectiongap", 0);
  984. if (!m_iSectionGap)
  985. {
  986. m_iSectionGap = DEFAULT_SECTION_GAP;
  987. }
  988. m_iLineGap = inResourceData->GetInt( "linegap", 0 );
  989. if (IsProportional())
  990. {
  991. m_iSectionGap = scheme()->GetProportionalScaledValueEx(GetScheme(), m_iSectionGap);
  992. m_iLineGap = scheme()->GetProportionalScaledValueEx( GetScheme(), m_iLineGap );
  993. }
  994. }
  995. //-----------------------------------------------------------------------------
  996. // Purpose: passes on proportional state to children
  997. //-----------------------------------------------------------------------------
  998. void SectionedListPanel::SetProportional(bool state)
  999. {
  1000. BaseClass::SetProportional(state);
  1001. // now setup the section headers and items
  1002. int i;
  1003. for (i = 0; i < m_Sections.Count(); i++)
  1004. {
  1005. m_Sections[i].m_pHeader->SetProportional(state);
  1006. }
  1007. FOR_EACH_LL( m_Items, j )
  1008. {
  1009. m_Items[j]->SetProportional(state);
  1010. }
  1011. }
  1012. //-----------------------------------------------------------------------------
  1013. // Purpose: sets whether or not the vertical scrollbar should ever be displayed
  1014. //-----------------------------------------------------------------------------
  1015. void SectionedListPanel::SetVerticalScrollbar(bool state)
  1016. {
  1017. m_bVerticalScrollbarEnabled = state;
  1018. }
  1019. //-----------------------------------------------------------------------------
  1020. // Purpose: adds a new section
  1021. //-----------------------------------------------------------------------------
  1022. void SectionedListPanel::AddSection(int sectionID, const char *name, SectionSortFunc_t sortFunc)
  1023. {
  1024. SectionedListPanelHeader *header = new SectionedListPanelHeader(this, name, sectionID);
  1025. AddSection(sectionID, header, sortFunc);
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. // Purpose: adds a new section
  1029. //-----------------------------------------------------------------------------
  1030. void SectionedListPanel::AddSection(int sectionID, const wchar_t *name, SectionSortFunc_t sortFunc)
  1031. {
  1032. SectionedListPanelHeader *header = new SectionedListPanelHeader(this, name, sectionID);
  1033. AddSection(sectionID, header, sortFunc);
  1034. }
  1035. //-----------------------------------------------------------------------------
  1036. // Purpose: Adds a new section, given object
  1037. //-----------------------------------------------------------------------------
  1038. void SectionedListPanel::AddSection(int sectionID, SectionedListPanelHeader *header, SectionSortFunc_t sortFunc)
  1039. {
  1040. header = SETUP_PANEL( header );
  1041. int index = m_Sections.AddToTail();
  1042. m_Sections[index].m_iID = sectionID;
  1043. m_Sections[index].m_pHeader = header;
  1044. m_Sections[index].m_pSortFunc = sortFunc;
  1045. m_Sections[index].m_bAlwaysVisible = false;
  1046. m_Sections[index].m_iMinimumHeight = 0;
  1047. }
  1048. //-----------------------------------------------------------------------------
  1049. // Purpose: removes all the sections from the current panel
  1050. //-----------------------------------------------------------------------------
  1051. void SectionedListPanel::RemoveAllSections()
  1052. {
  1053. for (int i = 0; i < m_Sections.Count(); i++)
  1054. {
  1055. if (!m_Sections.IsValidIndex(i))
  1056. continue;
  1057. m_Sections[i].m_pHeader->SetVisible(false);
  1058. m_Sections[i].m_pHeader->MarkForDeletion();
  1059. }
  1060. m_Sections.RemoveAll();
  1061. m_Sections.Purge();
  1062. m_SortedItems.RemoveAll();
  1063. InvalidateLayout();
  1064. ReSortList();
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. // Purpose: adds a new column to a section
  1068. //-----------------------------------------------------------------------------
  1069. bool SectionedListPanel::AddColumnToSection(int sectionID, const char *columnName, const char *columnText, int columnFlags, int width, HFont fallbackFont /*= INVALID_FONT*/ )
  1070. {
  1071. wchar_t wtext[64];
  1072. wchar_t *pwtext = g_pVGuiLocalize->Find(columnText);
  1073. if (!pwtext)
  1074. {
  1075. g_pVGuiLocalize->ConvertANSIToUnicode(columnText, wtext, sizeof(wtext));
  1076. pwtext = wtext;
  1077. }
  1078. return AddColumnToSection(sectionID, columnName, pwtext, columnFlags, width, fallbackFont );
  1079. }
  1080. //-----------------------------------------------------------------------------
  1081. // Purpose: as above but with wchar_t's
  1082. //-----------------------------------------------------------------------------
  1083. bool SectionedListPanel::AddColumnToSection(int sectionID, const char *columnName, const wchar_t *columnText, int columnFlags, int width, HFont fallbackFont /*= INVALID_FONT*/ )
  1084. {
  1085. int index = FindSectionIndexByID(sectionID);
  1086. if (index < 0)
  1087. return false;
  1088. section_t &section = m_Sections[index];
  1089. // add the new column to the sections' list
  1090. index = section.m_Columns.AddToTail();
  1091. column_t &column = section.m_Columns[index];
  1092. Q_strncpy(column.m_szColumnName, columnName, sizeof(column.m_szColumnName));
  1093. wcsncpy(column.m_szColumnText, columnText, sizeof(column.m_szColumnText) / sizeof(wchar_t));
  1094. column.m_szColumnText[sizeof(column.m_szColumnText) / sizeof(wchar_t) - 1] = 0;
  1095. column.m_iColumnFlags = columnFlags;
  1096. column.m_iWidth = width;
  1097. column.m_hFallbackFont = fallbackFont;
  1098. return true;
  1099. }
  1100. //-----------------------------------------------------------------------------
  1101. // Purpose: modifies the text in an existing column
  1102. //-----------------------------------------------------------------------------
  1103. bool SectionedListPanel::ModifyColumn(int sectionID, const char *columnName, const wchar_t *columnText)
  1104. {
  1105. int index = FindSectionIndexByID(sectionID);
  1106. if (index < 0)
  1107. return false;
  1108. section_t &section = m_Sections[index];
  1109. // find the specified column
  1110. int columnIndex;
  1111. for (columnIndex = 0; columnIndex < section.m_Columns.Count(); columnIndex++)
  1112. {
  1113. if (!stricmp(section.m_Columns[columnIndex].m_szColumnName, columnName))
  1114. break;
  1115. }
  1116. if (!section.m_Columns.IsValidIndex(columnIndex))
  1117. return false;
  1118. column_t &column = section.m_Columns[columnIndex];
  1119. // modify the text
  1120. wcsncpy(column.m_szColumnText, columnText, sizeof(column.m_szColumnText) / sizeof(wchar_t));
  1121. column.m_szColumnText[sizeof(column.m_szColumnText) / sizeof(wchar_t) - 1] = 0;
  1122. section.m_pHeader->InvalidateLayout();
  1123. return true;
  1124. }
  1125. //-----------------------------------------------------------------------------
  1126. // Purpose: adds an item to the list; returns itemID
  1127. //-----------------------------------------------------------------------------
  1128. int SectionedListPanel::AddItem(int sectionID, const KeyValues *data)
  1129. {
  1130. int itemID = GetNewItemButton();
  1131. ModifyItem(itemID, sectionID, data);
  1132. // not sorted but in list
  1133. m_SortedItems.AddToTail(m_Items[itemID]);
  1134. m_bSortNeeded = true;
  1135. return itemID;
  1136. }
  1137. //-----------------------------------------------------------------------------
  1138. // Purpose: modifies an existing item; returns false if the item does not exist
  1139. //-----------------------------------------------------------------------------
  1140. bool SectionedListPanel::ModifyItem(int itemID, int sectionID, const KeyValues *data)
  1141. {
  1142. if ( !m_Items.IsValidIndex(itemID) )
  1143. return false;
  1144. InvalidateLayout();
  1145. m_Items[itemID]->SetSectionID(sectionID);
  1146. m_Items[itemID]->SetData(data);
  1147. m_Items[itemID]->InvalidateLayout();
  1148. m_bSortNeeded = true;
  1149. return true;
  1150. }
  1151. //-----------------------------------------------------------------------------
  1152. // Purpose:
  1153. //-----------------------------------------------------------------------------
  1154. void SectionedListPanel::SetItemFgColor( int itemID, Color color )
  1155. {
  1156. Assert( m_Items.IsValidIndex(itemID) );
  1157. if ( !m_Items.IsValidIndex(itemID) )
  1158. return;
  1159. m_Items[itemID]->SetFgColor( color );
  1160. m_Items[itemID]->SetOverrideColors( true );
  1161. m_Items[itemID]->InvalidateLayout();
  1162. }
  1163. //=============================================================================
  1164. // HPE_BEGIN:
  1165. // [menglish] Setter for the background color similar to the foreground color
  1166. //=============================================================================
  1167. void SectionedListPanel::SetItemBgColor( int itemID, Color color )
  1168. {
  1169. Assert( m_Items.IsValidIndex(itemID) );
  1170. if ( !m_Items.IsValidIndex(itemID) )
  1171. return;
  1172. m_Items[itemID]->SetBgColor( color );
  1173. m_Items[itemID]->SetPaintBackgroundEnabled( true );
  1174. m_Items[itemID]->SetOverrideColors( true );
  1175. m_Items[itemID]->InvalidateLayout();
  1176. }
  1177. void SectionedListPanel::SetItemBgHorizFillInset( int itemID, int nInset )
  1178. {
  1179. Assert( m_Items.IsValidIndex( itemID ) );
  1180. if ( !m_Items.IsValidIndex( itemID ) )
  1181. return;
  1182. m_Items[itemID]->SetItemBgHorizFillInset( nInset );
  1183. }
  1184. void SectionedListPanel::SetItemFont( int itemID, HFont font )
  1185. {
  1186. Assert( m_Items.IsValidIndex(itemID) );
  1187. if ( !m_Items.IsValidIndex(itemID) )
  1188. return;
  1189. m_Items[itemID]->SetFont( font );
  1190. }
  1191. void SectionedListPanel::SetItemEnabled( int itemID, bool bEnabled )
  1192. {
  1193. Assert( m_Items.IsValidIndex(itemID) );
  1194. if ( !m_Items.IsValidIndex(itemID) )
  1195. return;
  1196. m_Items[itemID]->SetEnabled( bEnabled );
  1197. }
  1198. //=============================================================================
  1199. // HPE_END
  1200. //=============================================================================
  1201. //-----------------------------------------------------------------------------
  1202. // Purpose: sets the color of a section text & underline
  1203. //-----------------------------------------------------------------------------
  1204. void SectionedListPanel::SetSectionFgColor(int sectionID, Color color)
  1205. {
  1206. if (!m_Sections.IsValidIndex(sectionID))
  1207. return;
  1208. m_Sections[sectionID].m_pHeader->SetColor(color);
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // Purpose: added so you can change the divider color AFTER the main color.
  1212. //-----------------------------------------------------------------------------
  1213. void SectionedListPanel::SetSectionDividerColor( int sectionID, Color color)
  1214. {
  1215. if (!m_Sections.IsValidIndex(sectionID))
  1216. return;
  1217. m_Sections[sectionID].m_pHeader->SetDividerColor(color);
  1218. }
  1219. //-----------------------------------------------------------------------------
  1220. // Purpose:
  1221. //-----------------------------------------------------------------------------
  1222. void SectionedListPanel::SetSectionDrawDividerBar( int sectionID, bool bDraw )
  1223. {
  1224. if ( !m_Sections.IsValidIndex( sectionID ) )
  1225. return;
  1226. m_Sections[sectionID].m_pHeader->DrawDividerBar( bDraw );
  1227. }
  1228. //-----------------------------------------------------------------------------
  1229. // Purpose: forces a section to always be visible
  1230. //-----------------------------------------------------------------------------
  1231. void SectionedListPanel::SetSectionAlwaysVisible(int sectionID, bool visible)
  1232. {
  1233. if (!m_Sections.IsValidIndex(sectionID))
  1234. return;
  1235. m_Sections[sectionID].m_bAlwaysVisible = visible;
  1236. }
  1237. void SectionedListPanel::SetFontSection(int sectionID, HFont font)
  1238. {
  1239. if (!m_Sections.IsValidIndex(sectionID))
  1240. return;
  1241. m_Sections[sectionID].m_pHeader->SetFont(font);
  1242. }
  1243. void SectionedListPanel::SetSectionMinimumHeight(int sectionID, int iMinimumHeight)
  1244. {
  1245. if (!m_Sections.IsValidIndex(sectionID))
  1246. return;
  1247. m_Sections[sectionID].m_iMinimumHeight = iMinimumHeight;
  1248. InvalidateLayout();
  1249. }
  1250. //-----------------------------------------------------------------------------
  1251. // Purpose: removes an item from the list; returns false if the item does not exist or is already removed
  1252. //-----------------------------------------------------------------------------
  1253. bool SectionedListPanel::RemoveItem(int itemID)
  1254. {
  1255. if ( !m_Items.IsValidIndex(itemID) )
  1256. return false;
  1257. m_SortedItems.FindAndRemove(m_Items[itemID]);
  1258. m_bSortNeeded = true;
  1259. m_Items[itemID]->MarkForDeletion();
  1260. m_Items.Remove(itemID);
  1261. InvalidateLayout();
  1262. return true;
  1263. }
  1264. //-----------------------------------------------------------------------------
  1265. // Purpose: returns the number of columns in a section
  1266. //-----------------------------------------------------------------------------
  1267. int SectionedListPanel::GetColumnCountBySection(int sectionID)
  1268. {
  1269. int index = FindSectionIndexByID(sectionID);
  1270. if (index < 0)
  1271. return NULL;
  1272. return m_Sections[index].m_Columns.Size();
  1273. }
  1274. //-----------------------------------------------------------------------------
  1275. // Purpose: returns the name of a column by section and column index; returns NULL if there are no more columns
  1276. // valid range of columnIndex is [0, GetColumnCountBySection)
  1277. //-----------------------------------------------------------------------------
  1278. const char *SectionedListPanel::GetColumnNameBySection(int sectionID, int columnIndex)
  1279. {
  1280. int index = FindSectionIndexByID(sectionID);
  1281. if (index < 0 || columnIndex >= m_Sections[index].m_Columns.Size())
  1282. return NULL;
  1283. return m_Sections[index].m_Columns[columnIndex].m_szColumnName;
  1284. }
  1285. //-----------------------------------------------------------------------------
  1286. // Purpose: returns the text for a column by section and column index
  1287. //-----------------------------------------------------------------------------
  1288. const wchar_t *SectionedListPanel::GetColumnTextBySection(int sectionID, int columnIndex)
  1289. {
  1290. int index = FindSectionIndexByID(sectionID);
  1291. if (index < 0 || columnIndex >= m_Sections[index].m_Columns.Size())
  1292. return NULL;
  1293. return m_Sections[index].m_Columns[columnIndex].m_szColumnText;
  1294. }
  1295. //-----------------------------------------------------------------------------
  1296. // Purpose: returns the type of a column by section and column index
  1297. //-----------------------------------------------------------------------------
  1298. int SectionedListPanel::GetColumnFlagsBySection(int sectionID, int columnIndex)
  1299. {
  1300. int index = FindSectionIndexByID(sectionID);
  1301. if (index < 0)
  1302. return 0;
  1303. if (columnIndex >= m_Sections[index].m_Columns.Size())
  1304. return 0;
  1305. return m_Sections[index].m_Columns[columnIndex].m_iColumnFlags;
  1306. }
  1307. //-----------------------------------------------------------------------------
  1308. // Purpose:
  1309. //-----------------------------------------------------------------------------
  1310. int SectionedListPanel::GetColumnWidthBySection(int sectionID, int columnIndex)
  1311. {
  1312. int index = FindSectionIndexByID(sectionID);
  1313. if (index < 0)
  1314. return 0;
  1315. if (columnIndex >= m_Sections[index].m_Columns.Size())
  1316. return 0;
  1317. return m_Sections[index].m_Columns[columnIndex].m_iWidth;
  1318. }
  1319. //-----------------------------------------------------------------------------
  1320. // Purpose:
  1321. //-----------------------------------------------------------------------------
  1322. void SectionedListPanel::SetColumnWidthBySection(int sectionID, const char *columnName, int iWidth)
  1323. {
  1324. int index = FindSectionIndexByID(sectionID);
  1325. if (index < 0)
  1326. return;
  1327. section_t &section = m_Sections[index];
  1328. // find the specified column
  1329. int columnIndex;
  1330. for (columnIndex = 0; columnIndex < section.m_Columns.Count(); columnIndex++)
  1331. {
  1332. if (!stricmp(section.m_Columns[columnIndex].m_szColumnName, columnName))
  1333. break;
  1334. }
  1335. if (!section.m_Columns.IsValidIndex(columnIndex))
  1336. return;
  1337. column_t &column = section.m_Columns[columnIndex];
  1338. column.m_iWidth = iWidth;
  1339. // make sure the header for this section reloads with the new width
  1340. section.m_pHeader->InvalidateLayout();
  1341. }
  1342. //=============================================================================
  1343. // HPE_BEGIN:
  1344. // [menglish] Gets the column index by the string identifier
  1345. //=============================================================================
  1346. int SectionedListPanel::GetColumnIndexByName(int sectionID, char* name)
  1347. {
  1348. int index = FindSectionIndexByID(sectionID);
  1349. if (index < 0)
  1350. return 0;
  1351. for ( int columnIndex = 0; columnIndex < m_Sections[index].m_Columns.Count(); ++ columnIndex)
  1352. {
  1353. if( !V_strcmp( m_Sections[index].m_Columns[columnIndex].m_szColumnName, name ) )
  1354. return columnIndex;
  1355. }
  1356. return -1;
  1357. }
  1358. //=============================================================================
  1359. // HPE_END
  1360. //=============================================================================
  1361. //-----------------------------------------------------------------------------
  1362. // Purpose: returns -1 if section not found
  1363. //-----------------------------------------------------------------------------
  1364. int SectionedListPanel::FindSectionIndexByID(int sectionID)
  1365. {
  1366. for (int i = 0; i < m_Sections.Size(); i++)
  1367. {
  1368. if (m_Sections[i].m_iID == sectionID)
  1369. {
  1370. return i;
  1371. }
  1372. }
  1373. return -1;
  1374. }
  1375. //-----------------------------------------------------------------------------
  1376. // Purpose: Called when the scrollbar is moved
  1377. //-----------------------------------------------------------------------------
  1378. void SectionedListPanel::OnSliderMoved()
  1379. {
  1380. InvalidateLayout();
  1381. Repaint();
  1382. }
  1383. //-----------------------------------------------------------------------------
  1384. // Purpose: Scrolls the list according to the mouse wheel movement
  1385. //-----------------------------------------------------------------------------
  1386. void SectionedListPanel::OnMouseWheeled(int delta)
  1387. {
  1388. if (m_hEditModePanel.Get())
  1389. {
  1390. // ignore mouse wheel in edit mode, forward right up to parent
  1391. CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
  1392. return;
  1393. }
  1394. // scroll the window based on the delta
  1395. int val = m_pScrollBar->GetValue();
  1396. val -= (delta * BUTTON_HEIGHT_DEFAULT * 3);
  1397. m_pScrollBar->SetValue(val);
  1398. }
  1399. //-----------------------------------------------------------------------------
  1400. // Purpose: Resets the scrollbar position on size change
  1401. //-----------------------------------------------------------------------------
  1402. void SectionedListPanel::OnSizeChanged(int wide, int tall)
  1403. {
  1404. BaseClass::OnSizeChanged(wide, tall);
  1405. m_pScrollBar->SetValue(0);
  1406. InvalidateLayout();
  1407. Repaint();
  1408. }
  1409. //-----------------------------------------------------------------------------
  1410. // Purpose: deselects any items
  1411. //-----------------------------------------------------------------------------
  1412. void SectionedListPanel::OnMousePressed(MouseCode code)
  1413. {
  1414. //=============================================================================
  1415. // HPE_BEGIN:
  1416. // [tj] Only do this if clicking is enabled.
  1417. //=============================================================================
  1418. if (m_clickable){
  1419. ClearSelection();
  1420. }
  1421. //=============================================================================
  1422. // HPE_END
  1423. //=============================================================================}
  1424. }
  1425. //-----------------------------------------------------------------------------
  1426. // Purpose: deselects any items
  1427. //-----------------------------------------------------------------------------
  1428. void SectionedListPanel::ClearSelection( void )
  1429. {
  1430. SetSelectedItem((CItemButton *)NULL);
  1431. }
  1432. void SectionedListPanel::MoveSelectionDown( void )
  1433. {
  1434. int itemID = GetSelectedItem();
  1435. if (itemID == -1)
  1436. return;
  1437. if (!m_SortedItems.Count()) // if the list has been emptied
  1438. return;
  1439. int i;
  1440. for (i = 0; i < m_SortedItems.Count(); i++)
  1441. {
  1442. if (m_SortedItems[i]->GetID() == itemID)
  1443. break;
  1444. }
  1445. Assert(i != m_SortedItems.Count());
  1446. // we're already on the end
  1447. if (i >= m_SortedItems.Count() - 1)
  1448. return;
  1449. int newItemID = m_SortedItems[i + 1]->GetID();
  1450. SetSelectedItem(m_Items[newItemID]);
  1451. ScrollToItem(newItemID);
  1452. }
  1453. void SectionedListPanel::MoveSelectionUp( void )
  1454. {
  1455. int itemID = GetSelectedItem();
  1456. if (itemID == -1)
  1457. return;
  1458. if (!m_SortedItems.Count()) // if the list has been emptied
  1459. return;
  1460. int i;
  1461. for (i = 0; i < m_SortedItems.Count(); i++)
  1462. {
  1463. if (m_SortedItems[i]->GetID() == itemID)
  1464. break;
  1465. }
  1466. Assert(i != m_SortedItems.Count());
  1467. // we're already on the end
  1468. if (i == 0 || i >= m_SortedItems.Count() )
  1469. return;
  1470. int newItemID = m_SortedItems[i - 1]->GetID();
  1471. SetSelectedItem(m_Items[newItemID]);
  1472. ScrollToItem(newItemID);
  1473. }
  1474. void SectionedListPanel::NavigateTo( void )
  1475. {
  1476. BaseClass::NavigateTo();
  1477. if ( m_SortedItems.Count() )
  1478. {
  1479. int nItemID = m_SortedItems[ 0 ]->GetID();
  1480. SetSelectedItem( m_Items[ nItemID ] );
  1481. ScrollToItem( nItemID );
  1482. }
  1483. RequestFocus();
  1484. }
  1485. //-----------------------------------------------------------------------------
  1486. // Purpose: arrow key movement handler
  1487. //-----------------------------------------------------------------------------
  1488. void SectionedListPanel::OnKeyCodePressed( KeyCode code )
  1489. {
  1490. if (m_hEditModePanel.Get())
  1491. {
  1492. // ignore arrow keys in edit mode
  1493. // forward right up to parent so that tab focus change doesn't occur
  1494. CallParentFunction(new KeyValues("KeyCodePressed", "code", code));
  1495. return;
  1496. }
  1497. int buttonTall = GetSectionTall();
  1498. ButtonCode_t nButtonCode = GetBaseButtonCode( code );
  1499. if ( nButtonCode == KEY_XBUTTON_DOWN ||
  1500. nButtonCode == KEY_XSTICK1_DOWN ||
  1501. nButtonCode == KEY_XSTICK2_DOWN ||
  1502. nButtonCode == STEAMCONTROLLER_DPAD_DOWN ||
  1503. code == KEY_DOWN )
  1504. {
  1505. int itemID = GetSelectedItem();
  1506. MoveSelectionDown();
  1507. if ( itemID != GetSelectedItem() )
  1508. {
  1509. // Only eat the input if it did something
  1510. return;
  1511. }
  1512. }
  1513. else if ( nButtonCode == KEY_XBUTTON_UP ||
  1514. nButtonCode == KEY_XSTICK1_UP ||
  1515. nButtonCode == KEY_XSTICK2_UP ||
  1516. nButtonCode == STEAMCONTROLLER_DPAD_UP ||
  1517. code == KEY_UP)
  1518. {
  1519. int itemID = GetSelectedItem();
  1520. MoveSelectionUp();
  1521. if ( itemID != GetSelectedItem() )
  1522. {
  1523. // Only eat the input if it did something
  1524. return;
  1525. }
  1526. }
  1527. else if (code == KEY_PAGEDOWN)
  1528. {
  1529. // calculate info for # of rows
  1530. int cx, cy, cwide, ctall;
  1531. GetBounds(cx, cy, cwide, ctall);
  1532. int rowsperpage = ctall/buttonTall;
  1533. int itemID = GetSelectedItem();
  1534. int lastValidItem = itemID;
  1535. int secID = m_Items[itemID]->GetSectionID();
  1536. int i=0;
  1537. int row = m_SortedItems.Find(m_Items[itemID]);
  1538. while ( i < rowsperpage )
  1539. {
  1540. if ( m_SortedItems.IsValidIndex(++row) )
  1541. {
  1542. itemID = m_SortedItems[row]->GetID();
  1543. lastValidItem = itemID;
  1544. i++;
  1545. // if we switched sections, then count the section header as a row
  1546. if (m_Items[itemID]->GetSectionID() != secID)
  1547. {
  1548. secID = m_Items[itemID]->GetSectionID();
  1549. i++;
  1550. }
  1551. }
  1552. else
  1553. {
  1554. itemID = lastValidItem;
  1555. break;
  1556. }
  1557. }
  1558. SetSelectedItem(m_Items[itemID]);
  1559. ScrollToItem(itemID);
  1560. return;
  1561. }
  1562. else if (code == KEY_PAGEUP)
  1563. {
  1564. // calculate info for # of rows
  1565. int cx, cy, cwide, ctall;
  1566. GetBounds(cx, cy, cwide, ctall);
  1567. int rowsperpage = ctall/buttonTall;
  1568. int itemID = GetSelectedItem();
  1569. int lastValidItem = itemID;
  1570. int secID = m_Items[itemID]->GetSectionID();
  1571. int i=0;
  1572. int row = m_SortedItems.Find(m_Items[itemID]);
  1573. while ( i < rowsperpage )
  1574. {
  1575. if ( m_SortedItems.IsValidIndex(--row) )
  1576. {
  1577. itemID = m_SortedItems[row]->GetID();
  1578. lastValidItem = itemID;
  1579. i++;
  1580. // if we switched sections, then count the section header as a row
  1581. if (m_Items[itemID]->GetSectionID() != secID)
  1582. {
  1583. secID = m_Items[itemID]->GetSectionID();
  1584. i++;
  1585. }
  1586. }
  1587. else
  1588. {
  1589. SetSelectedItem(m_Items[lastValidItem]);
  1590. m_pScrollBar->SetValue(0);
  1591. return;
  1592. }
  1593. }
  1594. SetSelectedItem(m_Items[itemID]);
  1595. ScrollToItem(itemID);
  1596. return;
  1597. }
  1598. else if ( code == KEY_ENTER || nButtonCode == KEY_XBUTTON_A || nButtonCode == STEAMCONTROLLER_A )
  1599. {
  1600. Panel *pSelectedItem = m_hSelectedItem;
  1601. if ( pSelectedItem )
  1602. {
  1603. pSelectedItem->OnMousePressed( MOUSE_LEFT );
  1604. }
  1605. return;
  1606. }
  1607. BaseClass::OnKeyCodePressed( code );
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. // Purpose: Clears the list
  1611. //-----------------------------------------------------------------------------
  1612. void SectionedListPanel::DeleteAllItems()
  1613. {
  1614. FOR_EACH_LL( m_Items, i )
  1615. {
  1616. m_Items[i]->SetVisible(false);
  1617. m_Items[i]->Clear();
  1618. // don't delete, move to free list
  1619. int freeIndex = m_FreeItems.AddToTail();
  1620. m_FreeItems[freeIndex] = m_Items[i];
  1621. }
  1622. m_Items.RemoveAll();
  1623. m_SortedItems.RemoveAll();
  1624. m_hSelectedItem = NULL;
  1625. InvalidateLayout();
  1626. m_bSortNeeded = true;
  1627. }
  1628. //-----------------------------------------------------------------------------
  1629. // Purpose: Changes the current list selection
  1630. //-----------------------------------------------------------------------------
  1631. void SectionedListPanel::SetSelectedItem(CItemButton *item)
  1632. {
  1633. if (m_hSelectedItem.Get() == item)
  1634. return;
  1635. // deselect the current item
  1636. if (m_hSelectedItem.Get())
  1637. {
  1638. m_hSelectedItem->SetSelected(false);
  1639. }
  1640. // set the new item
  1641. m_hSelectedItem = item;
  1642. if (m_hSelectedItem.Get())
  1643. {
  1644. m_hSelectedItem->SetSelected(true);
  1645. }
  1646. Repaint();
  1647. PostActionSignal(new KeyValues("ItemSelected", "itemID", m_hSelectedItem.Get() ? m_hSelectedItem->GetID() : -1));
  1648. }
  1649. //-----------------------------------------------------------------------------
  1650. // Purpose:
  1651. //-----------------------------------------------------------------------------
  1652. int SectionedListPanel::GetSelectedItem()
  1653. {
  1654. if (m_hSelectedItem.Get())
  1655. {
  1656. return m_hSelectedItem->GetID();
  1657. }
  1658. return -1;
  1659. }
  1660. //-----------------------------------------------------------------------------
  1661. // Purpose: sets which item is currently selected
  1662. //-----------------------------------------------------------------------------
  1663. void SectionedListPanel::SetSelectedItem(int itemID)
  1664. {
  1665. if ( m_Items.IsValidIndex(itemID) )
  1666. {
  1667. SetSelectedItem(m_Items[itemID]);
  1668. }
  1669. }
  1670. //-----------------------------------------------------------------------------
  1671. // Purpose: returns the data of a selected item
  1672. //-----------------------------------------------------------------------------
  1673. KeyValues *SectionedListPanel::GetItemData(int itemID)
  1674. {
  1675. Assert(m_Items.IsValidIndex(itemID));
  1676. if ( !m_Items.IsValidIndex(itemID) )
  1677. return NULL;
  1678. return m_Items[itemID]->GetData();
  1679. }
  1680. //-----------------------------------------------------------------------------
  1681. // Purpose: returns what section an item is in
  1682. //-----------------------------------------------------------------------------
  1683. int SectionedListPanel::GetItemSection(int itemID)
  1684. {
  1685. if ( !m_Items.IsValidIndex(itemID) )
  1686. return -1;
  1687. return m_Items[itemID]->GetSectionID();
  1688. }
  1689. //-----------------------------------------------------------------------------
  1690. // Purpose: returns true if the itemID is valid for use
  1691. //-----------------------------------------------------------------------------
  1692. bool SectionedListPanel::IsItemIDValid(int itemID)
  1693. {
  1694. return m_Items.IsValidIndex(itemID);
  1695. }
  1696. //-----------------------------------------------------------------------------
  1697. // Purpose: returns true if the itemID is valid for use
  1698. //-----------------------------------------------------------------------------
  1699. int SectionedListPanel::GetHighestItemID()
  1700. {
  1701. return m_Items.MaxElementIndex();
  1702. }
  1703. //-----------------------------------------------------------------------------
  1704. // Purpose: item iterators
  1705. //-----------------------------------------------------------------------------
  1706. int SectionedListPanel::GetItemCount()
  1707. {
  1708. return m_SortedItems.Count();
  1709. }
  1710. //-----------------------------------------------------------------------------
  1711. // Purpose: item iterators
  1712. //-----------------------------------------------------------------------------
  1713. int SectionedListPanel::GetItemIDFromRow(int row)
  1714. {
  1715. if ( !m_SortedItems.IsValidIndex(row) )
  1716. return -1;
  1717. return m_SortedItems[row]->GetID();
  1718. }
  1719. //-----------------------------------------------------------------------------
  1720. // Purpose: returns the row that this itemID occupies. -1 if the itemID is invalid
  1721. //-----------------------------------------------------------------------------
  1722. int SectionedListPanel::GetRowFromItemID(int itemID)
  1723. {
  1724. for (int i = 0; i < m_SortedItems.Count(); i++)
  1725. {
  1726. if ( m_SortedItems[i]->GetID() == itemID )
  1727. {
  1728. return i;
  1729. }
  1730. }
  1731. return -1;
  1732. }
  1733. //-----------------------------------------------------------------------------
  1734. // Purpose: gets the local coordinates of a cell
  1735. //-----------------------------------------------------------------------------
  1736. bool SectionedListPanel::GetCellBounds(int itemID, int column, int &x, int &y, int &wide, int &tall)
  1737. {
  1738. x = y = wide = tall = 0;
  1739. if ( !IsItemIDValid(itemID) )
  1740. return false;
  1741. // get the item
  1742. CItemButton *item = m_Items[itemID];
  1743. if ( !item->IsVisible() )
  1744. return false;
  1745. //!! ignores column for now
  1746. item->GetBounds(x, y, wide, tall);
  1747. item->GetCellBounds(column, x, wide);
  1748. return true;
  1749. }
  1750. //-----------------------------------------------------------------------------
  1751. // Purpose: gets the local coordinates of a section header
  1752. //-----------------------------------------------------------------------------
  1753. bool SectionedListPanel::GetSectionHeaderBounds(int sectionID, int &x, int &y, int &wide, int &tall)
  1754. {
  1755. x = y = wide = tall = 0;
  1756. int index = FindSectionIndexByID(sectionID);
  1757. if (index < 0 || !m_Sections[index].m_pHeader )
  1758. return false;
  1759. m_Sections[index].m_pHeader->GetBounds( x, y, wide, tall );
  1760. return true;
  1761. }
  1762. //=============================================================================
  1763. // HPE_BEGIN:
  1764. // [menglish] Gets the local coordinates of a cell using the max width for every column
  1765. // Gets the local coordinates of a cell
  1766. //=============================================================================
  1767. bool SectionedListPanel::GetMaxCellBounds(int itemID, int column, int &x, int &y, int &wide, int &tall)
  1768. {
  1769. x = y = wide = tall = 0;
  1770. if ( !IsItemIDValid(itemID) )
  1771. return false;
  1772. // get the item
  1773. CItemButton *item = m_Items[itemID];
  1774. if ( !item->IsVisible() )
  1775. return false;
  1776. //!! ignores column for now
  1777. item->GetBounds(x, y, wide, tall);
  1778. item->GetMaxCellBounds(column, x, wide);
  1779. return true;
  1780. }
  1781. //-----------------------------------------------------------------------------
  1782. // Purpose: gets the local coordinates of a cell
  1783. //-----------------------------------------------------------------------------
  1784. bool SectionedListPanel::GetItemBounds(int itemID, int &x, int &y, int &wide, int &tall)
  1785. {
  1786. x = y = wide = tall = 0;
  1787. if ( !IsItemIDValid(itemID) )
  1788. return false;
  1789. // get the item
  1790. CItemButton *item = m_Items[itemID];
  1791. if ( !item->IsVisible() )
  1792. return false;
  1793. //!! ignores column for now
  1794. item->GetBounds(x, y, wide, tall);
  1795. return true;
  1796. }
  1797. //=============================================================================
  1798. // HPE_END
  1799. //=============================================================================
  1800. //-----------------------------------------------------------------------------
  1801. // Purpose: forces an item to redraw
  1802. //-----------------------------------------------------------------------------
  1803. void SectionedListPanel::InvalidateItem(int itemID)
  1804. {
  1805. if ( !IsItemIDValid(itemID) )
  1806. return;
  1807. m_Items[itemID]->InvalidateLayout();
  1808. m_Items[itemID]->Repaint();
  1809. }
  1810. //-----------------------------------------------------------------------------
  1811. // Purpose: set up a field for editing
  1812. //-----------------------------------------------------------------------------
  1813. void SectionedListPanel::EnterEditMode(int itemID, int column, vgui::Panel *editPanel)
  1814. {
  1815. m_hEditModePanel = editPanel;
  1816. m_iEditModeItemID = itemID;
  1817. m_iEditModeColumn = column;
  1818. editPanel->SetParent(this);
  1819. editPanel->SetVisible(true);
  1820. editPanel->RequestFocus();
  1821. editPanel->MoveToFront();
  1822. InvalidateLayout();
  1823. }
  1824. //-----------------------------------------------------------------------------
  1825. // Purpose: leaves editing mode
  1826. //-----------------------------------------------------------------------------
  1827. void SectionedListPanel::LeaveEditMode()
  1828. {
  1829. if (m_hEditModePanel.Get())
  1830. {
  1831. InvalidateItem(m_iEditModeItemID);
  1832. m_hEditModePanel->SetVisible(false);
  1833. m_hEditModePanel->SetParent((Panel *)NULL);
  1834. m_hEditModePanel = NULL;
  1835. }
  1836. }
  1837. //-----------------------------------------------------------------------------
  1838. // Purpose: returns true if we are currently in inline editing mode
  1839. //-----------------------------------------------------------------------------
  1840. bool SectionedListPanel::IsInEditMode()
  1841. {
  1842. return (m_hEditModePanel.Get() != NULL);
  1843. }
  1844. //-----------------------------------------------------------------------------
  1845. // Purpose: list used to match indexes in image columns to image pointers
  1846. //-----------------------------------------------------------------------------
  1847. void SectionedListPanel::SetImageList(ImageList *imageList, bool deleteImageListWhenDone)
  1848. {
  1849. m_bDeleteImageListWhenDone = deleteImageListWhenDone;
  1850. m_pImageList = imageList;
  1851. }
  1852. //-----------------------------------------------------------------------------
  1853. // Purpose:
  1854. //-----------------------------------------------------------------------------
  1855. void SectionedListPanel::OnSetFocus()
  1856. {
  1857. if (m_hSelectedItem.Get())
  1858. {
  1859. m_hSelectedItem->RequestFocus();
  1860. }
  1861. else
  1862. {
  1863. BaseClass::OnSetFocus();
  1864. }
  1865. }
  1866. //-----------------------------------------------------------------------------
  1867. // Purpose:
  1868. //-----------------------------------------------------------------------------
  1869. int SectionedListPanel::GetSectionTall()
  1870. {
  1871. if (m_Sections.Count())
  1872. {
  1873. HFont font = m_Sections[0].m_pHeader->GetFont();
  1874. if (font != INVALID_FONT)
  1875. {
  1876. return surface()->GetFontTall(font) + BUTTON_HEIGHT_SPACER;
  1877. }
  1878. }
  1879. return BUTTON_HEIGHT_DEFAULT;
  1880. }
  1881. //-----------------------------------------------------------------------------
  1882. // Purpose: returns the size required to fully draw the contents of the panel
  1883. //-----------------------------------------------------------------------------
  1884. void SectionedListPanel::GetContentSize(int &wide, int &tall)
  1885. {
  1886. // make sure our layout is done
  1887. if (IsLayoutInvalid())
  1888. {
  1889. if (m_bSortNeeded)
  1890. {
  1891. ReSortList();
  1892. m_bSortNeeded = false;
  1893. }
  1894. LayoutPanels(m_iContentHeight);
  1895. }
  1896. wide = GetWide();
  1897. tall = m_iContentHeight;
  1898. }
  1899. //-----------------------------------------------------------------------------
  1900. // Purpose: Returns the index of a new item button
  1901. //-----------------------------------------------------------------------------
  1902. int SectionedListPanel::GetNewItemButton()
  1903. {
  1904. int itemID = m_Items.AddToTail();
  1905. if (m_FreeItems.Count())
  1906. {
  1907. // reusing an existing CItemButton
  1908. m_Items[itemID] = m_FreeItems[m_FreeItems.Head()];
  1909. m_Items[itemID]->SetID(itemID);
  1910. m_Items[itemID]->SetVisible(true);
  1911. m_FreeItems.Remove(m_FreeItems.Head());
  1912. }
  1913. else
  1914. {
  1915. // create a new CItemButton
  1916. m_Items[itemID] = SETUP_PANEL(new CItemButton(this, itemID));
  1917. m_Items[itemID]->SetShowColumns( m_bShowColumns );
  1918. }
  1919. // Gross. Le's hope this isn't the only property that doesn't get defaulted
  1920. // properly when an item is recycled.....
  1921. m_Items[itemID]->SetEnabled( true );
  1922. return itemID;
  1923. }
  1924. //-----------------------------------------------------------------------------
  1925. // Purpose: Returns fallback font to use for text image for this column
  1926. // Input : sectionID -
  1927. // columnIndex -
  1928. // Output : virtual HFont
  1929. //-----------------------------------------------------------------------------
  1930. HFont SectionedListPanel::GetColumnFallbackFontBySection( int sectionID, int columnIndex )
  1931. {
  1932. int index = FindSectionIndexByID(sectionID);
  1933. if (index < 0)
  1934. return INVALID_FONT;
  1935. if (columnIndex >= m_Sections[index].m_Columns.Size())
  1936. return INVALID_FONT;
  1937. return m_Sections[index].m_Columns[columnIndex].m_hFallbackFont;
  1938. }
  1939. //-----------------------------------------------------------------------------
  1940. // Purpose:
  1941. //-----------------------------------------------------------------------------
  1942. Color *SectionedListPanel::GetColorOverrideForCell( int sectionID, int itemID, int columnID )
  1943. {
  1944. FOR_EACH_VEC( m_ColorOverrides, i )
  1945. {
  1946. if ( ( m_ColorOverrides[i].m_SectionID == sectionID ) &&
  1947. ( m_ColorOverrides[i].m_ItemID == itemID ) &&
  1948. ( m_ColorOverrides[i].m_ColumnID == columnID ) )
  1949. {
  1950. return &(m_ColorOverrides[i].m_clrOverride);
  1951. }
  1952. }
  1953. return NULL;
  1954. }
  1955. //-----------------------------------------------------------------------------
  1956. // Purpose:
  1957. //-----------------------------------------------------------------------------
  1958. void SectionedListPanel::SetColorOverrideForCell( int sectionID, int itemID, int columnID, Color clrOverride )
  1959. {
  1960. // is this value already in the override list?
  1961. FOR_EACH_VEC( m_ColorOverrides, i )
  1962. {
  1963. if ( ( m_ColorOverrides[i].m_SectionID == sectionID ) &&
  1964. ( m_ColorOverrides[i].m_ItemID == itemID ) &&
  1965. ( m_ColorOverrides[i].m_ColumnID == columnID ) )
  1966. {
  1967. m_ColorOverrides[i].m_clrOverride = clrOverride;
  1968. return;
  1969. }
  1970. }
  1971. int iIndex = m_ColorOverrides.AddToTail();
  1972. m_ColorOverrides[iIndex].m_SectionID = sectionID;
  1973. m_ColorOverrides[iIndex].m_ItemID = itemID;
  1974. m_ColorOverrides[iIndex].m_ColumnID = columnID;
  1975. m_ColorOverrides[iIndex].m_clrOverride = clrOverride;
  1976. }