source-engine/tools/toolutils/savewindowpositions.cpp

287 lines
7.1 KiB
C++
Raw Permalink Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "toolutils/savewindowpositions.h"
#include "iregistry.h"
#include "vgui_controls/Panel.h"
#include "vgui_controls/PHandle.h"
#include "vgui_controls/ToolWindow.h"
#include "vgui/ISurface.h"
#include "vgui_controls/PropertySheet.h"
#include "tier1/utlsymbol.h"
#include "tier1/utlbuffer.h"
#include "tier1/KeyValues.h"
#include "filesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Purpose: This will save the bounds and the visibility state of UI elements registered during startup
// FIXME: Preserve Z order?
//-----------------------------------------------------------------------------
class CWindowPositionMgr : public IWindowPositionMgr
{
public:
// Inherited from IWindowPositionMgr
virtual void SavePositions( char const *filename, char const *key );
virtual bool LoadPositions( char const *filename, Panel *parent, vgui::IToolWindowFactory *factory, char const *key, bool force = false );
virtual void RegisterPanel( char const *saveName, Panel *panel, bool contextMenu );
virtual void UnregisterPanel( vgui::Panel *panel );
private:
struct LoadInfo_t
{
CUtlSymbol m_Name;
PHandle m_hPanel;
bool m_bLoaded;
bool m_bContextMenu;
};
LoadInfo_t *Find( Panel *panel );
LoadInfo_t *Find( char const *panelName );
CUtlVector< LoadInfo_t > m_Panels;
};
//-----------------------------------------------------------------------------
// Singleton instance
//-----------------------------------------------------------------------------
static CWindowPositionMgr g_WindowPositionMgr;
IWindowPositionMgr *windowposmgr = &g_WindowPositionMgr;
CWindowPositionMgr::LoadInfo_t *CWindowPositionMgr::Find( Panel *panel )
{
if ( !panel )
return NULL;
int c = m_Panels.Count();
for ( int i = 0; i < c; ++i )
{
LoadInfo_t *info = &m_Panels[ i ];
if ( info->m_hPanel.Get() == panel )
return info;
}
return NULL;
}
CWindowPositionMgr::LoadInfo_t *CWindowPositionMgr::Find( char const *panelName )
{
if ( !panelName )
return NULL;
int c = m_Panels.Count();
for ( int i = 0; i < c; ++i )
{
LoadInfo_t *info = &m_Panels[ i ];
if ( !Q_stricmp( info->m_Name.String(), panelName ) )
return info;
}
return NULL;
}
static void BufPrint( CUtlBuffer& buf, int level, char const *fmt, ... )
{
char string[ 2048 ];
va_list argptr;
va_start( argptr, fmt );
_vsnprintf( string, sizeof( string ) - 1, fmt, argptr );
va_end( argptr );
string[ sizeof( string ) - 1 ] = 0;
while ( --level >= 0 )
{
buf.Printf( " " );
}
buf.Printf( "%s", string );
}
void CWindowPositionMgr::SavePositions( char const *filename, char const *key )
{
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
buf.Printf( "%s\n", key );
buf.Printf( "{\n" );
int sw, sh;
vgui::surface()->GetScreenSize( sw, sh );
float flOOW = (sw != 0.0f) ? 1.0f / (float)sw : 1.0f;
float flOOH = (sh != 0.0f) ? 1.0f / (float)sh : 1.0f;
int c = ToolWindow::GetToolWindowCount();
for ( int i = 0 ; i < c; ++i )
{
ToolWindow *tw = ToolWindow::GetToolWindow( i );
Assert( tw );
if ( !tw )
continue;
BufPrint( buf, 1, "toolwindow\n" );
BufPrint( buf, 1, "{\n" );
// Get panel bounds
int x, y, w, h;
tw->GetBounds( x, y, w, h );
float fx = (float)x * flOOW;
float fy = (float)y * flOOH;
float fw = (float)w * flOOW;
float fh = (float)h * flOOH;
BufPrint( buf, 2, "bounds \"%.10f %.10f %.10f %.10f\"\n", fx, fy, fw, fh );
// Now iterate the actual contained panels
PropertySheet *sheet = tw->GetPropertySheet();
Assert( sheet );
if ( sheet )
{
int subCount = sheet->GetNumPages();
Assert( subCount > 0 );
if ( subCount > 0 )
{
BufPrint( buf, 2, "windows\n" );
BufPrint( buf, 2, "{\n" );
for ( int s = 0 ; s < subCount; ++s )
{
Panel *subPanel = sheet->GetPage( s );
if ( !subPanel )
continue;
LoadInfo_t *info = Find( subPanel );
if ( !info )
continue;
BufPrint( buf, 3, "panel \"%s\"\n", info->m_Name.String() );
}
BufPrint( buf, 2, "}\n" );
}
}
BufPrint( buf, 1, "}\n" );
}
buf.Printf( "}\n" );
if ( g_pFullFileSystem->FileExists( filename, "DEFAULT_WRITE_PATH" ) &&
!g_pFullFileSystem->IsFileWritable( filename, "DEFAULT_WRITE_PATH" ) )
{
Warning( "IFM window layout file '%s' is read-only!!!\n", filename );
}
FileHandle_t h = g_pFullFileSystem->Open( filename, "wb", "DEFAULT_WRITE_PATH" );
if ( FILESYSTEM_INVALID_HANDLE != h )
{
g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), h );
g_pFullFileSystem->Close( h );
}
}
bool CWindowPositionMgr::LoadPositions( char const *filename, vgui::Panel *parent, vgui::IToolWindowFactory *factory, char const *key, bool force /*=false*/ )
{
bool success = false;
int sw, sh;
vgui::surface()->GetScreenSize( sw, sh );
KeyValues *kv = new KeyValues( key );
if ( kv->LoadFromFile( g_pFullFileSystem, filename, "GAME" ) )
{
// Walk through tools
for ( KeyValues *tw = kv->GetFirstSubKey(); tw != NULL; tw = tw->GetNextKey() )
{
if ( Q_stricmp( tw->GetName(), "toolwindow" ) )
continue;
// read bounds
float fx, fy, fw, fh;
int x, y, w, h;
char const *bounds = tw->GetString( "bounds", "" );
if ( !bounds || !bounds[ 0 ] )
continue;
if ( 4 != sscanf( bounds, "%f %f %f %f", &fx, &fy, &fw, &fh ) )
continue;
x = (int)( sw * fx + 0.5f );
y = (int)( sh * fy + 0.5f );
w = (int)( sw * fw + 0.5f );
h = (int)( sh * fh + 0.5f );
w = clamp( w, 0, sw );
h = clamp( h, 0, sh );
// Now load pages
KeyValues *pages = tw->FindKey( "windows", false );
if ( !pages )
continue;
ToolWindow *newTool = factory->InstanceToolWindow( parent, true, NULL, NULL, false );
newTool->SetBounds( x, y, w, h );
for ( KeyValues *page = pages->GetFirstSubKey(); page != NULL; page = page->GetNextKey() )
{
if ( Q_stricmp( page->GetName(), "panel" ) )
continue;
char const *pageName = page->GetString();
if ( !pageName || !pageName[ 0 ] )
continue;
LoadInfo_t *info = Find( pageName );
if ( !info )
continue;
newTool->AddPage( info->m_hPanel.Get(), info->m_Name.String(), info->m_bContextMenu );
success = true;
}
// If we didn't successfully create something, delete the tool
if ( !success )
{
delete newTool;
}
}
}
kv->deleteThis();
return success;
}
void CWindowPositionMgr::RegisterPanel( char const *saveName, Panel *panel, bool contextMenu )
{
char const *panelName = panel->GetName();
if ( !panelName || !panelName[ 0 ] )
{
Warning( "CWindowPositionMgr::RegisterPanel: Panel has NULL or blank name!!!\n" );
return;
}
LoadInfo_t info;
info.m_hPanel = panel;
info.m_Name = saveName;
info.m_bLoaded = false;
info.m_bContextMenu = contextMenu;
m_Panels.AddToTail( info );
}
void CWindowPositionMgr::UnregisterPanel( vgui::Panel *panel )
{
int c = m_Panels.Count();
for ( int i = c - 1; i >= 0; --i )
{
if ( m_Panels[ i ].m_hPanel.Get() != panel )
continue;
m_Panels.Remove( i );
break;
}
}