diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/vgui2/vgui_controls/FocusNavGroup.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/vgui2/vgui_controls/FocusNavGroup.cpp')
| -rw-r--r-- | mp/src/vgui2/vgui_controls/FocusNavGroup.cpp | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/mp/src/vgui2/vgui_controls/FocusNavGroup.cpp b/mp/src/vgui2/vgui_controls/FocusNavGroup.cpp new file mode 100644 index 00000000..10fc88ad --- /dev/null +++ b/mp/src/vgui2/vgui_controls/FocusNavGroup.cpp @@ -0,0 +1,433 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <assert.h>
+
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/IPanel.h>
+#include <vgui/VGUI.h>
+#include <KeyValues.h>
+#include <tier0/dbg.h>
+
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/FocusNavGroup.h>
+#include <vgui_controls/Panel.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : *panel - parent panel
+//-----------------------------------------------------------------------------
+FocusNavGroup::FocusNavGroup(Panel *panel) : _mainPanel(panel)
+{
+ _currentFocus = NULL;
+ _topLevelFocus = false;
+ _defaultButton = NULL;
+ _currentDefaultButton = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+FocusNavGroup::~FocusNavGroup()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the focus to the previous panel in the tab order
+// Input : *panel - panel currently with focus
+//-----------------------------------------------------------------------------
+bool FocusNavGroup::RequestFocusPrev(VPANEL panel)
+{
+ if(panel==0)
+ return false;
+
+ _currentFocus = NULL;
+ int newPosition = 9999999;
+ if (panel)
+ {
+ newPosition = ipanel()->GetTabPosition(panel);
+ }
+
+ bool bFound = false;
+ bool bRepeat = true;
+ Panel *best = NULL;
+ while (1)
+ {
+ newPosition--;
+ if (newPosition > 0)
+ {
+ int bestPosition = 0;
+
+ // look for the next tab position
+ for (int i = 0; i < _mainPanel->GetChildCount(); i++)
+ {
+ Panel *child = _mainPanel->GetChild(i);
+ if (child && child->IsVisible() && child->IsEnabled() && child->GetTabPosition())
+ {
+ int tabPosition = child->GetTabPosition();
+ if (tabPosition == newPosition)
+ {
+ // we've found the right tab
+ best = child;
+ bestPosition = newPosition;
+
+ // don't loop anymore since we've found the correct panel
+ break;
+ }
+ else if (tabPosition < newPosition && tabPosition > bestPosition)
+ {
+ // record the match since this is the closest so far
+ bestPosition = tabPosition;
+ best = child;
+ }
+ }
+ }
+
+ if (!bRepeat)
+ break;
+
+ if (best)
+ break;
+ }
+ else
+ {
+ // reset new position for next loop
+ newPosition = 9999999;
+ }
+
+ // haven't found an item
+
+ if (!_topLevelFocus)
+ {
+ // check to see if we should push the focus request up
+ if (_mainPanel->GetVParent() && _mainPanel->GetVParent() != surface()->GetEmbeddedPanel())
+ {
+ // we're not a top level panel, so forward up the request instead of looping
+ if (ipanel()->RequestFocusPrev(_mainPanel->GetVParent(), _mainPanel->GetVPanel()))
+ {
+ bFound = true;
+ SetCurrentDefaultButton(NULL);
+ break;
+ }
+ }
+ }
+
+ // not found an item, loop back
+ newPosition = 9999999;
+ bRepeat = false;
+ }
+
+ if (best)
+ {
+ _currentFocus = best->GetVPanel();
+ best->RequestFocus(-1);
+ bFound = true;
+
+ if (!CanButtonBeDefault(best->GetVPanel()))
+ {
+ if (_defaultButton)
+ {
+ SetCurrentDefaultButton(_defaultButton);
+ }
+ else
+ {
+ SetCurrentDefaultButton(NULL);
+
+ // we need to ask the parent to set its default button
+ if (_mainPanel->GetVParent())
+ {
+ ivgui()->PostMessage(_mainPanel->GetVParent(), new KeyValues("FindDefaultButton"), NULL);
+ }
+ }
+ }
+ else
+ {
+ SetCurrentDefaultButton(best->GetVPanel());
+ }
+ }
+ return bFound;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the focus to the previous panel in the tab order
+// Input : *panel - panel currently with focus
+//-----------------------------------------------------------------------------
+bool FocusNavGroup::RequestFocusNext(VPANEL panel)
+{
+ // basic recursion guard, in case user has set up a bad focus hierarchy
+ static int stack_depth = 0;
+ stack_depth++;
+
+ _currentFocus = NULL;
+ int newPosition = 0;
+ if (panel)
+ {
+ newPosition = ipanel()->GetTabPosition(panel);
+ }
+
+ bool bFound = false;
+ bool bRepeat = true;
+ Panel *best = NULL;
+ while (1)
+ {
+ newPosition++;
+ int bestPosition = 999999;
+
+ // look for the next tab position
+ for (int i = 0; i < _mainPanel->GetChildCount(); i++)
+ {
+ Panel *child = _mainPanel->GetChild(i);
+ if ( !child )
+ continue;
+
+ if (child && child->IsVisible() && child->IsEnabled() && child->GetTabPosition())
+ {
+ int tabPosition = child->GetTabPosition();
+ if (tabPosition == newPosition)
+ {
+ // we've found the right tab
+ best = child;
+ bestPosition = newPosition;
+
+ // don't loop anymore since we've found the correct panel
+ break;
+ }
+ else if (tabPosition > newPosition && tabPosition < bestPosition)
+ {
+ // record the match since this is the closest so far
+ bestPosition = tabPosition;
+ best = child;
+ }
+ }
+ }
+
+ if (!bRepeat)
+ break;
+
+ if (best)
+ break;
+
+ // haven't found an item
+
+ // check to see if we should push the focus request up
+ if (!_topLevelFocus)
+ {
+ if (_mainPanel->GetVParent() && _mainPanel->GetVParent() != surface()->GetEmbeddedPanel())
+ {
+ // we're not a top level panel, so forward up the request instead of looping
+ if (stack_depth < 15)
+ {
+ if (ipanel()->RequestFocusNext(_mainPanel->GetVParent(), _mainPanel->GetVPanel()))
+ {
+ bFound = true;
+ SetCurrentDefaultButton(NULL);
+ break;
+ }
+
+ // if we find one then we break, otherwise we loop
+ }
+ }
+ }
+
+ // loop back
+ newPosition = 0;
+ bRepeat = false;
+ }
+
+ if (best)
+ {
+ _currentFocus = best->GetVPanel();
+ best->RequestFocus(1);
+ bFound = true;
+
+ if (!CanButtonBeDefault(best->GetVPanel()))
+ {
+ if (_defaultButton)
+ {
+ SetCurrentDefaultButton(_defaultButton);
+ }
+ else
+ {
+ SetCurrentDefaultButton(NULL);
+
+ // we need to ask the parent to set its default button
+ if (_mainPanel->GetVParent())
+ {
+ ivgui()->PostMessage(_mainPanel->GetVParent(), new KeyValues("FindDefaultButton"), NULL);
+ }
+ }
+ }
+ else
+ {
+ SetCurrentDefaultButton(best->GetVPanel());
+ }
+ }
+
+ stack_depth--;
+ return bFound;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the panel that owns this FocusNavGroup to be the root in the focus traversal heirarchy
+//-----------------------------------------------------------------------------
+void FocusNavGroup::SetFocusTopLevel(bool state)
+{
+ _topLevelFocus = state;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets panel which receives input when ENTER is hit
+//-----------------------------------------------------------------------------
+void FocusNavGroup::SetDefaultButton(Panel *panel)
+{
+ VPANEL vpanel = panel ? panel->GetVPanel() : NULL;
+ if ( vpanel == _defaultButton.Get() )
+ return;
+
+// Assert(CanButtonBeDefault(vpanel));
+
+ _defaultButton = vpanel;
+ SetCurrentDefaultButton(_defaultButton);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets panel which receives input when ENTER is hit
+//-----------------------------------------------------------------------------
+void FocusNavGroup::SetCurrentDefaultButton(VPANEL panel, bool sendCurrentDefaultButtonMessage)
+{
+ if (panel == _currentDefaultButton.Get())
+ return;
+
+ if ( sendCurrentDefaultButtonMessage && _currentDefaultButton.Get() != 0)
+ {
+ ivgui()->PostMessage(_currentDefaultButton, new KeyValues("SetAsCurrentDefaultButton", "state", 0), NULL);
+ }
+
+ _currentDefaultButton = panel;
+
+ if ( sendCurrentDefaultButtonMessage && _currentDefaultButton.Get() != 0)
+ {
+ ivgui()->PostMessage(_currentDefaultButton, new KeyValues("SetAsCurrentDefaultButton", "state", 1), NULL);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets panel which receives input when ENTER is hit
+//-----------------------------------------------------------------------------
+VPANEL FocusNavGroup::GetCurrentDefaultButton()
+{
+ return _currentDefaultButton;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets panel which receives input when ENTER is hit
+//-----------------------------------------------------------------------------
+VPANEL FocusNavGroup::GetDefaultButton()
+{
+ return _defaultButton;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: finds the panel which is activated by the specified key
+// Input : code - the keycode of the hotkey
+// Output : Panel * - NULL if no panel found
+//-----------------------------------------------------------------------------
+Panel *FocusNavGroup::FindPanelByHotkey(wchar_t key)
+{
+ for (int i = 0; i < _mainPanel->GetChildCount(); i++)
+ {
+ Panel *child = _mainPanel->GetChild(i);
+ if ( !child )
+ continue;
+
+ Panel *hot = child->HasHotkey(key);
+ if (hot && hot->IsVisible() && hot->IsEnabled())
+ {
+ return hot;
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+Panel *FocusNavGroup::GetDefaultPanel()
+{
+ for (int i = 0; i < _mainPanel->GetChildCount(); i++)
+ {
+ Panel *child = _mainPanel->GetChild(i);
+ if ( !child )
+ continue;
+
+ if (child->GetTabPosition() == 1)
+ {
+ return child;
+ }
+ }
+
+ return NULL; // no specific panel set
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+Panel *FocusNavGroup::GetCurrentFocus()
+{
+ return _currentFocus ? ipanel()->GetPanel(_currentFocus, vgui::GetControlsModuleName()) : NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the current focus
+//-----------------------------------------------------------------------------
+VPANEL FocusNavGroup::SetCurrentFocus(VPANEL focus, VPANEL defaultPanel)
+{
+ _currentFocus = focus;
+
+ // if we haven't found a default panel yet, let's see if we know of one
+ if (defaultPanel == 0)
+ {
+ // can this focus itself by the default
+ if (CanButtonBeDefault(focus))
+ {
+ defaultPanel = focus;
+ }
+ else if (_defaultButton) // do we know of a default button
+ {
+ defaultPanel = _defaultButton;
+ }
+ }
+
+ SetCurrentDefaultButton(defaultPanel);
+ return defaultPanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if the specified panel can be the default
+//-----------------------------------------------------------------------------
+bool FocusNavGroup::CanButtonBeDefault(VPANEL panel)
+{
+ if( panel == 0 )
+ return false;
+
+ KeyValues *data = new KeyValues("CanBeDefaultButton");
+
+ bool bResult = false;
+ if (ipanel()->RequestInfo(panel, data))
+ {
+ bResult = (data->GetInt("result") == 1);
+ }
+ data->deleteThis();
+ return bResult;
+}
\ No newline at end of file |