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.

605 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #define PROTECTED_THINGS_DISABLE
  8. #include <vgui/IBorder.h>
  9. #include <vgui/IInput.h>
  10. #include <vgui/ISystem.h>
  11. #include <vgui/IScheme.h>
  12. #include <vgui/ISurface.h>
  13. #include <vgui/MouseCode.h>
  14. #include <KeyValues.h>
  15. #include <vgui_controls/ScrollBarSlider.h>
  16. #include <vgui_controls/Controls.h>
  17. #include <math.h>
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include <tier0/memdbgon.h>
  20. using namespace vgui;
  21. //-----------------------------------------------------------------------------
  22. // The ScrollBarSlider is the scroll bar nob that moves up and down in through a range.
  23. //-----------------------------------------------------------------------------
  24. ScrollBarSlider::ScrollBarSlider(Panel *parent, const char *panelName, bool vertical) : Panel(parent, panelName)
  25. {
  26. _vertical=vertical;
  27. _dragging=false;
  28. _value=0;
  29. _range[0]=0;
  30. _range[1]=0;
  31. _rangeWindow=0;
  32. _buttonOffset=0;
  33. _ScrollBarSliderBorder=NULL;
  34. RecomputeNobPosFromValue();
  35. SetBlockDragChaining( true );
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Purpose: Set the size of the ScrollBarSlider nob
  39. //-----------------------------------------------------------------------------
  40. void ScrollBarSlider::SetSize(int wide,int tall)
  41. {
  42. BaseClass::SetSize(wide,tall);
  43. RecomputeNobPosFromValue();
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose: Whether the scroll bar is vertical (true) or not (false)
  47. //-----------------------------------------------------------------------------
  48. bool ScrollBarSlider::IsVertical()
  49. {
  50. return _vertical;
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Set the ScrollBarSlider value of the nob.
  54. //-----------------------------------------------------------------------------
  55. void ScrollBarSlider::SetValue(int value)
  56. {
  57. int oldValue = _value;
  58. if (value > _range[1] - _rangeWindow)
  59. {
  60. // note our scrolling range must take into acount _rangeWindow
  61. value = _range[1] - _rangeWindow;
  62. }
  63. if (value < _range[0])
  64. {
  65. value = _range[0];
  66. }
  67. _value = value;
  68. RecomputeNobPosFromValue();
  69. if (_value != oldValue)
  70. {
  71. SendScrollBarSliderMovedMessage();
  72. }
  73. }
  74. //-----------------------------------------------------------------------------
  75. // Purpose: Get the ScrollBarSlider value of the nob.
  76. //-----------------------------------------------------------------------------
  77. int ScrollBarSlider::GetValue()
  78. {
  79. return _value;
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose:
  83. //-----------------------------------------------------------------------------
  84. void ScrollBarSlider::PerformLayout()
  85. {
  86. RecomputeNobPosFromValue();
  87. BaseClass::PerformLayout();
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Purpose: Given the value of the ScrollBarSlider, adjust the ends of the nob.
  91. //-----------------------------------------------------------------------------
  92. void ScrollBarSlider::RecomputeNobPosFromValue()
  93. {
  94. int wide, tall;
  95. GetPaintSize(wide, tall);
  96. float fwide = (float)( wide - 1 );
  97. float ftall = (float)( tall - 1 );
  98. float frange = (float)(_range[1] -_range[0]);
  99. float fvalue = (float)(_value - _range[0]);
  100. float frangewindow = (float)(_rangeWindow);
  101. float fper = ( frange != frangewindow ) ? fvalue / ( frange-frangewindow ) : 0;
  102. // Msg( "fwide: %f ftall: %f frange: %f fvalue: %f frangewindow: %f fper: %f\n",
  103. // fwide, ftall, frange, fvalue, frangewindow, fper );
  104. if ( frangewindow > 0 )
  105. {
  106. if ( frange <= 0.0 )
  107. {
  108. frange = 1.0;
  109. }
  110. float width, length;
  111. if (_vertical)
  112. {
  113. width = fwide;
  114. length = ftall;
  115. }
  116. else
  117. {
  118. width = ftall;
  119. length = fwide;
  120. }
  121. // our size is proportional to frangewindow/frange
  122. // the scroll bar nob's length reflects the amount of stuff on the screen
  123. // vs the total amount of stuff we could scroll through in window
  124. // so if a window showed half its contents and the other half is hidden the
  125. // scroll bar's length is half the window.
  126. // if everything is on the screen no nob is displayed
  127. // frange is how many 'lines' of stuff we can display
  128. // frangewindow is how many 'lines' are in the display window
  129. // proportion of whole window that is on screen
  130. float proportion = frangewindow / frange;
  131. float fnobsize = length * proportion;
  132. if ( fnobsize < width ) fnobsize = (float)width;
  133. float freepixels = length - fnobsize;
  134. float firstpixel = freepixels * fper;
  135. _nobPos[0] = (int)( firstpixel );
  136. _nobPos[1] = (int)( firstpixel + fnobsize );
  137. if ( _nobPos[1] > length )
  138. {
  139. _nobPos[0] = (int)( length - fnobsize );
  140. _nobPos[1] = (int)length;
  141. }
  142. }
  143. Repaint();
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose: Get the ScrollBarSlider value using the location of the nob ends.
  147. //-----------------------------------------------------------------------------
  148. void ScrollBarSlider::RecomputeValueFromNobPos()
  149. {
  150. int wide, tall;
  151. GetPaintSize(wide, tall);
  152. float fwide = (float)( wide - 1 );
  153. float ftall = (float)( tall - 1 );
  154. float frange = (float)( _range[1] - _range[0] );
  155. float fvalue = (float)( _value - _range[0] );
  156. float fnob = (float)_nobPos[0];
  157. float frangewindow = (float)(_rangeWindow);
  158. if ( frangewindow > 0 )
  159. {
  160. if ( frange <= 0.0 )
  161. {
  162. frange = 1.0;
  163. }
  164. // set local width and length
  165. float width, length;
  166. if ( _vertical )
  167. {
  168. width = fwide;
  169. length = ftall;
  170. }
  171. else
  172. {
  173. width = ftall;
  174. length = fwide;
  175. }
  176. // calculate the size of the nob
  177. float proportion = frangewindow / frange;
  178. float fnobsize = length * proportion;
  179. if ( fnobsize < width )
  180. {
  181. fnobsize = width;
  182. }
  183. // Our scroll bar actually doesnt scroll through all frange lines in the truerange, we
  184. // actually only scroll through frange-frangewindow number of lines so we must take that
  185. // into account when we calculate the value
  186. // convert to our local size system
  187. // Make sure we don't divide by zero
  188. if ( length - fnobsize == 0 )
  189. {
  190. fvalue = 0.0f;
  191. }
  192. else
  193. {
  194. fvalue = (frange - frangewindow) * ( fnob / ( length - fnobsize ) );
  195. }
  196. }
  197. // check to see if we should just snap to the bottom
  198. if (fabs(fvalue + _rangeWindow - _range[1]) < (0.01f * frange))
  199. {
  200. // snap to the end
  201. _value = _range[1] - _rangeWindow;
  202. }
  203. else
  204. {
  205. // Take care of rounding issues.
  206. _value = (int)( fvalue + _range[0] + 0.5);
  207. }
  208. // Clamp final result
  209. _value = ( _value < (_range[1] - _rangeWindow) ) ? _value : (_range[1] - _rangeWindow);
  210. if (_value < _range[0])
  211. {
  212. _value = _range[0];
  213. }
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose: Check if the ScrollBarSlider can move through one or more pixels per
  217. // unit of its range.
  218. //-----------------------------------------------------------------------------
  219. bool ScrollBarSlider::HasFullRange()
  220. {
  221. int wide, tall;
  222. GetPaintSize(wide, tall);
  223. float frangewindow = (float)(_rangeWindow);
  224. float checkAgainst = 0;
  225. if(_vertical)
  226. {
  227. checkAgainst = (float)tall;
  228. }
  229. else
  230. {
  231. checkAgainst = (float)wide;
  232. }
  233. if ( frangewindow > 0 )
  234. {
  235. if( frangewindow <= ( checkAgainst + _buttonOffset ) )
  236. {
  237. return true;
  238. }
  239. }
  240. return false;
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Purpose: Inform other watchers that the ScrollBarSlider was moved
  244. //-----------------------------------------------------------------------------
  245. void ScrollBarSlider::SendScrollBarSliderMovedMessage()
  246. {
  247. // send a changed message
  248. PostActionSignal(new KeyValues("ScrollBarSliderMoved", "position", _value));
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: Return true if this slider is actually drawing itself
  252. //-----------------------------------------------------------------------------
  253. bool ScrollBarSlider::IsSliderVisible( void )
  254. {
  255. int itemRange = _range[1] - _range[0];
  256. // Don't draw nob, no items in list
  257. if ( itemRange <= 0 )
  258. return false ;
  259. // Not enough range
  260. if ( itemRange <= _rangeWindow )
  261. return false;
  262. return true;
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. //-----------------------------------------------------------------------------
  267. void ScrollBarSlider::ApplySchemeSettings(IScheme *pScheme)
  268. {
  269. BaseClass::ApplySchemeSettings(pScheme);
  270. SetFgColor(GetSchemeColor("ScrollBarSlider.FgColor", pScheme));
  271. SetBgColor(GetSchemeColor("ScrollBarSlider.BgColor", pScheme));
  272. IBorder *newBorder = pScheme->GetBorder("ScrollBarSliderBorder");
  273. if ( newBorder )
  274. {
  275. _ScrollBarSliderBorder = newBorder;
  276. }
  277. else
  278. {
  279. _ScrollBarSliderBorder = pScheme->GetBorder("ButtonBorder");
  280. }
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. //-----------------------------------------------------------------------------
  285. void ScrollBarSlider::ApplySettings( KeyValues *pInResourceData )
  286. {
  287. BaseClass::ApplySettings( pInResourceData );
  288. const char *pButtonBorderName = pInResourceData->GetString( "ButtonBorder", NULL );
  289. if ( pButtonBorderName )
  290. {
  291. _ScrollBarSliderBorder = vgui::scheme()->GetIScheme( GetScheme() )->GetBorder( pButtonBorderName );
  292. }
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose:
  296. //-----------------------------------------------------------------------------
  297. void ScrollBarSlider::Paint()
  298. {
  299. int wide,tall;
  300. GetPaintSize(wide,tall);
  301. if ( !IsSliderVisible() )
  302. return;
  303. Color col = GetFgColor();
  304. surface()->DrawSetColor(col);
  305. if (_vertical)
  306. {
  307. if ( GetPaintBackgroundType() == 2 )
  308. {
  309. DrawBox( 1, _nobPos[0], wide - 2, _nobPos[1] - _nobPos[0], col, 1.0f );
  310. }
  311. else
  312. {
  313. // Nob
  314. surface()->DrawFilledRect(1, _nobPos[0], wide - 2, _nobPos[1]);
  315. }
  316. // border
  317. if (_ScrollBarSliderBorder)
  318. {
  319. _ScrollBarSliderBorder->Paint(0, _nobPos[0], wide, _nobPos[1]);
  320. }
  321. }
  322. else
  323. {
  324. // horizontal nob
  325. surface()->DrawFilledRect(_nobPos[0], 1, _nobPos[1], tall - 2 );
  326. // border
  327. if (_ScrollBarSliderBorder)
  328. {
  329. _ScrollBarSliderBorder->Paint(_nobPos[0] - 1, 1, _nobPos[1], tall );
  330. }
  331. }
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose:
  335. //-----------------------------------------------------------------------------
  336. void ScrollBarSlider::PaintBackground()
  337. {
  338. // BaseClass::PaintBackground();
  339. int wide,tall;
  340. GetPaintSize(wide,tall);
  341. surface()->DrawSetColor(GetBgColor());
  342. surface()->DrawFilledRect(0, 0, wide-1, tall-1);
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose: Set the range of the ScrollBarSlider
  346. //-----------------------------------------------------------------------------
  347. void ScrollBarSlider::SetRange(int min,int max)
  348. {
  349. if(max<min)
  350. {
  351. max=min;
  352. }
  353. if(min>max)
  354. {
  355. min=max;
  356. }
  357. _range[0]=min;
  358. _range[1]=max;
  359. // update the value (forces it within the range)
  360. SetValue( _value );
  361. InvalidateLayout();
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose: Get the range values of the ScrollBarSlider
  365. //-----------------------------------------------------------------------------
  366. void ScrollBarSlider::GetRange(int& min,int& max)
  367. {
  368. min=_range[0];
  369. max=_range[1];
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose: Respond to cursor movements, we only care about clicking and dragging
  373. //-----------------------------------------------------------------------------
  374. void ScrollBarSlider::OnCursorMoved(int x,int y)
  375. {
  376. if (!_dragging)
  377. {
  378. return;
  379. }
  380. // input()->GetCursorPos(x, y);
  381. // ScreenToLocal(x, y);
  382. int wide, tall;
  383. GetPaintSize(wide, tall);
  384. if (_vertical)
  385. {
  386. _nobPos[0] = _nobDragStartPos[0] + (y - _dragStartPos[1]);
  387. _nobPos[1] = _nobDragStartPos[1] + (y - _dragStartPos[1]);
  388. if (_nobPos[1] > tall)
  389. {
  390. _nobPos[0] = tall - (_nobPos[1] - _nobPos[0]);
  391. _nobPos[1] = tall;
  392. SetValue( _range[1] - _rangeWindow );
  393. }
  394. }
  395. else
  396. {
  397. _nobPos[0] = _nobDragStartPos[0] + (x - _dragStartPos[0]);
  398. _nobPos[1] = _nobDragStartPos[1] + (x - _dragStartPos[0]);
  399. if (_nobPos[1] > wide)
  400. {
  401. _nobPos[0] = wide - (_nobPos[1] - _nobPos[0]);
  402. _nobPos[1] = wide;
  403. }
  404. }
  405. if (_nobPos[0] < 0)
  406. {
  407. _nobPos[1] = _nobPos[1] - _nobPos[0];
  408. _nobPos[0] = 0;
  409. SetValue(0);
  410. }
  411. InvalidateLayout(); // not invalidatelayout - because it won't draw while we're scrolling the slider
  412. RecomputeValueFromNobPos();
  413. // Repaint();
  414. SendScrollBarSliderMovedMessage();
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose: Respond to mouse clicks on the ScrollBarSlider
  418. //-----------------------------------------------------------------------------
  419. void ScrollBarSlider::OnMousePressed(MouseCode code)
  420. {
  421. int x,y;
  422. input()->GetCursorPos(x,y);
  423. ScreenToLocal(x,y);
  424. if (_vertical)
  425. {
  426. if ((y >= _nobPos[0]) && (y < _nobPos[1]))
  427. {
  428. _dragging = true;
  429. input()->SetMouseCapture(GetVPanel());
  430. _nobDragStartPos[0] = _nobPos[0];
  431. _nobDragStartPos[1] = _nobPos[1];
  432. _dragStartPos[0] = x;
  433. _dragStartPos[1] = y;
  434. }
  435. else if (y < _nobPos[0])
  436. {
  437. // jump the bar up by the range window
  438. int val = GetValue();
  439. val -= _rangeWindow;
  440. SetValue(val);
  441. }
  442. else if (y >= _nobPos[1])
  443. {
  444. // jump the bar down by the range window
  445. int val = GetValue();
  446. val += _rangeWindow;
  447. SetValue(val);
  448. }
  449. }
  450. else
  451. {
  452. if((x >= _nobPos[0]) && (x < _nobPos[1]))
  453. {
  454. _dragging = true;
  455. input()->SetMouseCapture(GetVPanel());
  456. _nobDragStartPos[0] = _nobPos[0];
  457. _nobDragStartPos[1] = _nobPos[1];
  458. _dragStartPos[0] = x;
  459. _dragStartPos[1] = y;
  460. }
  461. else if (x < _nobPos[0])
  462. {
  463. // jump the bar up by the range window
  464. int val = GetValue();
  465. val -= _rangeWindow;
  466. SetValue(val);
  467. }
  468. else if (x >= _nobPos[1])
  469. {
  470. // jump the bar down by the range window
  471. int val = GetValue();
  472. val += _rangeWindow;
  473. SetValue(val);
  474. }
  475. }
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose: Treat double clicks as single clicks
  479. //-----------------------------------------------------------------------------
  480. void ScrollBarSlider::OnMouseDoublePressed(MouseCode code)
  481. {
  482. OnMousePressed(code);
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: Stop looking for mouse events when mouse is up.
  486. //-----------------------------------------------------------------------------
  487. void ScrollBarSlider::OnMouseReleased(MouseCode code)
  488. {
  489. _dragging = false;
  490. input()->SetMouseCapture(null);
  491. }
  492. //-----------------------------------------------------------------------------
  493. // Purpose: Get the position of the ends of the ScrollBarSlider.
  494. //-----------------------------------------------------------------------------
  495. void ScrollBarSlider::GetNobPos(int& min, int& max)
  496. {
  497. min=_nobPos[0];
  498. max=_nobPos[1];
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Purpose: Set the number of lines visible in the window the ScrollBarSlider is attached to
  502. //-----------------------------------------------------------------------------
  503. void ScrollBarSlider::SetRangeWindow(int rangeWindow)
  504. {
  505. _rangeWindow = rangeWindow;
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose: Get the number of lines visible in the window the ScrollBarSlider is attached to
  509. //-----------------------------------------------------------------------------
  510. int ScrollBarSlider::GetRangeWindow()
  511. {
  512. return _rangeWindow;
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Purpose:
  516. //-----------------------------------------------------------------------------
  517. void ScrollBarSlider::SetButtonOffset(int buttonOffset)
  518. {
  519. _buttonOffset = buttonOffset;
  520. }