Counter Strike : Global Offensive Source Code
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.

443 lines
12 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <assert.h>
  8. #include <vgui/ISurface.h>
  9. #include <vgui/IVGui.h>
  10. #include <vgui/IPanel.h>
  11. #include <vgui/vgui.h>
  12. #include <keyvalues.h>
  13. #include <tier0/dbg.h>
  14. #include <vgui_controls/Controls.h>
  15. #include <vgui_controls/FocusNavGroup.h>
  16. #include <vgui_controls/Panel.h>
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include <tier0/memdbgon.h>
  19. using namespace vgui;
  20. //-----------------------------------------------------------------------------
  21. // Purpose: Constructor
  22. // Input : *panel - parent panel
  23. //-----------------------------------------------------------------------------
  24. FocusNavGroup::FocusNavGroup(Panel *panel) : _mainPanel(panel)
  25. {
  26. _currentFocus = NULL;
  27. _topLevelFocus = false;
  28. _defaultButton = NULL;
  29. _currentDefaultButton = NULL;
  30. }
  31. //-----------------------------------------------------------------------------
  32. // Purpose: Destructor
  33. //-----------------------------------------------------------------------------
  34. FocusNavGroup::~FocusNavGroup()
  35. {
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Purpose: Sets the focus to the previous panel in the tab order
  39. // Input : *panel - panel currently with focus
  40. //-----------------------------------------------------------------------------
  41. bool FocusNavGroup::RequestFocusPrev(VPANEL panel)
  42. {
  43. if(panel==NULL)
  44. return false;
  45. _currentFocus = NULL;
  46. int newPosition = 9999999;
  47. if (panel)
  48. {
  49. newPosition = ipanel()->GetTabPosition(panel);
  50. }
  51. bool bFound = false;
  52. bool bRepeat = true;
  53. Panel *best = NULL;
  54. while (1)
  55. {
  56. newPosition--;
  57. if (newPosition > 0)
  58. {
  59. int bestPosition = 0;
  60. // look for the next tab position
  61. for (int i = 0; i < _mainPanel->GetChildCount(); i++)
  62. {
  63. Panel *child = _mainPanel->GetChild(i);
  64. if (child && child->IsVisible() && child->IsEnabled() && child->GetTabPosition())
  65. {
  66. int tabPosition = child->GetTabPosition();
  67. if (tabPosition == newPosition)
  68. {
  69. // we've found the right tab
  70. best = child;
  71. bestPosition = newPosition;
  72. // don't loop anymore since we've found the correct panel
  73. break;
  74. }
  75. else if (tabPosition < newPosition && tabPosition > bestPosition)
  76. {
  77. // record the match since this is the closest so far
  78. bestPosition = tabPosition;
  79. best = child;
  80. }
  81. }
  82. }
  83. if (!bRepeat)
  84. break;
  85. if (best)
  86. break;
  87. }
  88. else
  89. {
  90. // reset new position for next loop
  91. newPosition = 9999999;
  92. }
  93. // haven't found an item
  94. if (!_topLevelFocus)
  95. {
  96. // check to see if we should push the focus request up
  97. if (_mainPanel->GetVParent() && _mainPanel->GetVParent() != surface()->GetEmbeddedPanel())
  98. {
  99. // we're not a top level panel, so forward up the request instead of looping
  100. if (ipanel()->RequestFocusPrev(_mainPanel->GetVParent(), _mainPanel->GetVPanel()))
  101. {
  102. bFound = true;
  103. SetCurrentDefaultButton(NULL);
  104. break;
  105. }
  106. }
  107. }
  108. // not found an item, loop back
  109. newPosition = 9999999;
  110. bRepeat = false;
  111. }
  112. if (best)
  113. {
  114. _currentFocus = best->GetVPanel();
  115. best->RequestFocus(-1);
  116. bFound = true;
  117. if (!CanButtonBeDefault(best->GetVPanel()))
  118. {
  119. if (_defaultButton)
  120. {
  121. SetCurrentDefaultButton(_defaultButton);
  122. }
  123. else
  124. {
  125. SetCurrentDefaultButton(NULL);
  126. // we need to ask the parent to set its default button
  127. if (_mainPanel->GetVParent())
  128. {
  129. ivgui()->PostMessage(_mainPanel->GetVParent(), new KeyValues("FindDefaultButton"), NULL);
  130. }
  131. }
  132. }
  133. else
  134. {
  135. SetCurrentDefaultButton(best->GetVPanel());
  136. }
  137. }
  138. return bFound;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: Sets the focus to the previous panel in the tab order
  142. // Input : *panel - panel currently with focus
  143. //-----------------------------------------------------------------------------
  144. bool FocusNavGroup::RequestFocusNext(VPANEL panel)
  145. {
  146. // basic recursion guard, in case user has set up a bad focus hierarchy
  147. static int stack_depth = 0;
  148. stack_depth++;
  149. _currentFocus = NULL;
  150. int newPosition = 0;
  151. if (panel)
  152. {
  153. newPosition = ipanel()->GetTabPosition(panel);
  154. }
  155. bool bFound = false;
  156. bool bRepeat = true;
  157. Panel *best = NULL;
  158. while (1)
  159. {
  160. newPosition++;
  161. int bestPosition = 999999;
  162. // look for the next tab position
  163. for (int i = 0; i < _mainPanel->GetChildCount(); i++)
  164. {
  165. Panel *child = _mainPanel->GetChild(i);
  166. if ( !child )
  167. continue;
  168. if (child && child->IsVisible() && child->IsEnabled() && child->GetTabPosition())
  169. {
  170. int tabPosition = child->GetTabPosition();
  171. if (tabPosition == newPosition)
  172. {
  173. // we've found the right tab
  174. best = child;
  175. bestPosition = newPosition;
  176. // don't loop anymore since we've found the correct panel
  177. break;
  178. }
  179. else if (tabPosition > newPosition && tabPosition < bestPosition)
  180. {
  181. // record the match since this is the closest so far
  182. bestPosition = tabPosition;
  183. best = child;
  184. }
  185. }
  186. }
  187. if (!bRepeat)
  188. break;
  189. if (best)
  190. break;
  191. // haven't found an item
  192. // check to see if we should push the focus request up
  193. if (!_topLevelFocus)
  194. {
  195. if (_mainPanel->GetVParent() && _mainPanel->GetVParent() != surface()->GetEmbeddedPanel())
  196. {
  197. // we're not a top level panel, so forward up the request instead of looping
  198. if (stack_depth < 15)
  199. {
  200. if (ipanel()->RequestFocusNext(_mainPanel->GetVParent(), _mainPanel->GetVPanel()))
  201. {
  202. bFound = true;
  203. SetCurrentDefaultButton(NULL);
  204. break;
  205. }
  206. // if we find one then we break, otherwise we loop
  207. }
  208. }
  209. }
  210. // loop back
  211. newPosition = 0;
  212. bRepeat = false;
  213. }
  214. if (best)
  215. {
  216. _currentFocus = best->GetVPanel();
  217. best->RequestFocus(1);
  218. bFound = true;
  219. if (!CanButtonBeDefault(best->GetVPanel()))
  220. {
  221. if (_defaultButton)
  222. {
  223. SetCurrentDefaultButton(_defaultButton);
  224. }
  225. else
  226. {
  227. SetCurrentDefaultButton(NULL);
  228. // we need to ask the parent to set its default button
  229. if (_mainPanel->GetVParent())
  230. {
  231. ivgui()->PostMessage(_mainPanel->GetVParent(), new KeyValues("FindDefaultButton"), NULL);
  232. }
  233. }
  234. }
  235. else
  236. {
  237. SetCurrentDefaultButton(best->GetVPanel());
  238. }
  239. }
  240. stack_depth--;
  241. return bFound;
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose: sets the panel that owns this FocusNavGroup to be the root in the focus traversal heirarchy
  245. //-----------------------------------------------------------------------------
  246. void FocusNavGroup::SetFocusTopLevel(bool state)
  247. {
  248. _topLevelFocus = state;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: sets panel which receives input when ENTER is hit
  252. //-----------------------------------------------------------------------------
  253. void FocusNavGroup::SetDefaultButton(Panel *panel)
  254. {
  255. VPANEL vpanel = panel ? panel->GetVPanel() : NULL;
  256. if ( vpanel == _defaultButton.Get() )
  257. return;
  258. Assert(CanButtonBeDefault(vpanel));
  259. _defaultButton = vpanel;
  260. SetCurrentDefaultButton(_defaultButton);
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Purpose: sets panel which receives input when ENTER is hit
  264. //-----------------------------------------------------------------------------
  265. void FocusNavGroup::SetCurrentDefaultButton(VPANEL panel, bool sendCurrentDefaultButtonMessage)
  266. {
  267. if (panel == _currentDefaultButton.Get())
  268. return;
  269. if ( sendCurrentDefaultButtonMessage && _currentDefaultButton.Get() != NULL)
  270. {
  271. ivgui()->PostMessage(_currentDefaultButton, new KeyValues("SetAsCurrentDefaultButton", "state", 0), NULL);
  272. }
  273. _currentDefaultButton = panel;
  274. if ( sendCurrentDefaultButtonMessage && _currentDefaultButton.Get() != NULL)
  275. {
  276. ivgui()->PostMessage(_currentDefaultButton, new KeyValues("SetAsCurrentDefaultButton", "state", 1), NULL);
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose: sets panel which receives input when ENTER is hit
  281. //-----------------------------------------------------------------------------
  282. VPANEL FocusNavGroup::GetCurrentDefaultButton()
  283. {
  284. return _currentDefaultButton;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Purpose: sets panel which receives input when ENTER is hit
  288. //-----------------------------------------------------------------------------
  289. VPANEL FocusNavGroup::GetDefaultButton()
  290. {
  291. return _defaultButton;
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Purpose: finds the panel which is activated by the specified key
  295. // Input : code - the keycode of the hotkey
  296. // Output : Panel * - NULL if no panel found
  297. //-----------------------------------------------------------------------------
  298. Panel *FocusNavGroup::FindPanelByHotkey(wchar_t key)
  299. {
  300. for (int i = 0; i < _mainPanel->GetChildCount(); i++)
  301. {
  302. Panel *child = _mainPanel->GetChild(i);
  303. if ( !child )
  304. continue;
  305. Panel *hot = child->HasHotkey(key);
  306. if (hot && hot->IsVisible() && hot->IsEnabled())
  307. {
  308. return hot;
  309. }
  310. }
  311. return NULL;
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Purpose:
  315. //-----------------------------------------------------------------------------
  316. Panel *FocusNavGroup::GetDefaultPanel()
  317. {
  318. for (int i = 0; i < _mainPanel->GetChildCount(); i++)
  319. {
  320. Panel *child = _mainPanel->GetChild(i);
  321. if ( !child )
  322. continue;
  323. if (child->GetTabPosition() == 1)
  324. {
  325. return child;
  326. }
  327. }
  328. return NULL; // no specific panel set
  329. }
  330. //-----------------------------------------------------------------------------
  331. // Purpose:
  332. //-----------------------------------------------------------------------------
  333. Panel *FocusNavGroup::GetCurrentFocus()
  334. {
  335. Panel *pFocus = _currentFocus ? ipanel()->GetPanel(_currentFocus, vgui::GetControlsModuleName()) : NULL;
  336. if ( pFocus && !pFocus->IsFullyVisible() )
  337. {
  338. RequestFocusNext();
  339. pFocus = _currentFocus ? ipanel()->GetPanel(_currentFocus, vgui::GetControlsModuleName()) : NULL;
  340. Assert( !pFocus || pFocus->IsFullyVisible() );
  341. }
  342. return pFocus;
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose: Sets the current focus
  346. //-----------------------------------------------------------------------------
  347. VPANEL FocusNavGroup::SetCurrentFocus(VPANEL focus, VPANEL defaultPanel)
  348. {
  349. _currentFocus = focus;
  350. // if we haven't found a default panel yet, let's see if we know of one
  351. if (defaultPanel == NULL)
  352. {
  353. // can this focus itself by the default
  354. if (CanButtonBeDefault(focus))
  355. {
  356. defaultPanel = focus;
  357. }
  358. else if (_defaultButton) // do we know of a default button
  359. {
  360. defaultPanel = _defaultButton;
  361. }
  362. }
  363. SetCurrentDefaultButton(defaultPanel);
  364. return defaultPanel;
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Purpose: Returns true if the specified panel can be the default
  368. //-----------------------------------------------------------------------------
  369. bool FocusNavGroup::CanButtonBeDefault(VPANEL panel)
  370. {
  371. if( panel == NULL )
  372. return false;
  373. KeyValues *data = new KeyValues("CanBeDefaultButton");
  374. bool bResult = false;
  375. if (ipanel()->RequestInfo(panel, data))
  376. {
  377. bResult = (data->GetInt("result") == 1);
  378. }
  379. data->deleteThis();
  380. return bResult;
  381. }