//====== Copyright © 1996-2005, 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; } }