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.
1072 lines
31 KiB
1072 lines
31 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
|
|
#include <vgui/IPanel.h> |
|
#include <vgui/ISurface.h> |
|
#include <vgui/ISystem.h> |
|
#include <vgui/ILocalize.h> |
|
#include <KeyValues.h> |
|
#include "vgui/IVGui.h" |
|
|
|
#include <vgui_controls/BuildGroup.h> |
|
#include <vgui_controls/BuildModeDialog.h> |
|
#include <vgui_controls/EditablePanel.h> |
|
|
|
// these includes are all for the virtual contruction factory Dialog::CreateControlByName() |
|
#include <vgui_controls/Button.h> |
|
#include <vgui_controls/Label.h> |
|
#include <vgui_controls/CheckButton.h> |
|
#include <vgui_controls/ComboBox.h> |
|
#include <vgui_controls/Menu.h> |
|
#include <vgui_controls/MenuItem.h> |
|
#include <vgui_controls/MessageBox.h> |
|
#include <vgui_controls/ProgressBar.h> |
|
#include <vgui_controls/RadioButton.h> |
|
#include <vgui_controls/ScrollBar.h> |
|
#include <vgui_controls/ToggleButton.h> |
|
#include <vgui_controls/ImagePanel.h> |
|
#include <vgui_controls/AnimatingImagePanel.h> |
|
#include <vgui_controls/Divider.h> |
|
#include <vgui_controls/URLLabel.h> |
|
#include <vgui_controls/RichText.h> |
|
#include <vgui_controls/BitmapImagePanel.h> |
|
|
|
#include "filesystem.h" |
|
#include "fmtstr.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
using namespace vgui; |
|
|
|
DECLARE_BUILD_FACTORY( EditablePanel ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
#pragma warning( disable : 4355 ) |
|
|
|
EditablePanel::EditablePanel(Panel *parent, const char *panelName) : Panel(parent, panelName), m_NavGroup(this) |
|
{ |
|
_buildGroup = new BuildGroup(this, this); |
|
m_pszConfigName = NULL; |
|
m_iConfigID = 0; |
|
m_pDialogVariables = NULL; |
|
m_bShouldSkipAutoResize = false; |
|
|
|
// add ourselves to the build group |
|
SetBuildGroup(GetBuildGroup()); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
EditablePanel::EditablePanel(Panel *parent, const char *panelName, HScheme hScheme) : Panel(parent, panelName, hScheme), m_NavGroup(this) |
|
{ |
|
_buildGroup = new BuildGroup(this, this); |
|
m_pszConfigName = NULL; |
|
m_iConfigID = 0; |
|
m_pDialogVariables = NULL; |
|
m_bShouldSkipAutoResize = false; |
|
|
|
// add ourselves to the build group |
|
SetBuildGroup(GetBuildGroup()); |
|
} |
|
|
|
#pragma warning( default : 4355 ) |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor |
|
//----------------------------------------------------------------------------- |
|
EditablePanel::~EditablePanel() |
|
{ |
|
delete [] m_pszConfigName; |
|
delete _buildGroup; |
|
|
|
if (m_pDialogVariables) |
|
{ |
|
m_pDialogVariables->deleteThis(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when a child is added to the panel. |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnChildAdded(VPANEL child) |
|
{ |
|
BaseClass::OnChildAdded(child); |
|
|
|
// add only if we're in the same module |
|
Panel *panel = ipanel()->GetPanel(child, GetModuleName()); |
|
if (panel) |
|
{ |
|
panel->SetBuildGroup(_buildGroup); |
|
panel->AddActionSignalTarget(this); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnKeyCodePressed( KeyCode code ) |
|
{ |
|
static ConVarRef vgui_nav_lock_default_button( "vgui_nav_lock_default_button" ); |
|
if ( !vgui_nav_lock_default_button.IsValid() || vgui_nav_lock_default_button.GetInt() == 0 ) |
|
{ |
|
ButtonCode_t nButtonCode = GetBaseButtonCode( code ); |
|
|
|
// check for a default button |
|
VPANEL panel = GetFocusNavGroup().GetCurrentDefaultButton(); |
|
if ( panel && !IsConsoleStylePanel() ) |
|
{ |
|
switch ( nButtonCode ) |
|
{ |
|
case KEY_XBUTTON_UP: |
|
case KEY_XSTICK1_UP: |
|
case KEY_XSTICK2_UP: |
|
case KEY_UP: |
|
case STEAMCONTROLLER_DPAD_UP: |
|
case KEY_XBUTTON_DOWN: |
|
case KEY_XSTICK1_DOWN: |
|
case KEY_XSTICK2_DOWN: |
|
case KEY_DOWN: |
|
case STEAMCONTROLLER_DPAD_DOWN: |
|
case KEY_XBUTTON_LEFT: |
|
case KEY_XSTICK1_LEFT: |
|
case KEY_XSTICK2_LEFT: |
|
case KEY_LEFT: |
|
case KEY_XBUTTON_RIGHT: |
|
case KEY_XSTICK1_RIGHT: |
|
case KEY_XSTICK2_RIGHT: |
|
case KEY_RIGHT: |
|
case KEY_XBUTTON_B: |
|
case STEAMCONTROLLER_B: |
|
// Navigating menus |
|
vgui_nav_lock_default_button.SetValue( 1 ); |
|
PostMessage( panel, new KeyValues( "KeyCodePressed", "code", code ) ); |
|
return; |
|
|
|
case KEY_XBUTTON_A: |
|
case STEAMCONTROLLER_A: |
|
case KEY_ENTER: |
|
if ( ipanel()->IsVisible( panel ) && ipanel()->IsEnabled( panel ) ) |
|
{ |
|
// Activate the button |
|
PostMessage( panel, new KeyValues( "Hotkey" ) ); |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( !m_PassUnhandledInput ) |
|
return; |
|
|
|
// Nothing to do with the button |
|
BaseClass::OnKeyCodePressed( code ); |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Callback for when the panel size has been changed |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnSizeChanged(int wide, int tall) |
|
{ |
|
BaseClass::OnSizeChanged(wide, tall); |
|
InvalidateLayout(); |
|
|
|
for (int i = 0; i < GetChildCount(); i++) |
|
{ |
|
// perform auto-layout on the child panel |
|
Panel *child = GetChild(i); |
|
if ( !child ) |
|
continue; |
|
|
|
int x, y, w, h; |
|
child->GetBounds( x, y, w, h ); |
|
|
|
int px, py; |
|
child->GetPinOffset( px, py ); |
|
|
|
int ox, oy; |
|
child->GetResizeOffset( ox, oy ); |
|
|
|
int ex; |
|
int ey; |
|
|
|
AutoResize_e resize = child->GetAutoResize(); |
|
bool bResizeHoriz = ( resize == AUTORESIZE_RIGHT || resize == AUTORESIZE_DOWNANDRIGHT ); |
|
bool bResizeVert = ( resize == AUTORESIZE_DOWN || resize == AUTORESIZE_DOWNANDRIGHT ); |
|
|
|
// The correct version of this code would say: |
|
// if ( resize != AUTORESIZE_NO ) |
|
// but we're very close to shipping and this causes artifacts in other vgui panels that now |
|
// depend on this bug. So, I've added m_bShouldSkipAutoResize, which defaults to false but can |
|
// be set using "skip_autoresize" in a .res file |
|
if ( !m_bShouldSkipAutoResize ) |
|
{ |
|
PinCorner_e pinCorner = child->GetPinCorner(); |
|
if ( pinCorner == PIN_TOPRIGHT || pinCorner == PIN_BOTTOMRIGHT ) |
|
{ |
|
// move along with the right edge |
|
ex = wide + px; |
|
x = bResizeHoriz ? ox : ex - w; |
|
} |
|
else |
|
{ |
|
x = px; |
|
ex = bResizeHoriz ? wide + ox : px + w; |
|
} |
|
|
|
if ( pinCorner == PIN_BOTTOMLEFT || pinCorner == PIN_BOTTOMRIGHT ) |
|
{ |
|
// move along with the right edge |
|
ey = tall + py; |
|
y = bResizeVert ? oy : ey - h; |
|
} |
|
else |
|
{ |
|
y = py; |
|
ey = bResizeVert ? tall + oy : py + h; |
|
} |
|
|
|
// Clamp.. |
|
if ( ex < x ) |
|
{ |
|
ex = x; |
|
} |
|
if ( ey < y ) |
|
{ |
|
ey = y; |
|
} |
|
|
|
child->SetBounds( x, y, ex - x, ey - y ); |
|
child->InvalidateLayout(); |
|
} |
|
} |
|
Repaint(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnCurrentDefaultButtonSet( VPANEL defaultButton ) |
|
{ |
|
m_NavGroup.SetCurrentDefaultButton( defaultButton, false ); |
|
|
|
// forward the message up |
|
if (GetVParent()) |
|
{ |
|
KeyValues *msg = new KeyValues("CurrentDefaultButtonSet"); |
|
msg->SetInt("button", ivgui()->PanelToHandle( defaultButton ) ); |
|
PostMessage(GetVParent(), msg); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnDefaultButtonSet( VPANEL defaultButton ) |
|
{ |
|
Panel *panel = ipanel()->GetPanel( defaultButton, GetModuleName() ); |
|
|
|
m_NavGroup.SetDefaultButton(panel); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnFindDefaultButton() |
|
{ |
|
if (m_NavGroup.GetDefaultButton()) |
|
{ |
|
m_NavGroup.SetCurrentDefaultButton(m_NavGroup.GetDefaultButton()); |
|
} |
|
else |
|
{ |
|
if (GetVParent()) |
|
{ |
|
PostMessage(GetVParent(), new KeyValues("FindDefaultButton")); |
|
} |
|
} |
|
} |
|
|
|
struct leaf_t |
|
{ |
|
short x, y, wide, tall; |
|
unsigned char split; // 0 no split; 1 x-axis, 2 y-axis |
|
bool filled; // true if this is already filled |
|
short splitpos; // place of split |
|
|
|
leaf_t *left; |
|
leaf_t *right; |
|
}; |
|
|
|
leaf_t g_Leaves[256]; |
|
int g_iNextLeaf; |
|
|
|
inline leaf_t *AllocLeaf() |
|
{ |
|
Assert(g_iNextLeaf < 255); |
|
|
|
return &g_Leaves[g_iNextLeaf++]; |
|
} |
|
|
|
void AddSolidToTree(leaf_t *leaf, int x, int y, int wide, int tall) |
|
{ |
|
// clip to this leaf |
|
if (x < leaf->x) |
|
{ |
|
wide -= (leaf->x - x); |
|
if (wide < 1) |
|
return; |
|
x = leaf->x; |
|
} |
|
if (y < leaf->y) |
|
{ |
|
tall -= (leaf->y - y); |
|
if (tall < 1) |
|
return; |
|
y = leaf->y; |
|
} |
|
if (x + wide > leaf->x + leaf->wide) |
|
{ |
|
wide -= ((x + wide) - (leaf->x + leaf->wide)); |
|
if (wide < 1) |
|
return; |
|
} |
|
if (y + tall > leaf->y + leaf->tall) |
|
{ |
|
tall -= ((y + tall) - (leaf->y + leaf->tall)); |
|
if (tall < 1) |
|
return; |
|
} |
|
|
|
// the rect should now be completely within the leaf |
|
if (leaf->split == 1) |
|
{ |
|
// see if it is to the left or the right of the split |
|
if (x < leaf->splitpos) |
|
{ |
|
// it's to the left |
|
AddSolidToTree(leaf->left, x, y, wide, tall); |
|
} |
|
else if (x + wide > leaf->splitpos) |
|
{ |
|
// it's to the right |
|
AddSolidToTree(leaf->right, x, y, wide, tall); |
|
} |
|
} |
|
else if (leaf->split == 2) |
|
{ |
|
// check y |
|
// see if it is to the left (above) or the right (below) of the split |
|
if (y < leaf->splitpos) |
|
{ |
|
// it's above |
|
AddSolidToTree(leaf->left, x, y, wide, tall); |
|
} |
|
else if (y + tall > leaf->splitpos) |
|
{ |
|
// it's below |
|
AddSolidToTree(leaf->right, x, y, wide, tall); |
|
} |
|
} |
|
else |
|
{ |
|
// this leaf is unsplit, make the first split against the first edge we find |
|
if (x > leaf->x) |
|
{ |
|
// split the left side of the rect |
|
leaf->split = 1; |
|
leaf->splitpos = (short)x; |
|
|
|
// create 2 new leaves |
|
leaf_t *left = AllocLeaf(); |
|
leaf_t *right = AllocLeaf(); |
|
memset(left, 0, sizeof(leaf_t)); |
|
memset(right, 0, sizeof(leaf_t)); |
|
leaf->left = left; |
|
leaf->right = right; |
|
|
|
left->x = leaf->x; |
|
left->y = leaf->y; |
|
left->wide = (short)(leaf->splitpos - leaf->x); |
|
left->tall = leaf->tall; |
|
|
|
right->x = leaf->splitpos; |
|
right->y = leaf->y; |
|
right->wide = (short)(leaf->wide - left->wide); |
|
right->tall = leaf->tall; |
|
|
|
// split the right leaf by the current rect |
|
AddSolidToTree(leaf->right, x, y, wide, tall); |
|
} |
|
else if (y > leaf->y) |
|
{ |
|
// split the top edge |
|
leaf->split = 2; |
|
leaf->splitpos = (short)y; |
|
|
|
// create 2 new leaves (facing to the east) |
|
leaf_t *left = AllocLeaf(); |
|
leaf_t *right = AllocLeaf(); |
|
memset(left, 0, sizeof(leaf_t)); |
|
memset(right, 0, sizeof(leaf_t)); |
|
leaf->left = left; |
|
leaf->right = right; |
|
|
|
left->x = leaf->x; |
|
left->y = leaf->y; |
|
left->wide = leaf->wide; |
|
left->tall = (short)(y - leaf->y); |
|
|
|
right->x = leaf->x; |
|
right->y = leaf->splitpos; |
|
right->wide = leaf->wide; |
|
right->tall = (short)(leaf->tall + leaf->y - right->y); |
|
|
|
// split the right leaf by the current rect |
|
AddSolidToTree(leaf->right, x, y, wide, tall); |
|
} |
|
else if (x + wide < leaf->x + leaf->wide) |
|
{ |
|
// split the right edge |
|
leaf->split = 1; |
|
leaf->splitpos = (short)(x + wide); |
|
|
|
// create 2 new leaves |
|
leaf_t *left = AllocLeaf(); |
|
leaf_t *right = AllocLeaf(); |
|
memset(left, 0, sizeof(leaf_t)); |
|
memset(right, 0, sizeof(leaf_t)); |
|
leaf->left = left; |
|
leaf->right = right; |
|
|
|
left->x = leaf->x; |
|
left->y = leaf->y; |
|
left->wide = (short)(leaf->splitpos - leaf->x); |
|
left->tall = leaf->tall; |
|
|
|
right->x = leaf->splitpos; |
|
right->y = leaf->y; |
|
right->wide = (short)(leaf->wide - left->wide); |
|
right->tall = leaf->tall; |
|
|
|
// split the left leaf by the current rect |
|
AddSolidToTree(leaf->left, x, y, wide, tall); |
|
} |
|
else if (y + tall < leaf->y + leaf->tall) |
|
{ |
|
// split the bottom edge |
|
leaf->split = 2; |
|
leaf->splitpos = (short)(y + tall); |
|
|
|
// create 2 new leaves (facing to the east) |
|
leaf_t *left = AllocLeaf(); |
|
leaf_t *right = AllocLeaf(); |
|
memset(left, 0, sizeof(leaf_t)); |
|
memset(right, 0, sizeof(leaf_t)); |
|
leaf->left = left; |
|
leaf->right = right; |
|
|
|
left->x = leaf->x; |
|
left->y = leaf->y; |
|
left->wide = leaf->wide; |
|
left->tall = (short)(leaf->splitpos - leaf->y); |
|
|
|
right->x = leaf->x; |
|
right->y = leaf->splitpos; |
|
right->wide = leaf->wide; |
|
right->tall = (short)(leaf->tall - left->tall); |
|
|
|
// split the left leaf by the current rect |
|
AddSolidToTree(leaf->left, x, y, wide, tall); |
|
} |
|
else |
|
{ |
|
// this is the exact same rect! don't draw this leaf |
|
leaf->filled = true; |
|
return; |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Fills the panel background, clipping if possible |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::PaintBackground() |
|
{ |
|
BaseClass::PaintBackground(); |
|
return; |
|
|
|
/* |
|
test code, using a screenspace bsp tree to reduce overdraw in vgui |
|
not yet fully functional |
|
|
|
// test: fill background with obnoxious color to show holes |
|
// surface()->DrawSetColor(Color(255, 0, 0, 255)); |
|
// surface()->DrawFilledRect(0, 0, GetWide(), GetTall()); |
|
// return; |
|
|
|
// reset the leaf memory |
|
g_iNextLeaf = 0; |
|
|
|
leaf_t *headNode = AllocLeaf(); |
|
memset(headNode, 0, sizeof(leaf_t)); |
|
|
|
headNode->wide = (short)GetWide(); |
|
headNode->tall = (short)GetTall(); |
|
|
|
// split the leaf by the first child |
|
for (int i = 0; i < GetChildCount(); i++) |
|
{ |
|
Panel *child = GetChild(i); |
|
if (child->IsOpaque()) |
|
{ |
|
int x, y, wide, tall; |
|
child->GetBounds(x, y, wide, tall); |
|
|
|
// ignore small children |
|
if (wide + tall < 100) |
|
continue; |
|
|
|
AddSolidToTree(headNode, x, y, wide, tall); |
|
} |
|
} |
|
|
|
// walk the built tree, painting the background |
|
Color col = GetBgColor(); |
|
surface()->DrawSetColor(col); |
|
for (i = 0; i < g_iNextLeaf; i++) |
|
{ |
|
leaf_t *leaf = g_Leaves + i; |
|
if (leaf->splitpos || leaf->filled) |
|
continue; |
|
surface()->DrawFilledRect(leaf->x, leaf->y, leaf->x + leaf->wide, leaf->y + leaf->tall); |
|
} |
|
*/ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Activates the build mode dialog for editing panels. |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::ActivateBuildMode() |
|
{ |
|
_buildGroup->SetEnabled(true); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Loads panel settings from a resource file. |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::LoadControlSettings(const char *resourceName, const char *pathID, KeyValues *pKeyValues, KeyValues *pConditions) |
|
{ |
|
#if defined( DBGFLAG_ASSERT ) && !defined(OSX) && !defined(LINUX) |
|
// Since nobody wants to fix this assert, I'm making it a Msg instead: |
|
// editablepanel.cpp (535) : Resource file "resource\DebugOptionsPanel.res" not found on disk! |
|
// AssertMsg( g_pFullFileSystem->FileExists( resourceName ), CFmtStr( "Resource file \"%s\" not found on disk!", resourceName ).Access() ); |
|
if ( !g_pFullFileSystem->FileExists( resourceName ) ) |
|
{ |
|
Msg( "Resource file \"%s\" not found on disk!", resourceName ); |
|
} |
|
#endif |
|
_buildGroup->LoadControlSettings(resourceName, pathID, pKeyValues, pConditions); |
|
ForceSubPanelsToUpdateWithNewDialogVariables(); |
|
InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: registers a file in the list of control settings, so the vgui dialog can choose between them to edit |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::RegisterControlSettingsFile(const char *resourceName, const char *pathID) |
|
{ |
|
_buildGroup->RegisterControlSettingsFile(resourceName, pathID); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sets the name of this dialog so it can be saved in the user config area |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::LoadUserConfig(const char *configName, int dialogID) |
|
{ |
|
KeyValues *data = system()->GetUserConfigFileData(configName, dialogID); |
|
|
|
delete [] m_pszConfigName; |
|
int len = Q_strlen(configName) + 1; |
|
m_pszConfigName = new char[ len ]; |
|
Q_strncpy(m_pszConfigName, configName, len ); |
|
m_iConfigID = dialogID; |
|
|
|
// apply our user config settings (this will recurse through our children) |
|
if (data) |
|
{ |
|
ApplyUserConfigSettings(data); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: saves all the settings to the document |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SaveUserConfig() |
|
{ |
|
if (m_pszConfigName) |
|
{ |
|
KeyValues *data = system()->GetUserConfigFileData(m_pszConfigName, m_iConfigID); |
|
|
|
// get our user config settings (this will recurse through our children) |
|
if (data) |
|
{ |
|
GetUserConfigSettings(data); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: combines both of the above, LoadControlSettings & LoadUserConfig |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::LoadControlSettingsAndUserConfig(const char *dialogResourceName, int dialogID) |
|
{ |
|
LoadControlSettings(dialogResourceName); |
|
LoadUserConfig(dialogResourceName, dialogID); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: applies the user config settings to all the children |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::ApplyUserConfigSettings(KeyValues *userConfig) |
|
{ |
|
for (int i = 0; i < GetChildCount(); i++) |
|
{ |
|
Panel *child = GetChild(i); |
|
if (child->HasUserConfigSettings()) |
|
{ |
|
const char *name = child->GetName(); |
|
if (name && *name) |
|
{ |
|
child->ApplyUserConfigSettings(userConfig->FindKey(name, true)); |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: gets all the children's user config settings |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::GetUserConfigSettings(KeyValues *userConfig) |
|
{ |
|
for (int i = 0; i < GetChildCount(); i++) |
|
{ |
|
Panel *child = GetChild(i); |
|
if (child->HasUserConfigSettings()) |
|
{ |
|
const char *name = child->GetName(); |
|
if (name && *name) |
|
{ |
|
child->GetUserConfigSettings(userConfig->FindKey(name, true)); |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Save user config settings |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnClose() |
|
{ |
|
SaveUserConfig(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handle information requests |
|
//----------------------------------------------------------------------------- |
|
bool EditablePanel::RequestInfo(KeyValues *data) |
|
{ |
|
if (!stricmp(data->GetName(), "BuildDialog")) |
|
{ |
|
// a build dialog is being requested, give it one |
|
// a bit hacky, but this is a case where vgui.dll needs to reach out |
|
data->SetPtr("PanelPtr", new BuildModeDialog( (BuildGroup *)data->GetPtr("BuildGroupPtr"))); |
|
return true; |
|
} |
|
else if (!stricmp(data->GetName(), "ControlFactory")) |
|
{ |
|
Panel *newPanel = CreateControlByName(data->GetString("ControlName")); |
|
if (newPanel) |
|
{ |
|
data->SetPtr("PanelPtr", newPanel); |
|
return true; |
|
} |
|
} |
|
return BaseClass::RequestInfo(data); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return the buildgroup that this panel is part of. |
|
// Input : |
|
// Output : BuildGroup |
|
//----------------------------------------------------------------------------- |
|
BuildGroup *EditablePanel::GetBuildGroup() |
|
{ |
|
return _buildGroup; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return a pointer to the nav group |
|
// Output : FocusNavGroup |
|
//----------------------------------------------------------------------------- |
|
FocusNavGroup &EditablePanel::GetFocusNavGroup() |
|
{ |
|
return m_NavGroup; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool EditablePanel::RequestFocusNext(VPANEL panel) |
|
{ |
|
bool bRet = m_NavGroup.RequestFocusNext(panel); |
|
if ( IsPC() && !bRet && IsConsoleStylePanel() ) |
|
{ |
|
NavigateDown(); |
|
} |
|
return bRet; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool EditablePanel::RequestFocusPrev(VPANEL panel) |
|
{ |
|
bool bRet = m_NavGroup.RequestFocusPrev(panel); |
|
if ( IsPC() && !bRet && IsConsoleStylePanel() ) |
|
{ |
|
NavigateUp(); |
|
} |
|
return bRet; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Delegates focus to a sub panel |
|
// Input : direction - the direction in which focus travelled to arrive at this panel; forward = 1, back = -1 |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::RequestFocus(int direction) |
|
{ |
|
// we must be a sub panel for this to be called |
|
// delegate focus |
|
if (direction == 1) |
|
{ |
|
RequestFocusNext(NULL); |
|
} |
|
else if (direction == -1) |
|
{ |
|
RequestFocusPrev(NULL); |
|
} |
|
else |
|
{ |
|
BaseClass::RequestFocus(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Pass the focus down onto the last used panel |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnSetFocus() |
|
{ |
|
Panel *focus = m_NavGroup.GetCurrentFocus(); |
|
if (focus && focus != this) |
|
{ |
|
focus->RequestFocus(); |
|
} |
|
else |
|
{ |
|
focus = m_NavGroup.GetDefaultPanel(); |
|
if (focus) |
|
{ |
|
focus->RequestFocus(); |
|
focus->OnSetFocus(); |
|
} |
|
} |
|
|
|
BaseClass::OnSetFocus(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when the resource file is loaded to set up the panel state |
|
// Input : *inResourceData - |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::ApplySettings(KeyValues *inResourceData) |
|
{ |
|
BaseClass::ApplySettings(inResourceData); |
|
|
|
_buildGroup->ApplySettings(inResourceData); |
|
|
|
m_bShouldSkipAutoResize = inResourceData->GetBool( "skip_autoresize", false ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Update focus info for navigation |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::OnRequestFocus(VPANEL subFocus, VPANEL defaultPanel) |
|
{ |
|
if (!ipanel()->IsPopup(subFocus)) |
|
{ |
|
defaultPanel = m_NavGroup.SetCurrentFocus(subFocus, defaultPanel); |
|
} |
|
BaseClass::OnRequestFocus(GetVPanel(), defaultPanel); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the panel that currently has keyfocus |
|
//----------------------------------------------------------------------------- |
|
VPANEL EditablePanel::GetCurrentKeyFocus() |
|
{ |
|
Panel *focus = m_NavGroup.GetCurrentFocus(); |
|
if (focus == this) |
|
return NULL; |
|
|
|
if (focus) |
|
{ |
|
if (focus->IsPopup()) |
|
return BaseClass::GetCurrentKeyFocus(); |
|
|
|
// chain down the editpanel hierarchy |
|
VPANEL subFocus = focus->GetCurrentKeyFocus(); |
|
if (subFocus) |
|
return subFocus; |
|
|
|
// hit a leaf panel, return that |
|
return focus->GetVPanel(); |
|
} |
|
return BaseClass::GetCurrentKeyFocus(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Gets the panel with the specified hotkey |
|
//----------------------------------------------------------------------------- |
|
Panel *EditablePanel::HasHotkey(wchar_t key) |
|
{ |
|
if( !IsVisible() || !IsEnabled()) // not visible, so can't respond to a hot key |
|
{ |
|
return NULL; |
|
} |
|
|
|
for (int i = 0; i < GetChildCount(); i++) |
|
{ |
|
Panel *hot = GetChild(i)->HasHotkey(key); |
|
if (hot && hot->IsVisible() && hot->IsEnabled()) |
|
{ |
|
return hot; |
|
} |
|
} |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to setting enabled state of control |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetControlEnabled(const char *controlName, bool enabled) |
|
{ |
|
Panel *control = FindChildByName(controlName); |
|
if (control) |
|
{ |
|
control->SetEnabled(enabled); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to setting visibility state of control |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetControlVisible(const char *controlName, bool visible, bool bRecurseDown /*= false*/ ) |
|
{ |
|
Panel *control = FindChildByName(controlName, bRecurseDown); |
|
if (control) |
|
{ |
|
control->SetVisible(visible); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to set data in child controls |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetControlString(const char *controlName, const char *string) |
|
{ |
|
Panel *control = FindChildByName(controlName); |
|
if (control) |
|
{ |
|
if (string[0] == '#') |
|
{ |
|
const wchar_t *wszText = g_pVGuiLocalize->Find(string); |
|
if (wszText) |
|
{ |
|
PostMessage(control, new KeyValues("SetText", "text", wszText)); |
|
} |
|
} |
|
else |
|
{ |
|
PostMessage(control, new KeyValues("SetText", "text", string)); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to set data in child controls |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetControlString(const char *controlName, const wchar_t *string) |
|
{ |
|
Panel *control = FindChildByName(controlName); |
|
if (control) |
|
{ |
|
PostMessage(control, new KeyValues("SetText", "text", string)); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to set data in child controls |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetControlInt(const char *controlName, int state) |
|
{ |
|
Panel *control = FindChildByName(controlName); |
|
if (control) |
|
{ |
|
PostMessage(control, new KeyValues("SetState", "state", state)); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to get data in child controls |
|
//----------------------------------------------------------------------------- |
|
int EditablePanel::GetControlInt(const char *controlName, int defaultState) |
|
{ |
|
Panel *control = FindChildByName(controlName); |
|
if (control) |
|
{ |
|
KeyValues *data = new KeyValues("GetState"); |
|
if (control->RequestInfo(data)) |
|
{ |
|
int state = data->GetInt("state", defaultState); |
|
data->deleteThis(); |
|
return state; |
|
} |
|
} |
|
return defaultState; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to get data in child controls |
|
//----------------------------------------------------------------------------- |
|
const char *EditablePanel::GetControlString(const char *controlName, const char *defaultString) |
|
{ |
|
static char buf[512]; |
|
GetControlString(controlName, buf, sizeof(buf) - 1, defaultString); |
|
return buf; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shortcut function to get data in child controls |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::GetControlString(const char *controlName, char *buf, int bufSize, const char *defaultString) |
|
{ |
|
Panel *control = FindChildByName(controlName); |
|
KeyValues *data = new KeyValues("GetText"); |
|
if (control && control->RequestInfo(data)) |
|
{ |
|
Q_strncpy(buf, data->GetString("text", defaultString), bufSize); |
|
} |
|
else |
|
{ |
|
// no value found, copy in default text |
|
Q_strncpy(buf, defaultString, bufSize); |
|
} |
|
|
|
// ensure null termination of string |
|
buf[bufSize - 1] = 0; |
|
|
|
// free |
|
data->deleteThis(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: localization variables (used in constructing UI strings) |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetDialogVariable(const char *varName, const char *value) |
|
{ |
|
GetDialogVariables()->SetString(varName, value); |
|
ForceSubPanelsToUpdateWithNewDialogVariables(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: localization variables (used in constructing UI strings) |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetDialogVariable(const char *varName, const wchar_t *value) |
|
{ |
|
GetDialogVariables()->SetWString(varName, value); |
|
ForceSubPanelsToUpdateWithNewDialogVariables(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: localization variables (used in constructing UI strings) |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetDialogVariable(const char *varName, int value) |
|
{ |
|
GetDialogVariables()->SetInt(varName, value); |
|
ForceSubPanelsToUpdateWithNewDialogVariables(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: localization variables (used in constructing UI strings) |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::SetDialogVariable(const char *varName, float value) |
|
{ |
|
GetDialogVariables()->SetFloat(varName, value); |
|
ForceSubPanelsToUpdateWithNewDialogVariables(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: redraws child panels with new localization vars |
|
//----------------------------------------------------------------------------- |
|
void EditablePanel::ForceSubPanelsToUpdateWithNewDialogVariables() |
|
{ |
|
if (m_pDialogVariables) |
|
{ |
|
ipanel()->SendMessage(GetVPanel(), m_pDialogVariables, GetVPanel()); |
|
for (int i = 0; i < ipanel()->GetChildCount(GetVPanel()); i++) |
|
{ |
|
ipanel()->SendMessage(ipanel()->GetChild(GetVPanel(), i), m_pDialogVariables, GetVPanel()); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: lazy creation of localization vars object |
|
//----------------------------------------------------------------------------- |
|
KeyValues *EditablePanel::GetDialogVariables() |
|
{ |
|
if (m_pDialogVariables) |
|
return m_pDialogVariables; |
|
|
|
m_pDialogVariables = new KeyValues("DialogVariables"); |
|
return m_pDialogVariables; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Virtual factory for control creation |
|
//----------------------------------------------------------------------------- |
|
Panel *EditablePanel::CreateControlByName(const char *controlName) |
|
{ |
|
Panel *fromFactory = CBuildFactoryHelper::InstancePanel( controlName ); |
|
if ( fromFactory ) |
|
{ |
|
return fromFactory; |
|
} |
|
|
|
return NULL; |
|
}
|
|
|