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.

476 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "vgui/MouseCode.h"
  8. #include "vgui/IInput.h"
  9. #include "vgui/IScheme.h"
  10. #include "vgui/ISurface.h"
  11. #include "vgui_controls/EditablePanel.h"
  12. #include "vgui_controls/ScrollBar.h"
  13. #include "vgui_controls/Label.h"
  14. #include "vgui_controls/Button.h"
  15. #include "vgui_controls/Controls.h"
  16. #include "vgui_controls/PanelListPanel.h"
  17. #include "KeyValues.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. using namespace vgui;
  21. DECLARE_BUILD_FACTORY( PanelListPanel );
  22. //-----------------------------------------------------------------------------
  23. // Purpose: Constructor
  24. //-----------------------------------------------------------------------------
  25. PanelListPanel::PanelListPanel( vgui::Panel *parent, char const *panelName ) : EditablePanel( parent, panelName )
  26. {
  27. SetBounds( 0, 0, 100, 100 );
  28. m_vbar = new ScrollBar(this, "PanelListPanelVScroll", true);
  29. m_vbar->SetVisible(false);
  30. m_vbar->AddActionSignalTarget( this );
  31. m_pPanelEmbedded = new EditablePanel(this, "PanelListEmbedded");
  32. m_pPanelEmbedded->SetBounds(0, 0, 20, 20);
  33. m_pPanelEmbedded->SetPaintBackgroundEnabled( false );
  34. m_pPanelEmbedded->SetPaintBorderEnabled(false);
  35. m_iFirstColumnWidth = 100; // default width
  36. m_iNumColumns = 1; // 1 column by default
  37. if ( IsProportional() )
  38. {
  39. m_iDefaultHeight = scheme()->GetProportionalScaledValueEx( GetScheme(), DEFAULT_HEIGHT );
  40. m_iPanelBuffer = scheme()->GetProportionalScaledValueEx( GetScheme(), PANELBUFFER );
  41. }
  42. else
  43. {
  44. m_iDefaultHeight = DEFAULT_HEIGHT;
  45. m_iPanelBuffer = PANELBUFFER;
  46. }
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose: Destructor
  50. //-----------------------------------------------------------------------------
  51. PanelListPanel::~PanelListPanel()
  52. {
  53. // free data from table
  54. DeleteAllItems();
  55. }
  56. void PanelListPanel::SetVerticalBufferPixels( int buffer )
  57. {
  58. m_iPanelBuffer = buffer;
  59. InvalidateLayout();
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose: counts the total vertical pixels
  63. //-----------------------------------------------------------------------------
  64. int PanelListPanel::ComputeVPixelsNeeded()
  65. {
  66. int iCurrentItem = 0;
  67. int iLargestH = 0;
  68. int pixels = 0;
  69. for ( int i = 0; i < m_SortedItems.Count(); i++ )
  70. {
  71. Panel *panel = m_DataItems[ m_SortedItems[i] ].panel;
  72. if ( !panel )
  73. continue;
  74. if ( panel->IsLayoutInvalid() )
  75. {
  76. panel->InvalidateLayout( true );
  77. }
  78. int iCurrentColumn = iCurrentItem % m_iNumColumns;
  79. int w, h;
  80. panel->GetSize( w, h );
  81. if ( iLargestH < h )
  82. iLargestH = h;
  83. if ( iCurrentColumn == 0 )
  84. pixels += m_iPanelBuffer; // add in buffer. between rows.
  85. if ( iCurrentColumn >= m_iNumColumns - 1 )
  86. {
  87. pixels += iLargestH;
  88. iLargestH = 0;
  89. }
  90. iCurrentItem++;
  91. }
  92. // Add in remaining largest height
  93. pixels += iLargestH;
  94. pixels += m_iPanelBuffer; // add in buffer below last item
  95. return pixels;
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Purpose: Returns the panel to use to render a cell
  99. //-----------------------------------------------------------------------------
  100. Panel *PanelListPanel::GetCellRenderer( int row )
  101. {
  102. if ( !m_SortedItems.IsValidIndex(row) )
  103. return NULL;
  104. Panel *panel = m_DataItems[ m_SortedItems[row] ].panel;
  105. return panel;
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Purpose: adds an item to the view
  109. // data->GetName() is used to uniquely identify an item
  110. // data sub items are matched against column header name to be used in the table
  111. //-----------------------------------------------------------------------------
  112. int PanelListPanel::AddItem( Panel *labelPanel, Panel *panel )
  113. {
  114. Assert(panel);
  115. if ( labelPanel )
  116. {
  117. labelPanel->SetParent( m_pPanelEmbedded );
  118. }
  119. panel->SetParent( m_pPanelEmbedded );
  120. int itemID = m_DataItems.AddToTail();
  121. DATAITEM &newitem = m_DataItems[itemID];
  122. newitem.labelPanel = labelPanel;
  123. newitem.panel = panel;
  124. m_SortedItems.AddToTail(itemID);
  125. InvalidateLayout();
  126. return itemID;
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: iteration accessor
  130. //-----------------------------------------------------------------------------
  131. int PanelListPanel::GetItemCount() const
  132. {
  133. return m_DataItems.Count();
  134. }
  135. int PanelListPanel::GetItemIDFromRow( int nRow ) const
  136. {
  137. if ( nRow < 0 || nRow >= GetItemCount() )
  138. return m_DataItems.InvalidIndex();
  139. return m_SortedItems[ nRow ];
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Iteration. Use these until they return InvalidItemID to iterate all the items.
  143. //-----------------------------------------------------------------------------
  144. int PanelListPanel::FirstItem() const
  145. {
  146. return m_DataItems.Head();
  147. }
  148. int PanelListPanel::NextItem( int nItemID ) const
  149. {
  150. return m_DataItems.Next( nItemID );
  151. }
  152. int PanelListPanel::InvalidItemID() const
  153. {
  154. return m_DataItems.InvalidIndex( );
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose: returns label panel for this itemID
  158. //-----------------------------------------------------------------------------
  159. Panel *PanelListPanel::GetItemLabel(int itemID)
  160. {
  161. if ( !m_DataItems.IsValidIndex(itemID) )
  162. return NULL;
  163. return m_DataItems[itemID].labelPanel;
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose: returns label panel for this itemID
  167. //-----------------------------------------------------------------------------
  168. Panel *PanelListPanel::GetItemPanel(int itemID)
  169. {
  170. if ( !m_DataItems.IsValidIndex(itemID) )
  171. return NULL;
  172. return m_DataItems[itemID].panel;
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. //-----------------------------------------------------------------------------
  177. void PanelListPanel::RemoveItem(int itemID)
  178. {
  179. if ( !m_DataItems.IsValidIndex(itemID) )
  180. return;
  181. DATAITEM &item = m_DataItems[itemID];
  182. if ( item.panel )
  183. {
  184. item.panel->MarkForDeletion();
  185. }
  186. if ( item.labelPanel )
  187. {
  188. item.labelPanel->MarkForDeletion();
  189. }
  190. m_DataItems.Remove(itemID);
  191. m_SortedItems.FindAndRemove(itemID);
  192. InvalidateLayout();
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: clears and deletes all the memory used by the data items
  196. //-----------------------------------------------------------------------------
  197. void PanelListPanel::DeleteAllItems()
  198. {
  199. FOR_EACH_LL( m_DataItems, i )
  200. {
  201. if ( m_DataItems[i].panel )
  202. {
  203. m_DataItems[i].panel->MarkForDeletion();
  204. m_DataItems[i].panel = NULL;
  205. }
  206. }
  207. m_DataItems.RemoveAll();
  208. m_SortedItems.RemoveAll();
  209. InvalidateLayout();
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: clears and deletes all the memory used by the data items
  213. //-----------------------------------------------------------------------------
  214. void PanelListPanel::RemoveAll()
  215. {
  216. m_DataItems.RemoveAll();
  217. m_SortedItems.RemoveAll();
  218. // move the scrollbar to the top of the list
  219. m_vbar->SetValue(0);
  220. InvalidateLayout();
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose:
  224. //-----------------------------------------------------------------------------
  225. void PanelListPanel::OnSizeChanged(int wide, int tall)
  226. {
  227. BaseClass::OnSizeChanged(wide, tall);
  228. InvalidateLayout();
  229. Repaint();
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose: relayouts out the panel after any internal changes
  233. //-----------------------------------------------------------------------------
  234. void PanelListPanel::PerformLayout()
  235. {
  236. int wide, tall;
  237. GetSize( wide, tall );
  238. int vpixels = ComputeVPixelsNeeded();
  239. m_vbar->SetRange( 0, vpixels );
  240. m_vbar->SetRangeWindow( tall );
  241. m_vbar->SetButtonPressedScrollValue( tall / 4 ); // standard height of labels/buttons etc.
  242. m_vbar->SetPos( wide - m_vbar->GetWide() - 2, 0 );
  243. m_vbar->SetSize( m_vbar->GetWide(), tall - 2 );
  244. int top = m_vbar->GetValue();
  245. m_pPanelEmbedded->SetPos( 0, -top );
  246. m_pPanelEmbedded->SetSize( wide - m_vbar->GetWide(), vpixels ); // scrollbar will sit on top (zpos set explicitly)
  247. bool bScrollbarVisible = true;
  248. // If we're supposed to automatically hide the scrollbar when unnecessary, check it now
  249. if ( m_bAutoHideScrollbar )
  250. {
  251. bScrollbarVisible = (m_pPanelEmbedded->GetTall() > tall);
  252. }
  253. m_vbar->SetVisible( bScrollbarVisible );
  254. // Now lay out the controls on the embedded panel
  255. int y = 0;
  256. int h = 0;
  257. int totalh = 0;
  258. int xpos = m_iFirstColumnWidth + m_iPanelBuffer;
  259. int iColumnWidth = ( wide - xpos - m_vbar->GetWide() - 12 ) / m_iNumColumns;
  260. for ( int i = 0; i < m_SortedItems.Count(); i++ )
  261. {
  262. int iCurrentColumn = i % m_iNumColumns;
  263. // add in a little buffer between panels
  264. if ( iCurrentColumn == 0 )
  265. y += m_iPanelBuffer;
  266. DATAITEM &item = m_DataItems[ m_SortedItems[i] ];
  267. if ( h < item.panel->GetTall() )
  268. h = item.panel->GetTall();
  269. if ( item.labelPanel )
  270. {
  271. item.labelPanel->SetBounds( 0, y, m_iFirstColumnWidth, item.panel->GetTall() );
  272. }
  273. item.panel->SetBounds( xpos + iCurrentColumn * iColumnWidth, y, iColumnWidth, item.panel->GetTall() );
  274. if ( iCurrentColumn >= m_iNumColumns - 1 )
  275. {
  276. y += h;
  277. totalh += h;
  278. h = 0;
  279. }
  280. }
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose: scheme settings
  284. //-----------------------------------------------------------------------------
  285. void PanelListPanel::ApplySchemeSettings(IScheme *pScheme)
  286. {
  287. BaseClass::ApplySchemeSettings(pScheme);
  288. SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
  289. SetBgColor(GetSchemeColor("ListPanel.BgColor", GetBgColor(), pScheme));
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose:
  293. //-----------------------------------------------------------------------------
  294. void PanelListPanel::OnSliderMoved( int position )
  295. {
  296. InvalidateLayout();
  297. Repaint();
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose:
  301. //-----------------------------------------------------------------------------
  302. void PanelListPanel::MoveScrollBarToTop()
  303. {
  304. m_vbar->SetValue(0);
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Purpose:
  308. //-----------------------------------------------------------------------------
  309. void PanelListPanel::SetFirstColumnWidth( int width )
  310. {
  311. m_iFirstColumnWidth = width;
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Purpose: data accessor
  315. //-----------------------------------------------------------------------------
  316. int PanelListPanel::GetFirstColumnWidth()
  317. {
  318. return m_iFirstColumnWidth;
  319. }
  320. void PanelListPanel::SetNumColumns( int iNumColumns )
  321. {
  322. m_iNumColumns = iNumColumns;
  323. }
  324. int PanelListPanel::GetNumColumns( void )
  325. {
  326. return m_iNumColumns;
  327. }
  328. //-----------------------------------------------------------------------------
  329. // Purpose: moves the scrollbar with the mousewheel
  330. //-----------------------------------------------------------------------------
  331. void PanelListPanel::OnMouseWheeled(int delta)
  332. {
  333. int val = m_vbar->GetValue();
  334. val -= (delta * DEFAULT_HEIGHT);
  335. m_vbar->SetValue(val);
  336. }
  337. //-----------------------------------------------------------------------------
  338. // Purpose: selection handler
  339. //-----------------------------------------------------------------------------
  340. void PanelListPanel::SetSelectedPanel( Panel *panel )
  341. {
  342. if ( panel != m_hSelectedItem )
  343. {
  344. // notify the panels of the selection change
  345. if ( m_hSelectedItem )
  346. {
  347. PostMessage( m_hSelectedItem.Get(), new KeyValues("PanelSelected", "state", 0) );
  348. }
  349. if ( panel )
  350. {
  351. PostMessage( panel, new KeyValues("PanelSelected", "state", 1) );
  352. }
  353. m_hSelectedItem = panel;
  354. }
  355. }
  356. //-----------------------------------------------------------------------------
  357. // Purpose: data accessor
  358. //-----------------------------------------------------------------------------
  359. Panel *PanelListPanel::GetSelectedPanel()
  360. {
  361. return m_hSelectedItem;
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose:
  365. //-----------------------------------------------------------------------------
  366. void PanelListPanel::ScrollToItem( int itemNumber )
  367. {
  368. if (!m_vbar->IsVisible())
  369. {
  370. return;
  371. }
  372. DATAITEM& item = m_DataItems[ m_SortedItems[ itemNumber ] ];
  373. if ( !item.panel )
  374. return;
  375. int x, y;
  376. item.panel->GetPos( x, y );
  377. int lx, ly;
  378. lx = x;
  379. ly = y;
  380. m_pPanelEmbedded->LocalToScreen( lx, ly );
  381. ScreenToLocal( lx, ly );
  382. int h = item.panel->GetTall();
  383. if ( ly >= 0 && ly + h < GetTall() )
  384. return;
  385. m_vbar->SetValue( y );
  386. InvalidateLayout();
  387. }