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.

484 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "tabwindow.h"
  9. #include "DrawHelper.h"
  10. //-----------------------------------------------------------------------------
  11. // Purpose: Constructor
  12. // Input : *parent -
  13. // x -
  14. // y -
  15. // w -
  16. // h -
  17. // id -
  18. // style -
  19. //-----------------------------------------------------------------------------
  20. CTabWindow::CTabWindow( mxWindow *parent, int x, int y, int w, int h, int id /*= 0*/, int style /*=0*/ )
  21. : mxWindow( parent, x, y, w, h, "", style )
  22. {
  23. setId( id );
  24. m_nSelected = -1;
  25. m_nRowHeight = 20;
  26. m_nRowsRequired = 1;
  27. m_nTabWidth = 80;
  28. m_nPixelDelta = 3;
  29. m_bInverted = false;
  30. m_bRightJustify = false;
  31. SetColor( COLOR_BG, GetSysColor( COLOR_BTNFACE ) );
  32. SetColor( COLOR_FG, GetSysColor( COLOR_INACTIVECAPTION ) );
  33. SetColor( COLOR_FG_SELECTED, GetSysColor( COLOR_ACTIVECAPTION ) );
  34. SetColor( COLOR_HILITE, GetSysColor( COLOR_3DSHADOW ) );
  35. SetColor( COLOR_HILITE_SELECTED, GetSysColor( COLOR_3DHILIGHT ) );
  36. SetColor( COLOR_TEXT, GetSysColor( COLOR_BTNTEXT ) );
  37. SetColor( COLOR_TEXT_SELECTED, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
  38. SceneManager_AddWindowStyle( this, WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. // Output : CTabWindow::~CTabWindow
  43. //-----------------------------------------------------------------------------
  44. CTabWindow::~CTabWindow ( void )
  45. {
  46. removeAll();
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose:
  50. // Input : index -
  51. // clr -
  52. //-----------------------------------------------------------------------------
  53. void CTabWindow::SetColor( int index, COLORREF clr )
  54. {
  55. if ( index < 0 || index >= NUM_COLORS )
  56. return;
  57. m_Colors[ index ] = clr;
  58. }
  59. void CTabWindow::SetInverted( bool invert )
  60. {
  61. m_bInverted = invert;
  62. RecomputeLayout( w2() );
  63. }
  64. void CTabWindow::SetRightJustify( bool rightjustify )
  65. {
  66. m_bRightJustify = true;
  67. RecomputeLayout( w2() );
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose: Tabs are sized to string content
  71. // Input : rcClient -
  72. // tabRect -
  73. // tabNum -
  74. //-----------------------------------------------------------------------------
  75. void CTabWindow::GetTabRect( const RECT& rcClient, RECT& tabRect, int tabNum )
  76. {
  77. tabRect = m_Items[ tabNum ].rect;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. // Input : drawHelper -
  82. // rcClient -
  83. // tabnum -
  84. // selected -
  85. //-----------------------------------------------------------------------------
  86. void CTabWindow::DrawTab( CDrawHelper& drawHelper, RECT& rcClient, int tabnum, bool selected )
  87. {
  88. RECT rcTab;
  89. if ( tabnum < 0 || tabnum >= m_Items.Size() )
  90. return;
  91. #if defined( _DEBUG )
  92. CETItem *p = &m_Items[ tabnum ];
  93. Assert( p );
  94. #endif
  95. GetTabRect( rcClient, rcTab, tabnum );
  96. COLORREF fgcolor = m_Colors[ selected ? COLOR_FG_SELECTED : COLOR_FG ];
  97. COLORREF hilightcolor = m_Colors[ selected ? COLOR_HILITE_SELECTED : COLOR_HILITE ];
  98. COLORREF text = m_Colors[ selected ? COLOR_TEXT_SELECTED : COLOR_TEXT ];
  99. // Create a trapezoid/paralleogram
  100. POINT region[4];
  101. int cPoints = 4;
  102. OffsetRect( &rcTab, 0, m_bInverted ? 1 : -1 );
  103. if ( m_bInverted )
  104. {
  105. region[ 0 ].x = rcTab.left - m_nPixelDelta;
  106. region[ 0 ].y = rcTab.top;
  107. region[ 1 ].x = rcTab.right + m_nPixelDelta;
  108. region[ 1 ].y = rcTab.top;
  109. region[ 2 ].x = rcTab.right - m_nPixelDelta;
  110. region[ 2 ].y = rcTab.bottom;
  111. region[ 3 ].x = rcTab.left + m_nPixelDelta;
  112. region[ 3 ].y = rcTab.bottom;
  113. }
  114. else
  115. {
  116. region[ 0 ].x = rcTab.left + m_nPixelDelta;
  117. region[ 0 ].y = rcTab.top;
  118. region[ 1 ].x = rcTab.right - m_nPixelDelta;
  119. region[ 1 ].y = rcTab.top;
  120. region[ 2 ].x = rcTab.right + m_nPixelDelta;
  121. region[ 2 ].y = rcTab.bottom;
  122. region[ 3 ].x = rcTab.left - m_nPixelDelta;
  123. region[ 3 ].y = rcTab.bottom;
  124. }
  125. HDC dc = drawHelper.GrabDC();
  126. HRGN rgn = CreatePolygonRgn( region, cPoints, ALTERNATE );
  127. int oldPF = SetPolyFillMode( dc, ALTERNATE );
  128. HBRUSH brBg = CreateSolidBrush( fgcolor );
  129. HBRUSH brBorder = CreateSolidBrush( hilightcolor );
  130. //HBRUSH brInset = CreateSolidBrush( fgcolor );
  131. FillRgn( dc, rgn, brBg );
  132. FrameRgn( dc, rgn, brBorder, 1, 1 );
  133. SetPolyFillMode( dc, oldPF );
  134. DeleteObject( rgn );
  135. DeleteObject( brBg );
  136. DeleteObject( brBorder );
  137. //DeleteObject( brInset );
  138. // Position label
  139. InflateRect( &rcTab, -5, 0 );
  140. OffsetRect( &rcTab, 2, 0 );
  141. // Draw label
  142. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, text, rcTab, "%s%s", getPrefix( tabnum ), getLabel( tabnum ) );
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose:
  146. //-----------------------------------------------------------------------------
  147. void CTabWindow::redraw( void )
  148. {
  149. CDrawHelper drawHelper( this, m_Colors[ COLOR_BG ] );
  150. int liney = m_bInverted ? 1 : h2() - 2;
  151. drawHelper.DrawColoredLine( m_Colors[ COLOR_HILITE ], PS_SOLID, 1, 0, liney, w(), liney );
  152. RECT rc;
  153. drawHelper.GetClientRect( rc );
  154. // Draw non-selected first
  155. for ( int i = 0 ; i < m_Items.Size(); i++ )
  156. {
  157. if ( i == m_nSelected )
  158. continue;
  159. DrawTab( drawHelper, rc, i );
  160. }
  161. // Draw selected last, so that it appears to pop to top of z order
  162. if ( m_nSelected >= 0 && m_nSelected < m_Items.Size() )
  163. {
  164. DrawTab( drawHelper, rc, m_nSelected, true );
  165. }
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. // Input : mx -
  170. // my -
  171. // Output : int
  172. //-----------------------------------------------------------------------------
  173. int CTabWindow::GetItemUnderMouse( int mx, int my )
  174. {
  175. RECT rcClient;
  176. GetClientRect( (HWND)getHandle(), &rcClient );
  177. for ( int i = 0; i < m_Items.Size() ; i++ )
  178. {
  179. RECT rcTab;
  180. GetTabRect( rcClient, rcTab, i );
  181. if ( mx < rcTab.left ||
  182. mx > rcTab.right ||
  183. my < rcTab.top ||
  184. my > rcTab.bottom )
  185. {
  186. continue;
  187. }
  188. return i;
  189. }
  190. return -1;
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose:
  194. // Input : *event -
  195. // Output : int CTabWindow::handleEvent
  196. //-----------------------------------------------------------------------------
  197. int CTabWindow::handleEvent (mxEvent *event)
  198. {
  199. int iret = 0;
  200. switch ( event->event )
  201. {
  202. case mxEvent::MouseDown:
  203. {
  204. int item = GetItemUnderMouse( (short)event->x, (short)event->y );
  205. if ( item != -1 )
  206. {
  207. m_nSelected = item;
  208. redraw();
  209. // Send CBN_SELCHANGE WM_COMMAND message to parent
  210. HWND parent = (HWND)( getParent() ? getParent()->getHandle() : NULL );
  211. if ( parent )
  212. {
  213. LPARAM lp;
  214. WPARAM wp;
  215. wp = MAKEWPARAM( getId(), CBN_SELCHANGE );
  216. lp = (long)getHandle();
  217. PostMessage( parent, WM_COMMAND, wp, lp );
  218. }
  219. iret = 1;
  220. }
  221. if ( event->buttons & mxEvent::MouseRightButton )
  222. {
  223. ShowRightClickMenu( (short)event->x, (short)event->y );
  224. iret = 1;
  225. }
  226. }
  227. break;
  228. case mxEvent::Size:
  229. {
  230. RecomputeLayout( w2() );
  231. }
  232. break;
  233. }
  234. return iret;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose: Add string to table
  238. // Input : *item -
  239. //-----------------------------------------------------------------------------
  240. void CTabWindow::add( const char *item )
  241. {
  242. m_Items.AddToTail();
  243. CETItem *p = &m_Items[ m_Items.Size() - 1 ];
  244. Assert( p );
  245. Q_memset( &p->rect, 0, sizeof( p->rect) );
  246. strcpy( p->m_szString, item );
  247. p->m_szPrefix[ 0 ] = 0;
  248. m_nSelected = min( m_nSelected, m_Items.Size() - 1 );
  249. m_nSelected = max( m_nSelected, 0 );
  250. RecomputeLayout( w2() );
  251. redraw();
  252. }
  253. void CTabWindow::setPrefix( int item, char const *prefix )
  254. {
  255. if ( item < 0 || item >= m_Items.Size() )
  256. return;
  257. strncpy( m_Items[ item ].m_szPrefix, prefix, sizeof( m_Items[ item ].m_szPrefix ) );
  258. // RecomputeLayout( w2() );
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose: Change selected item
  262. // Input : index -
  263. //-----------------------------------------------------------------------------
  264. void CTabWindow::select( int index )
  265. {
  266. if ( index < 0 || index >= m_Items.Size() )
  267. return;
  268. m_nSelected = index;
  269. redraw();
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose: Remove a string
  273. // Input : index -
  274. //-----------------------------------------------------------------------------
  275. void CTabWindow::remove( int index )
  276. {
  277. if ( index < 0 || index >= m_Items.Size() )
  278. return;
  279. m_Items.Remove( index );
  280. m_nSelected = min( m_nSelected, m_Items.Size() - 1 );
  281. m_nSelected = max( m_nSelected, 0 );
  282. RecomputeLayout( w2() );
  283. redraw();
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose: Clear out everything
  287. //-----------------------------------------------------------------------------
  288. void CTabWindow::removeAll()
  289. {
  290. m_nSelected = -1;
  291. m_Items.RemoveAll();
  292. RecomputeLayout( w2() );
  293. redraw();
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose:
  297. // Output : int
  298. //-----------------------------------------------------------------------------
  299. int CTabWindow::getItemCount () const
  300. {
  301. return m_Items.Size();
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose:
  305. // Output : int
  306. //-----------------------------------------------------------------------------
  307. int CTabWindow::getSelectedIndex () const
  308. {
  309. // Convert based on override index
  310. return m_nSelected;
  311. }
  312. char const *CTabWindow::getLabel( int item )
  313. {
  314. if ( item < 0 || item >= m_Items.Count() )
  315. return "";
  316. return m_Items[ item ].m_szString;
  317. }
  318. char const *CTabWindow::getPrefix( int item )
  319. {
  320. if ( item < 0 || item >= m_Items.Count() )
  321. return "";
  322. return m_Items[ item ].m_szPrefix;
  323. }
  324. void CTabWindow::SetRowHeight( int rowheight )
  325. {
  326. m_nRowHeight = rowheight;
  327. RecomputeLayout( w2() );
  328. redraw();
  329. }
  330. int CTabWindow::GetBestHeight( int width )
  331. {
  332. return RecomputeLayout( width, false ) * m_nRowHeight;
  333. }
  334. int CTabWindow::RecomputeLayout( int windowWidth, bool dolayout /*=true*/ )
  335. {
  336. // Draw non-selected first
  337. int curedge = m_nPixelDelta + 1;
  338. int curtop = 0;
  339. if ( m_bRightJustify )
  340. {
  341. curedge = windowWidth - ( m_nPixelDelta + 1 ) - 5;
  342. }
  343. int startedge = curedge;
  344. int currentrow = 0;
  345. for ( int i = 0 ; i < m_Items.Size(); i++ )
  346. {
  347. CETItem *p = &m_Items[ i ];
  348. RECT rc;
  349. int textwidth = CDrawHelper::CalcTextWidth( "Arial", 9, FW_NORMAL, "%s%s", p->m_szPrefix, p->m_szString ) + 15;
  350. if ( !m_bRightJustify )
  351. {
  352. // Starting column
  353. if ( curedge + textwidth > windowWidth )
  354. {
  355. curedge = startedge;
  356. curtop += m_nRowHeight;
  357. currentrow++;
  358. }
  359. rc.left = curedge;
  360. rc.right = curedge + textwidth;
  361. rc.top = curtop + 2;
  362. rc.bottom = curtop + m_nRowHeight;
  363. curedge += textwidth;
  364. p->rect = rc;
  365. }
  366. else
  367. {
  368. // Starting column
  369. if ( curedge - textwidth < 0 )
  370. {
  371. curedge = startedge;
  372. curtop += m_nRowHeight;
  373. currentrow++;
  374. }
  375. rc.left = curedge - textwidth;
  376. rc.right = curedge;
  377. rc.top = curtop;
  378. rc.bottom = curtop + m_nRowHeight - 2;
  379. curedge -= textwidth;
  380. }
  381. if ( dolayout )
  382. {
  383. p->rect = rc;
  384. }
  385. }
  386. if ( dolayout )
  387. {
  388. m_nRowsRequired = currentrow + 1;
  389. }
  390. return currentrow + 1;
  391. }