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.

425 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdarg.h>
  8. #include <stdio.h>
  9. #include <vgui/IInput.h>
  10. #include <vgui/IPanel.h>
  11. #include <vgui/IScheme.h>
  12. #include <vgui/ISystem.h>
  13. #include <vgui/IVGui.h>
  14. #include <vgui/KeyCode.h>
  15. #include <KeyValues.h>
  16. #include <vgui_controls/FocusNavGroup.h>
  17. #include <vgui_controls/Image.h>
  18. #include <vgui_controls/RadioButton.h>
  19. #include <vgui_controls/TextImage.h>
  20. #include <vgui_controls/Controls.h>
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include <tier0/memdbgon.h>
  23. using namespace vgui;
  24. enum direction
  25. {
  26. UP = -1,
  27. DOWN = 1,
  28. };
  29. //-----------------------------------------------------------------------------
  30. // Purpose: Check box image
  31. //-----------------------------------------------------------------------------
  32. void RadioImage::Paint()
  33. {
  34. DrawSetTextFont(GetFont());
  35. // draw background
  36. if (_radioButton->IsEnabled())
  37. {
  38. DrawSetTextColor(_bgColor);
  39. }
  40. else
  41. {
  42. DrawSetTextColor(_radioButton->GetBgColor());
  43. }
  44. DrawPrintChar(0, 1, 'n');
  45. // draw border circl
  46. DrawSetTextColor(_borderColor1);
  47. DrawPrintChar(0, 1, 'j');
  48. DrawSetTextColor(_borderColor2);
  49. DrawPrintChar(0, 1, 'k');
  50. // draw selected check
  51. if (_radioButton->IsSelected())
  52. {
  53. DrawSetTextColor(_checkColor);
  54. DrawPrintChar(0, 1, 'h');
  55. }
  56. }
  57. DECLARE_BUILD_FACTORY_DEFAULT_TEXT( RadioButton, RadioButton );
  58. //-----------------------------------------------------------------------------
  59. // Purpose: Create a radio button.
  60. //-----------------------------------------------------------------------------
  61. RadioButton::RadioButton(Panel *parent, const char *panelName, const char *text) : ToggleButton(parent, panelName, text)
  62. {
  63. SetContentAlignment(a_west);
  64. // create the image
  65. _radioBoxImage = new RadioImage(this);
  66. _oldTabPosition = 0;
  67. _subTabPosition = 0;
  68. SetTextImageIndex(1);
  69. SetImageAtIndex(0, _radioBoxImage, 0);
  70. SetButtonActivationType(ACTIVATE_ONPRESSED);
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Purpose: Destructor
  74. //-----------------------------------------------------------------------------
  75. RadioButton::~RadioButton()
  76. {
  77. delete _radioBoxImage;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose: Apply resource file scheme.
  81. //-----------------------------------------------------------------------------
  82. void RadioButton::ApplySchemeSettings(IScheme *pScheme)
  83. {
  84. BaseClass::ApplySchemeSettings(pScheme);
  85. _radioBoxImage->_bgColor = GetSchemeColor("CheckButton.BgColor", Color(150, 150, 150, 0), pScheme);
  86. _radioBoxImage->_borderColor1 = GetSchemeColor("CheckButton.Border1", Color(20, 20, 20, 0), pScheme);
  87. _radioBoxImage->_borderColor2 = GetSchemeColor("CheckButton.Border2", Color(90, 90, 90, 0), pScheme);
  88. _radioBoxImage->_checkColor = GetSchemeColor("CheckButton.Check", Color(20, 20, 20, 0), pScheme);
  89. SetFgColor(GetSchemeColor("RadioButton.TextColor", pScheme));
  90. _selectedFgColor = GetSchemeColor("RadioButton.SelectedTextColor", GetSchemeColor("ControlText", pScheme), pScheme);
  91. SetDefaultColor( GetFgColor(), GetBgColor() );
  92. SetArmedColor( GetSchemeColor("RadioButton.ArmedTextColor", pScheme), GetButtonArmedBgColor() );
  93. SetContentAlignment(a_west);
  94. // reloading the scheme wipes out lists of images
  95. HFont hFont = pScheme->GetFont("MarlettSmall", IsProportional());
  96. if ( hFont == INVALID_FONT )
  97. {
  98. // fallback to Marlett if MarlettSmall isn't found
  99. hFont = pScheme->GetFont("Marlett", IsProportional());
  100. }
  101. _radioBoxImage->SetFont( hFont );
  102. _radioBoxImage->ResizeImageToContent();
  103. SetImageAtIndex(0, _radioBoxImage, 0);
  104. // don't draw a background
  105. SetPaintBackgroundEnabled(false);
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Purpose: Get the border style of the button, Radio buttons have no border
  109. //-----------------------------------------------------------------------------
  110. IBorder *RadioButton::GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
  111. {
  112. return NULL;
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose: Get the tab position of the radio button with the set of radio buttons
  116. // A group of RadioButtons must have the same TabPosition, with [1, n] subtabpositions
  117. //-----------------------------------------------------------------------------
  118. int RadioButton::GetSubTabPosition()
  119. {
  120. return _subTabPosition;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Get the tab position of the radio button with the set of radio buttons
  124. // A group of RadioButtons must have the same TabPosition, with [1, n] subtabpositions
  125. //-----------------------------------------------------------------------------
  126. void RadioButton::SetSubTabPosition(int position)
  127. {
  128. _subTabPosition = position;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose: Return the RadioButton's real tab position (its Panel one changes)
  132. //-----------------------------------------------------------------------------
  133. int RadioButton::GetRadioTabPosition()
  134. {
  135. return _oldTabPosition;
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose: Set the radio button checked. When a radio button is checked, a
  139. // message is sent to all other radio buttons in the same group so
  140. // they will become unchecked.
  141. //-----------------------------------------------------------------------------
  142. void RadioButton::SetSelected(bool state)
  143. {
  144. InternalSetSelected( state, true );
  145. }
  146. void RadioButton::InternalSetSelected(bool state, bool bFireEvents)
  147. {
  148. if (state == true)
  149. {
  150. if (!IsEnabled())
  151. return;
  152. // restore our tab position
  153. SetTabPosition(_oldTabPosition);
  154. // Should we send notifications?
  155. if ( bFireEvents )
  156. {
  157. // send a message
  158. KeyValues *msg = new KeyValues("RadioButtonChecked");
  159. msg->SetPtr("panel", this);
  160. msg->SetInt("tabposition", _oldTabPosition);
  161. // send a message to all other panels on the same level as heirarchy,
  162. // so that other radio buttons know to shut off
  163. VPANEL radioParent = GetVParent();
  164. if (radioParent)
  165. {
  166. for (int i = 0; i < ipanel()->GetChildCount(radioParent); i++)
  167. {
  168. VPANEL child = ipanel()->GetChild(radioParent, i);
  169. if (child != GetVPanel())
  170. {
  171. ivgui()->PostMessage(child, msg->MakeCopy(), GetVPanel());
  172. }
  173. }
  174. }
  175. RequestFocus();
  176. PostActionSignal(msg);
  177. }
  178. }
  179. else
  180. {
  181. // remove ourselves from the tab order
  182. if (GetTabPosition())
  183. {
  184. _oldTabPosition = GetTabPosition();
  185. }
  186. SetTabPosition(0);
  187. }
  188. InvalidateLayout();
  189. Repaint();
  190. ToggleButton::SetSelected(state);
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose: Set the selection state without firing any events
  194. //-----------------------------------------------------------------------------
  195. void RadioButton::SilentSetSelected(bool state)
  196. {
  197. InternalSetSelected( state, false );
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Purpose: Set up the text color before doing normal layout
  201. //-----------------------------------------------------------------------------
  202. void RadioButton::PerformLayout()
  203. {
  204. if (IsSelected())
  205. {
  206. SetFgColor(_selectedFgColor);
  207. }
  208. else
  209. {
  210. SetFgColor(GetButtonFgColor());
  211. }
  212. BaseClass::PerformLayout();
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: Apply resource settings including button state and text color.
  216. //-----------------------------------------------------------------------------
  217. void RadioButton::ApplySettings(KeyValues *inResourceData)
  218. {
  219. ToggleButton::ApplySettings(inResourceData);
  220. SetTextColorState(CS_NORMAL);
  221. _subTabPosition = inResourceData->GetInt("SubTabPosition");
  222. _oldTabPosition = inResourceData->GetInt("TabPosition");
  223. SetImageAtIndex(0, _radioBoxImage, 0);
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose: Get resource settings including button state, text color, and subTabPosition
  227. //-----------------------------------------------------------------------------
  228. void RadioButton::GetSettings(KeyValues *outResourceData)
  229. {
  230. ToggleButton::GetSettings(outResourceData);
  231. outResourceData->SetInt("SubTabPosition", _subTabPosition);
  232. outResourceData->SetInt("TabPosition", GetRadioTabPosition());
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Purpose: Describe editing details
  236. //-----------------------------------------------------------------------------
  237. const char *RadioButton::GetDescription( void )
  238. {
  239. static char buf[1024];
  240. Q_snprintf(buf, sizeof(buf), "%s, int SubTabPosition", BaseClass::GetDescription());
  241. return buf;
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose: When a radio button is checked, all other radio buttons
  245. // in the same group become unchecked.
  246. //-----------------------------------------------------------------------------
  247. void RadioButton::OnRadioButtonChecked(int tabPosition)
  248. {
  249. // make sure we're in the same tab group
  250. if (tabPosition != _oldTabPosition)
  251. return;
  252. // wouldn't be sent to us from ourselves, so another radio button has taken over
  253. SetSelected(false);
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose: Draws the selection rectangle
  257. //-----------------------------------------------------------------------------
  258. void RadioButton::Paint()
  259. {
  260. BaseClass::Paint();
  261. /*
  262. if (HasFocus())
  263. {
  264. int tx0, ty0, tx1, ty1;
  265. _textImage->GetPos(tx0, ty0);
  266. _textImage->GetSize(tx1, ty1);
  267. DrawFocusBorder(tx0, ty0, tx0 + tx1, ty0 + ty1);
  268. }
  269. */
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose:
  273. //-----------------------------------------------------------------------------
  274. void RadioButton::DoClick()
  275. {
  276. SetSelected(true);
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Purpose: Handle arrow key movement
  280. //-----------------------------------------------------------------------------
  281. void RadioButton::OnKeyCodeTyped(KeyCode code)
  282. {
  283. switch (code)
  284. {
  285. case KEY_ENTER:
  286. case KEY_SPACE:
  287. {
  288. if (!IsSelected())
  289. {
  290. SetSelected(true);
  291. }
  292. else
  293. {
  294. Panel::OnKeyCodeTyped(code);
  295. }
  296. }
  297. break;
  298. case KEY_DOWN:
  299. case KEY_RIGHT:
  300. {
  301. RadioButton *bestRadio = FindBestRadioButton( DOWN );
  302. if (bestRadio)
  303. {
  304. bestRadio->SetSelected(true);
  305. }
  306. }
  307. break;
  308. case KEY_UP:
  309. case KEY_LEFT:
  310. {
  311. RadioButton *bestRadio = FindBestRadioButton( UP );
  312. if (bestRadio)
  313. {
  314. bestRadio->SetSelected(true);
  315. }
  316. }
  317. break;
  318. default:
  319. BaseClass::OnKeyCodeTyped(code);
  320. break;
  321. }
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose: Find the correct radio button to move to.
  325. // Input : direction - the direction we are moving, up or down.
  326. //-----------------------------------------------------------------------------
  327. RadioButton *RadioButton::FindBestRadioButton(int direction)
  328. {
  329. RadioButton *bestRadio = NULL;
  330. int highestRadio = 0;
  331. Panel *pr = GetParent();
  332. if (pr)
  333. {
  334. // find the radio button to go to next
  335. for (int i = 0; i < pr->GetChildCount(); i++)
  336. {
  337. RadioButton *child = dynamic_cast<RadioButton *>(pr->GetChild(i));
  338. if (child && child->GetRadioTabPosition() == _oldTabPosition)
  339. {
  340. if (child->GetSubTabPosition() == _subTabPosition + direction)
  341. {
  342. bestRadio = child;
  343. break;
  344. }
  345. if ( (child->GetSubTabPosition() == 0) && (direction == DOWN) )
  346. {
  347. bestRadio = child;
  348. continue;
  349. }
  350. else if ( (child->GetSubTabPosition() > highestRadio) && (direction == UP) )
  351. {
  352. bestRadio = child;
  353. highestRadio = bestRadio->GetSubTabPosition();
  354. continue;
  355. }
  356. if (!bestRadio)
  357. {
  358. bestRadio = child;
  359. }
  360. }
  361. }
  362. if (bestRadio)
  363. {
  364. bestRadio->RequestFocus();
  365. }
  366. InvalidateLayout();
  367. Repaint();
  368. }
  369. return bestRadio;
  370. }