mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
982 lines
30 KiB
C++
982 lines
30 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
IceTech GPL Source Code
|
|
Copyright (C) 2026 Justin Marshall
|
|
|
|
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
|
|
|
IceTech Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
IceTech Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "../radiant/qe3.h"
|
|
#include "DialogDeclBrowser.h"
|
|
#include "../radiant/InspectorDialog.h"
|
|
#include <commctrl.h>
|
|
|
|
#ifdef ID_DEBUG_MEMORY
|
|
#undef new
|
|
#undef DEBUG_NEW
|
|
#define DEBUG_NEW new
|
|
#endif
|
|
|
|
const int DECLTYPE_SHIFT = 24;
|
|
const int DECLINDEX_MASK = ( 1 << DECLTYPE_SHIFT ) - 1;
|
|
|
|
#define GetIdFromTypeAndIndex( type, index ) ( ( (int)type << DECLTYPE_SHIFT ) | index )
|
|
#define GetTypeFromId( id ) ( (declType_t) ( (int)id >> DECLTYPE_SHIFT ) )
|
|
#define GetIndexFromId( id ) ( (int)id & DECLINDEX_MASK )
|
|
|
|
static const COLORREF DECL_BROWSER_BG = RGB( 17, 19, 23 );
|
|
static const COLORREF DECL_BROWSER_PANEL_BG = RGB( 23, 26, 31 );
|
|
static const COLORREF DECL_BROWSER_FIELD_BG = RGB( 14, 16, 20 );
|
|
static const COLORREF DECL_BROWSER_TEXT = RGB( 226, 232, 240 );
|
|
static const COLORREF DECL_BROWSER_MUTED_TEXT = RGB( 151, 163, 184 );
|
|
static const COLORREF DECL_BROWSER_BORDER = RGB( 58, 64, 72 );
|
|
static const COLORREF DECL_BROWSER_ACCENT = RGB( 87, 166, 255 );
|
|
|
|
static const int DECL_BROWSER_MARGIN = 8;
|
|
static const int DECL_BROWSER_ROW_HEIGHT = 24;
|
|
static const int DECL_BROWSER_BUTTON_HEIGHT = 24;
|
|
static const int DECL_BROWSER_STATUS_HEIGHT = 20;
|
|
static const int DECL_BROWSER_LEFT_MIN_WIDTH = 260;
|
|
static const int DECL_BROWSER_LEFT_MAX_WIDTH = 420;
|
|
|
|
static const UINT IDC_DECLBROWSER_CHILD_TREE = 0x5C00;
|
|
static const UINT IDC_DECLBROWSER_CHILD_BASE_TREE = 0x5C01;
|
|
static const UINT IDC_DECLBROWSER_CHILD_FIND_NAME = 0x5C02;
|
|
static const UINT IDC_DECLBROWSER_CHILD_FIND_TEXT = 0x5C03;
|
|
static const UINT IDC_DECLBROWSER_CHILD_FIND = 0x5C04;
|
|
static const UINT IDC_DECLBROWSER_CHILD_LOAD = 0x5C05;
|
|
static const UINT IDC_DECLBROWSER_CHILD_RELOAD = 0x5C06;
|
|
static const UINT IDC_DECLBROWSER_CHILD_NEW_TYPE = 0x5C07;
|
|
static const UINT IDC_DECLBROWSER_CHILD_NEW_NAME = 0x5C08;
|
|
static const UINT IDC_DECLBROWSER_CHILD_NEW_FILE = 0x5C09;
|
|
static const UINT IDC_DECLBROWSER_CHILD_CREATE = 0x5C0A;
|
|
static const UINT IDC_DECLBROWSER_CHILD_EDITOR = 0x5C0B;
|
|
|
|
static const char *DECL_BROWSER_DARK_FIELD_OLDPROC = "IceTech.DeclBrowser.DarkFieldOldProc";
|
|
|
|
#ifndef TVS_NOTOOLTIPS
|
|
#define TVS_NOTOOLTIPS 0x0080
|
|
#endif
|
|
|
|
toolTip_t DialogDeclBrowser::toolTips[] = {
|
|
{ IDC_DECLBROWSER_CHILD_TREE, "declaration browser" },
|
|
{ IDC_DECLBROWSER_CHILD_FIND_NAME, "search for declarations with matching name, supports *, ? and [abc...]" },
|
|
{ IDC_DECLBROWSER_CHILD_FIND_TEXT, "search for declarations containing text" },
|
|
{ IDC_DECLBROWSER_CHILD_FIND, "find declarations matching the search strings" },
|
|
{ IDC_DECLBROWSER_CHILD_LOAD, "load the selected declaration into the editor" },
|
|
{ IDC_DECLBROWSER_CHILD_RELOAD, "reload declarations" },
|
|
{ IDC_DECLBROWSER_CHILD_NEW_TYPE, "type for a new declaration" },
|
|
{ IDC_DECLBROWSER_CHILD_NEW_NAME, "name for a new declaration" },
|
|
{ IDC_DECLBROWSER_CHILD_NEW_FILE, "source file for a new declaration" },
|
|
{ IDC_DECLBROWSER_CHILD_CREATE, "create a new declaration through the declaration manager" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static void DeclBrowserFillRect( HDC hDC, const RECT &rc, COLORREF color ) {
|
|
HBRUSH brush = ::CreateSolidBrush( color );
|
|
::FillRect( hDC, &rc, brush );
|
|
::DeleteObject( brush );
|
|
}
|
|
|
|
static void DeclBrowserFrameRect( HDC hDC, const RECT &rc, COLORREF color ) {
|
|
HBRUSH brush = ::CreateSolidBrush( color );
|
|
::FrameRect( hDC, &rc, brush );
|
|
::DeleteObject( brush );
|
|
}
|
|
|
|
static void DeclBrowserApplyNativeDarkTheme( HWND hWnd ) {
|
|
if ( !hWnd ) {
|
|
return;
|
|
}
|
|
|
|
typedef HRESULT (WINAPI *SetWindowThemeProc)( HWND, LPCWSTR, LPCWSTR );
|
|
typedef BOOL (WINAPI *AllowDarkModeForWindowProc)( HWND, BOOL );
|
|
static HMODULE hUxTheme = ::LoadLibraryA( "uxtheme.dll" );
|
|
static SetWindowThemeProc pSetWindowTheme = hUxTheme ? (SetWindowThemeProc)::GetProcAddress( hUxTheme, "SetWindowTheme" ) : NULL;
|
|
static AllowDarkModeForWindowProc pAllowDarkModeForWindow = hUxTheme ? (AllowDarkModeForWindowProc)::GetProcAddress( hUxTheme, MAKEINTRESOURCEA( 133 ) ) : NULL;
|
|
|
|
if ( pAllowDarkModeForWindow ) {
|
|
pAllowDarkModeForWindow( hWnd, TRUE );
|
|
}
|
|
if ( pSetWindowTheme ) {
|
|
pSetWindowTheme( hWnd, L"DarkMode_Explorer", NULL );
|
|
}
|
|
::SendMessage( hWnd, WM_THEMECHANGED, 0, 0 );
|
|
}
|
|
|
|
static bool DeclBrowserIsClass( HWND hWnd, const char *className ) {
|
|
char actual[128];
|
|
actual[0] = '\0';
|
|
::GetClassNameA( hWnd, actual, sizeof( actual ) );
|
|
return ::lstrcmpiA( actual, className ) == 0;
|
|
}
|
|
|
|
static void DeclBrowserRemoveClientEdge( HWND hWnd ) {
|
|
if ( !hWnd ) {
|
|
return;
|
|
}
|
|
LONG exStyle = ::GetWindowLong( hWnd, GWL_EXSTYLE );
|
|
if ( exStyle & WS_EX_CLIENTEDGE ) {
|
|
::SetWindowLong( hWnd, GWL_EXSTYLE, exStyle & ~WS_EX_CLIENTEDGE );
|
|
::SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED );
|
|
}
|
|
}
|
|
|
|
static void DeclBrowserDrawWindowFrame( HWND hWnd ) {
|
|
HDC hDC = ::GetWindowDC( hWnd );
|
|
if ( !hDC ) {
|
|
return;
|
|
}
|
|
RECT rc;
|
|
::GetWindowRect( hWnd, &rc );
|
|
::OffsetRect( &rc, -rc.left, -rc.top );
|
|
DeclBrowserFrameRect( hDC, rc, DECL_BROWSER_BORDER );
|
|
::ReleaseDC( hWnd, hDC );
|
|
}
|
|
|
|
static LRESULT CALLBACK DeclBrowserDarkFieldProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
|
|
WNDPROC oldProc = (WNDPROC)::GetPropA( hWnd, DECL_BROWSER_DARK_FIELD_OLDPROC );
|
|
if ( !oldProc ) {
|
|
return ::DefWindowProc( hWnd, uMsg, wParam, lParam );
|
|
}
|
|
|
|
switch( uMsg ) {
|
|
case WM_NCPAINT:
|
|
case WM_PAINT:
|
|
{
|
|
LRESULT result = ::CallWindowProc( oldProc, hWnd, uMsg, wParam, lParam );
|
|
DeclBrowserDrawWindowFrame( hWnd );
|
|
return result;
|
|
}
|
|
case WM_SETFOCUS:
|
|
case WM_KILLFOCUS:
|
|
case WM_ENABLE:
|
|
{
|
|
LRESULT result = ::CallWindowProc( oldProc, hWnd, uMsg, wParam, lParam );
|
|
::RedrawWindow( hWnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW );
|
|
return result;
|
|
}
|
|
case WM_NCDESTROY:
|
|
{
|
|
::SetWindowLongPtr( hWnd, GWLP_WNDPROC, (LONG_PTR)oldProc );
|
|
::RemovePropA( hWnd, DECL_BROWSER_DARK_FIELD_OLDPROC );
|
|
return ::CallWindowProc( oldProc, hWnd, uMsg, wParam, lParam );
|
|
}
|
|
}
|
|
|
|
return ::CallWindowProc( oldProc, hWnd, uMsg, wParam, lParam );
|
|
}
|
|
|
|
static void DeclBrowserSubclassField( HWND hWnd ) {
|
|
if ( !hWnd || ::GetPropA( hWnd, DECL_BROWSER_DARK_FIELD_OLDPROC ) ) {
|
|
return;
|
|
}
|
|
WNDPROC oldProc = (WNDPROC)::GetWindowLongPtr( hWnd, GWLP_WNDPROC );
|
|
::SetPropA( hWnd, DECL_BROWSER_DARK_FIELD_OLDPROC, (HANDLE)oldProc );
|
|
::SetWindowLongPtr( hWnd, GWLP_WNDPROC, (LONG_PTR)DeclBrowserDarkFieldProc );
|
|
}
|
|
|
|
template< class type >
|
|
int idListDeclSortCompare( const type *a, const type *b ) {
|
|
return idStr::IcmpPath( (*a)->GetName(), (*b)->GetName() );
|
|
}
|
|
|
|
IMPLEMENT_DYNAMIC(DialogDeclBrowser, CWnd)
|
|
|
|
DialogDeclBrowser::DialogDeclBrowser()
|
|
: CWnd()
|
|
, numListedDecls( 0 )
|
|
, controlsCreated( false )
|
|
, reloadingTree( false )
|
|
, m_pchTip( NULL )
|
|
, m_pwchTip( NULL ) {
|
|
}
|
|
|
|
DialogDeclBrowser::~DialogDeclBrowser() {
|
|
delete m_pwchTip;
|
|
delete m_pchTip;
|
|
if ( modernFont.GetSafeHandle() ) {
|
|
modernFont.DeleteObject();
|
|
}
|
|
if ( bgBrush.GetSafeHandle() ) {
|
|
bgBrush.DeleteObject();
|
|
}
|
|
if ( panelBrush.GetSafeHandle() ) {
|
|
panelBrush.DeleteObject();
|
|
}
|
|
if ( editBrush.GetSafeHandle() ) {
|
|
editBrush.DeleteObject();
|
|
}
|
|
if ( staticBrush.GetSafeHandle() ) {
|
|
staticBrush.DeleteObject();
|
|
}
|
|
}
|
|
|
|
BOOL DialogDeclBrowser::Create( CWnd *parent, UINT id ) {
|
|
if ( !parent ) {
|
|
return FALSE;
|
|
}
|
|
if ( id == 0 ) {
|
|
id = (UINT)-1;
|
|
}
|
|
|
|
CString className = AfxRegisterWndClass( CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, ::LoadCursor( NULL, IDC_ARROW ), (HBRUSH)::GetStockObject( NULL_BRUSH ), NULL );
|
|
CRect rect( 0, 0, 100, 100 );
|
|
return CWnd::CreateEx( 0, className, "DeclBrowserChild", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, rect, parent, id );
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(DialogDeclBrowser, CWnd)
|
|
ON_WM_CREATE()
|
|
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
|
|
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
|
|
ON_WM_CTLCOLOR()
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_PAINT()
|
|
ON_WM_DESTROY()
|
|
ON_WM_SIZE()
|
|
ON_WM_SETFOCUS()
|
|
ON_NOTIFY(TVN_SELCHANGED, IDC_DECLBROWSER_CHILD_TREE, OnTreeSelChanged)
|
|
ON_NOTIFY(NM_DBLCLK, IDC_DECLBROWSER_CHILD_TREE, OnTreeDblclk)
|
|
ON_BN_CLICKED(IDC_DECLBROWSER_CHILD_FIND, OnBnClickedFind)
|
|
ON_BN_CLICKED(IDC_DECLBROWSER_CHILD_LOAD, OnBnClickedLoad)
|
|
ON_BN_CLICKED(IDC_DECLBROWSER_CHILD_CREATE, OnBnClickedCreate)
|
|
ON_BN_CLICKED(IDC_DECLBROWSER_CHILD_RELOAD, OnBnClickedReload)
|
|
ON_CBN_SELCHANGE(IDC_DECLBROWSER_CHILD_NEW_TYPE, OnTypeChanged)
|
|
END_MESSAGE_MAP()
|
|
|
|
int DialogDeclBrowser::OnCreate( LPCREATESTRUCT lpCreateStruct ) {
|
|
if ( CWnd::OnCreate( lpCreateStruct ) == -1 ) {
|
|
return -1;
|
|
}
|
|
|
|
CreateChildControls();
|
|
ApplyDarkTheme();
|
|
PopulateTypeCombo();
|
|
InitBaseDeclTree();
|
|
findNameString = "*";
|
|
findTextString = "";
|
|
findNameEdit.SetWindowText( findNameString.c_str() );
|
|
findTextEdit.SetWindowText( findTextString.c_str() );
|
|
OnBnClickedFind();
|
|
SetBrowserStatus( va( "%d decls listed", numListedDecls ) );
|
|
return 0;
|
|
}
|
|
|
|
void DialogDeclBrowser::CreateChildControls( void ) {
|
|
if ( controlsCreated ) {
|
|
return;
|
|
}
|
|
|
|
CRect r( 0, 0, 0, 0 );
|
|
DWORD staticStyle = WS_CHILD | WS_VISIBLE | SS_LEFT | SS_NOPREFIX;
|
|
DWORD editStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL;
|
|
DWORD buttonStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON;
|
|
|
|
declTree.Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS, r, this, IDC_DECLBROWSER_CHILD_TREE );
|
|
baseDeclTree.Create( WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_NOTOOLTIPS, r, this, IDC_DECLBROWSER_CHILD_BASE_TREE );
|
|
|
|
findNameStatic.Create( "Name", staticStyle, r, this );
|
|
findTextStatic.Create( "Text", staticStyle, r, this );
|
|
findNameEdit.CreateEx( WS_EX_CLIENTEDGE, "EDIT", "", editStyle, r, this, IDC_DECLBROWSER_CHILD_FIND_NAME );
|
|
findTextEdit.CreateEx( WS_EX_CLIENTEDGE, "EDIT", "", editStyle, r, this, IDC_DECLBROWSER_CHILD_FIND_TEXT );
|
|
findButton.Create( "Find", buttonStyle, r, this, IDC_DECLBROWSER_CHILD_FIND );
|
|
loadButton.Create( "Load", buttonStyle, r, this, IDC_DECLBROWSER_CHILD_LOAD );
|
|
reloadButton.Create( "Reload", buttonStyle, r, this, IDC_DECLBROWSER_CHILD_RELOAD );
|
|
|
|
newTypeStatic.Create( "Type", staticStyle, r, this );
|
|
newNameStatic.Create( "New", staticStyle, r, this );
|
|
newFileStatic.Create( "File", staticStyle, r, this );
|
|
newTypeCombo.Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | CBS_DROPDOWNLIST | WS_VSCROLL, r, this, IDC_DECLBROWSER_CHILD_NEW_TYPE );
|
|
newNameEdit.CreateEx( WS_EX_CLIENTEDGE, "EDIT", "", editStyle, r, this, IDC_DECLBROWSER_CHILD_NEW_NAME );
|
|
newFileEdit.CreateEx( WS_EX_CLIENTEDGE, "EDIT", "", editStyle, r, this, IDC_DECLBROWSER_CHILD_NEW_FILE );
|
|
createButton.Create( "Create", buttonStyle, r, this, IDC_DECLBROWSER_CHILD_CREATE );
|
|
statusText.Create( "No declaration selected", WS_CHILD | WS_VISIBLE | SS_LEFT | SS_NOPREFIX, r, this );
|
|
|
|
declEditor.Create( this, IDC_DECLBROWSER_CHILD_EDITOR );
|
|
|
|
controlsCreated = true;
|
|
}
|
|
|
|
void DialogDeclBrowser::PopulateTypeCombo( void ) {
|
|
if ( !newTypeCombo.GetSafeHwnd() ) {
|
|
return;
|
|
}
|
|
newTypeCombo.ResetContent();
|
|
for( int i = 0; i < declManager->GetNumDeclTypes(); i++ ) {
|
|
newTypeCombo.AddString( declManager->GetDeclNameFromType( (declType_t)i ) );
|
|
}
|
|
if ( newTypeCombo.GetCount() > 0 ) {
|
|
newTypeCombo.SetCurSel( 0 );
|
|
OnTypeChanged();
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::ApplyModernFontRecursive( CWnd *wnd ) {
|
|
if ( !wnd || !wnd->GetSafeHwnd() || !modernFont.GetSafeHandle() ) {
|
|
return;
|
|
}
|
|
wnd->SetFont( &modernFont, FALSE );
|
|
CWnd *child = wnd->GetWindow( GW_CHILD );
|
|
while( child ) {
|
|
child->SetFont( &modernFont, FALSE );
|
|
child = child->GetNextWindow();
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::ApplyDarkTheme( void ) {
|
|
if ( !GetSafeHwnd() ) {
|
|
return;
|
|
}
|
|
|
|
if ( !modernFont.GetSafeHandle() ) {
|
|
LOGFONT lf;
|
|
memset( &lf, 0, sizeof( lf ) );
|
|
HDC hDC = ::GetDC( GetSafeHwnd() );
|
|
const int dpiY = GetDeviceCaps( hDC, LOGPIXELSY );
|
|
::ReleaseDC( GetSafeHwnd(), hDC );
|
|
lf.lfHeight = -MulDiv( 9, dpiY, 72 );
|
|
lf.lfWeight = FW_NORMAL;
|
|
lf.lfQuality = CLEARTYPE_QUALITY;
|
|
strncpy( lf.lfFaceName, "Segoe UI", sizeof( lf.lfFaceName ) - 1 );
|
|
modernFont.CreateFontIndirect( &lf );
|
|
}
|
|
|
|
if ( !bgBrush.GetSafeHandle() ) {
|
|
bgBrush.CreateSolidBrush( DECL_BROWSER_BG );
|
|
}
|
|
if ( !panelBrush.GetSafeHandle() ) {
|
|
panelBrush.CreateSolidBrush( DECL_BROWSER_PANEL_BG );
|
|
}
|
|
if ( !editBrush.GetSafeHandle() ) {
|
|
editBrush.CreateSolidBrush( DECL_BROWSER_FIELD_BG );
|
|
}
|
|
if ( !staticBrush.GetSafeHandle() ) {
|
|
staticBrush.CreateSolidBrush( DECL_BROWSER_BG );
|
|
}
|
|
|
|
SetFont( &modernFont, FALSE );
|
|
ApplyModernFontRecursive( this );
|
|
DeclBrowserApplyNativeDarkTheme( GetSafeHwnd() );
|
|
ModifyStyleEx( WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED );
|
|
|
|
for( HWND child = ::GetWindow( GetSafeHwnd(), GW_CHILD ); child != NULL; child = ::GetWindow( child, GW_HWNDNEXT ) ) {
|
|
DeclBrowserApplyNativeDarkTheme( child );
|
|
if ( DeclBrowserIsClass( child, "Edit" ) ) {
|
|
DeclBrowserRemoveClientEdge( child );
|
|
} else if ( DeclBrowserIsClass( child, "SysTreeView32" ) || DeclBrowserIsClass( child, "ComboBox" ) ) {
|
|
// Keep tree/combo controls native-subclass free; the tree owns its tooltip path.
|
|
DeclBrowserRemoveClientEdge( child );
|
|
}
|
|
}
|
|
|
|
if ( declTree.GetSafeHwnd() ) {
|
|
::SendMessage( declTree.GetSafeHwnd(), TVM_SETBKCOLOR, 0, (LPARAM)DECL_BROWSER_FIELD_BG );
|
|
::SendMessage( declTree.GetSafeHwnd(), TVM_SETTEXTCOLOR, 0, (LPARAM)DECL_BROWSER_TEXT );
|
|
}
|
|
Invalidate( TRUE );
|
|
}
|
|
|
|
BOOL DialogDeclBrowser::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) {
|
|
if ( pResult ) {
|
|
*pResult = 0;
|
|
}
|
|
|
|
// CPathTreeCtrl already owns its per-item tooltip forwarding. Calling
|
|
// TreeView APIs from inside the forwarded TTN_NEEDTEXT path can re-enter
|
|
// comctl32 and hang the docked inspector, so the docked browser only uses
|
|
// static control tooltips here.
|
|
if ( pNMHDR && pNMHDR->hwndFrom == declTree.GetSafeHwnd() ) {
|
|
return FALSE;
|
|
}
|
|
|
|
return DefaultOnToolTipNotify( toolTips, id, pNMHDR, pResult );
|
|
}
|
|
|
|
HBRUSH DialogDeclBrowser::OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ) {
|
|
HBRUSH hbr = CWnd::OnCtlColor( pDC, pWnd, nCtlColor );
|
|
if ( !pDC ) {
|
|
return hbr;
|
|
}
|
|
|
|
pDC->SetTextColor( DECL_BROWSER_TEXT );
|
|
switch( nCtlColor ) {
|
|
case CTLCOLOR_DLG:
|
|
pDC->SetBkColor( DECL_BROWSER_BG );
|
|
return (HBRUSH)bgBrush.GetSafeHandle();
|
|
case CTLCOLOR_STATIC:
|
|
pDC->SetBkColor( DECL_BROWSER_BG );
|
|
pDC->SetTextColor( DECL_BROWSER_MUTED_TEXT );
|
|
return (HBRUSH)staticBrush.GetSafeHandle();
|
|
case CTLCOLOR_EDIT:
|
|
case CTLCOLOR_LISTBOX:
|
|
pDC->SetBkColor( DECL_BROWSER_FIELD_BG );
|
|
pDC->SetTextColor( DECL_BROWSER_TEXT );
|
|
return (HBRUSH)editBrush.GetSafeHandle();
|
|
case CTLCOLOR_BTN:
|
|
pDC->SetBkColor( DECL_BROWSER_BG );
|
|
pDC->SetTextColor( DECL_BROWSER_TEXT );
|
|
return (HBRUSH)bgBrush.GetSafeHandle();
|
|
default:
|
|
break;
|
|
}
|
|
return hbr;
|
|
}
|
|
|
|
BOOL DialogDeclBrowser::OnEraseBkgnd( CDC* pDC ) {
|
|
CRect rc;
|
|
GetClientRect( &rc );
|
|
pDC->FillSolidRect( &rc, DECL_BROWSER_BG );
|
|
return TRUE;
|
|
}
|
|
|
|
void DialogDeclBrowser::OnPaint() {
|
|
CPaintDC dc( this );
|
|
CRect rc;
|
|
GetClientRect( &rc );
|
|
dc.FillSolidRect( &rc, DECL_BROWSER_BG );
|
|
}
|
|
|
|
void DialogDeclBrowser::OnSetFocus( CWnd *pOldWnd ) {
|
|
CWnd::OnSetFocus( pOldWnd );
|
|
if ( declTree.GetSafeHwnd() ) {
|
|
declTree.SetFocus();
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::OnDestroy() {
|
|
CWnd::OnDestroy();
|
|
}
|
|
|
|
void DialogDeclBrowser::OnSize( UINT nType, int cx, int cy ) {
|
|
CWnd::OnSize( nType, cx, cy );
|
|
LayoutBrowser( cx, cy );
|
|
}
|
|
|
|
void DialogDeclBrowser::LayoutBrowser( int cx, int cy ) {
|
|
if ( !controlsCreated || cx <= 0 || cy <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
const int margin = DECL_BROWSER_MARGIN;
|
|
const int row = DECL_BROWSER_ROW_HEIGHT;
|
|
const int buttonHeight = DECL_BROWSER_BUTTON_HEIGHT;
|
|
const int statusHeight = DECL_BROWSER_STATUS_HEIGHT;
|
|
int leftWidth = cx / 3;
|
|
if ( leftWidth < DECL_BROWSER_LEFT_MIN_WIDTH ) {
|
|
leftWidth = DECL_BROWSER_LEFT_MIN_WIDTH;
|
|
}
|
|
if ( leftWidth > DECL_BROWSER_LEFT_MAX_WIDTH ) {
|
|
leftWidth = DECL_BROWSER_LEFT_MAX_WIDTH;
|
|
}
|
|
if ( leftWidth > cx - 240 ) {
|
|
leftWidth = cx - 240;
|
|
}
|
|
if ( leftWidth < 180 ) {
|
|
leftWidth = 180;
|
|
}
|
|
|
|
const int left = margin;
|
|
const int top = margin;
|
|
const int divider = left + leftWidth + margin;
|
|
const int editorLeft = divider + margin;
|
|
const int statusTop = cy - statusHeight;
|
|
const int createHeight = row * 4 + margin * 2;
|
|
const int searchHeight = row * 3 + margin;
|
|
const int treeTop = top + searchHeight;
|
|
const int createTop = statusTop - createHeight - margin;
|
|
const int treeBottom = createTop - margin;
|
|
|
|
LockWindowUpdate();
|
|
|
|
if ( findNameStatic.GetSafeHwnd() ) {
|
|
findNameStatic.MoveWindow( left, top + 3, 42, row );
|
|
}
|
|
if ( findNameEdit.GetSafeHwnd() ) {
|
|
findNameEdit.MoveWindow( left + 46, top, leftWidth - 46, row );
|
|
}
|
|
if ( findTextStatic.GetSafeHwnd() ) {
|
|
findTextStatic.MoveWindow( left, top + row + 3, 42, row );
|
|
}
|
|
if ( findTextEdit.GetSafeHwnd() ) {
|
|
findTextEdit.MoveWindow( left + 46, top + row, leftWidth - 46, row );
|
|
}
|
|
if ( findButton.GetSafeHwnd() ) {
|
|
findButton.MoveWindow( left, top + row * 2 + margin / 2, 64, buttonHeight );
|
|
}
|
|
if ( loadButton.GetSafeHwnd() ) {
|
|
loadButton.MoveWindow( left + 68, top + row * 2 + margin / 2, 64, buttonHeight );
|
|
}
|
|
if ( reloadButton.GetSafeHwnd() ) {
|
|
reloadButton.MoveWindow( left + 136, top + row * 2 + margin / 2, 72, buttonHeight );
|
|
}
|
|
if ( declTree.GetSafeHwnd() ) {
|
|
declTree.MoveWindow( left, treeTop, leftWidth, treeBottom - treeTop );
|
|
}
|
|
if ( baseDeclTree.GetSafeHwnd() ) {
|
|
baseDeclTree.MoveWindow( 0, 0, 0, 0 );
|
|
}
|
|
|
|
if ( newTypeStatic.GetSafeHwnd() ) {
|
|
newTypeStatic.MoveWindow( left, createTop + 3, 40, row );
|
|
}
|
|
if ( newTypeCombo.GetSafeHwnd() ) {
|
|
newTypeCombo.MoveWindow( left + 46, createTop, leftWidth - 46, 300 );
|
|
}
|
|
if ( newNameStatic.GetSafeHwnd() ) {
|
|
newNameStatic.MoveWindow( left, createTop + row + 3, 40, row );
|
|
}
|
|
if ( newNameEdit.GetSafeHwnd() ) {
|
|
newNameEdit.MoveWindow( left + 46, createTop + row, leftWidth - 46, row );
|
|
}
|
|
if ( newFileStatic.GetSafeHwnd() ) {
|
|
newFileStatic.MoveWindow( left, createTop + row * 2 + 3, 40, row );
|
|
}
|
|
if ( newFileEdit.GetSafeHwnd() ) {
|
|
newFileEdit.MoveWindow( left + 46, createTop + row * 2, leftWidth - 46, row );
|
|
}
|
|
if ( createButton.GetSafeHwnd() ) {
|
|
createButton.MoveWindow( left, createTop + row * 3 + margin / 2, 82, buttonHeight );
|
|
}
|
|
|
|
if ( declEditor.GetSafeHwnd() ) {
|
|
declEditor.MoveWindow( editorLeft, top, cx - editorLeft - margin, statusTop - top - margin );
|
|
}
|
|
if ( statusText.GetSafeHwnd() ) {
|
|
statusText.MoveWindow( margin, statusTop + 2, cx - margin * 2, statusHeight - 2 );
|
|
}
|
|
|
|
UnlockWindowUpdate();
|
|
}
|
|
|
|
void DialogDeclBrowser::AddDeclTypeToTree( declType_t type, const char *root, CPathTreeCtrl &tree ) {
|
|
int i;
|
|
idList<const idDecl*> decls;
|
|
idPathTreeStack stack;
|
|
idStr rootStr, declName;
|
|
|
|
decls.SetNum( declManager->GetNumDecls( type ) );
|
|
for ( i = 0; i < decls.Num(); i++ ) {
|
|
decls[i] = declManager->DeclByIndex( type, i, false );
|
|
}
|
|
decls.Sort( idListDeclSortCompare );
|
|
|
|
rootStr = root;
|
|
rootStr += "/";
|
|
|
|
stack.PushRoot( NULL );
|
|
|
|
for ( i = 0; i < decls.Num(); i++ ) {
|
|
if ( !decls[i] ) {
|
|
continue;
|
|
}
|
|
declName = rootStr + decls[i]->GetName();
|
|
declName.BackSlashesToSlashes();
|
|
declName.Strip( ' ' );
|
|
tree.AddPathToTree( declName, GetIdFromTypeAndIndex( type, decls[i]->Index() ), stack );
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::InitBaseDeclTree( void ) {
|
|
if ( !baseDeclTree.GetSafeHwnd() ) {
|
|
return;
|
|
}
|
|
numListedDecls = 0;
|
|
baseDeclTree.DeleteAllItems();
|
|
|
|
for ( int i = 0; i < declManager->GetNumDeclTypes(); i++ ) {
|
|
AddDeclTypeToTree( (declType_t)i, declManager->GetDeclNameFromType( (declType_t)i ), baseDeclTree );
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::GetDeclName( HTREEITEM item, idStr &typeName, idStr &declName ) const {
|
|
HTREEITEM parent;
|
|
idStr itemName;
|
|
|
|
declName.Clear();
|
|
if ( !item ) {
|
|
typeName.Clear();
|
|
return;
|
|
}
|
|
for( parent = declTree.GetParentItem( item ); parent; parent = declTree.GetParentItem( parent ) ) {
|
|
itemName = declTree.GetItemText( item );
|
|
declName = itemName + "/" + declName;
|
|
item = parent;
|
|
}
|
|
declName.Strip( '/' );
|
|
typeName = declTree.GetItemText( item );
|
|
}
|
|
|
|
const idDecl *DialogDeclBrowser::GetDeclFromTreeItem( HTREEITEM item ) const {
|
|
if ( !item || !declTree.GetSafeHwnd() ) {
|
|
return NULL;
|
|
}
|
|
|
|
TVITEM tvItem;
|
|
memset( &tvItem, 0, sizeof( tvItem ) );
|
|
tvItem.mask = TVIF_PARAM | TVIF_CHILDREN;
|
|
tvItem.hItem = item;
|
|
|
|
if ( !::SendMessage( declTree.GetSafeHwnd(), TVM_GETITEM, 0, (LPARAM)&tvItem ) ) {
|
|
return NULL;
|
|
}
|
|
|
|
if ( tvItem.cChildren != 0 ) {
|
|
return NULL;
|
|
}
|
|
|
|
const int id = (int)tvItem.lParam;
|
|
declType_t type = GetTypeFromId( id );
|
|
const int index = GetIndexFromId( id );
|
|
|
|
if ( type < 0 || type >= declManager->GetNumDeclTypes() || index < 0 || index >= declManager->GetNumDecls( type ) ) {
|
|
return NULL;
|
|
}
|
|
|
|
const idDecl *decl = declManager->DeclByIndex( type, index, false );
|
|
if ( !decl || decl->GetType() != type || decl->Index() != index ) {
|
|
return NULL;
|
|
}
|
|
|
|
return decl;
|
|
}
|
|
|
|
const idDecl *DialogDeclBrowser::GetSelectedDecl( void ) const {
|
|
return GetDeclFromTreeItem( declTree.GetSelectedItem() );
|
|
}
|
|
|
|
bool DialogDeclBrowser::CompareDecl( HTREEITEM item, const char *name ) const {
|
|
if ( findNameString.Length() ) {
|
|
if ( !idStr::Filter( findNameString, name, false ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ( findTextString.Length() ) {
|
|
TVITEM tvItem;
|
|
memset( &tvItem, 0, sizeof( tvItem ) );
|
|
tvItem.mask = TVIF_PARAM | TVIF_CHILDREN;
|
|
tvItem.hItem = item;
|
|
|
|
if ( !baseDeclTree.GetSafeHwnd() || !::SendMessage( baseDeclTree.GetSafeHwnd(), TVM_GETITEM, 0, (LPARAM)&tvItem ) ) {
|
|
return false;
|
|
}
|
|
if ( tvItem.cChildren != 0 ) {
|
|
return false;
|
|
}
|
|
|
|
const int id = (int)tvItem.lParam;
|
|
declType_t type = GetTypeFromId( id );
|
|
const int index = GetIndexFromId( id );
|
|
|
|
if ( type < 0 || type >= declManager->GetNumDeclTypes() || index < 0 || index >= declManager->GetNumDecls( type ) ) {
|
|
return false;
|
|
}
|
|
|
|
const idDecl *decl = declManager->DeclByIndex( type, index, false );
|
|
if ( !decl ) {
|
|
return false;
|
|
}
|
|
char *declText = (char *)_alloca( ( decl->GetTextLength() + 1 ) * sizeof( char ) );
|
|
decl->GetText( declText );
|
|
if ( idStr::FindText( declText, findTextString, false ) == -1 ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DeclBrowserCompareDecl( void *data, HTREEITEM item, const char *name ) {
|
|
return reinterpret_cast<DialogDeclBrowser *>( data )->CompareDecl( item, name );
|
|
}
|
|
|
|
void DialogDeclBrowser::OnBnClickedFind() {
|
|
CString windowText;
|
|
|
|
findNameEdit.GetWindowText( windowText );
|
|
findNameString = windowText;
|
|
findNameString.Strip( ' ' );
|
|
if ( !findNameString.Length() ) {
|
|
findNameString = "*";
|
|
}
|
|
|
|
findTextEdit.GetWindowText( windowText );
|
|
findTextString = windowText;
|
|
findTextString.Strip( ' ' );
|
|
|
|
reloadingTree = true;
|
|
numListedDecls = baseDeclTree.SearchTree( DeclBrowserCompareDecl, this, declTree );
|
|
reloadingTree = false;
|
|
SetBrowserStatus( va( "%d decls listed", numListedDecls ) );
|
|
}
|
|
|
|
void DialogDeclBrowser::OnBnClickedLoad() {
|
|
LoadSelectedDecl();
|
|
}
|
|
|
|
void DialogDeclBrowser::LoadSelectedDecl( void ) {
|
|
const idDecl *selected = GetSelectedDecl();
|
|
if ( !selected ) {
|
|
declEditor.ClearDecl();
|
|
SetBrowserStatus( va( "%d decls listed", numListedDecls ) );
|
|
return;
|
|
}
|
|
|
|
idDecl *editable = const_cast<idDecl *>( selected );
|
|
declEditor.LoadDecl( editable );
|
|
SetCreateDefaultsFromSelection( selected );
|
|
SetBrowserStatus( va( "%d decls listed - %s/%s, %s line %d", numListedDecls, declManager->GetDeclNameFromType( selected->GetType() ), selected->GetName(), selected->GetFileName(), selected->GetLineNum() ) );
|
|
}
|
|
|
|
void DialogDeclBrowser::OnTreeSelChanged( NMHDR* pNMHDR, LRESULT* pResult ) {
|
|
if ( !reloadingTree ) {
|
|
const idDecl *decl = GetSelectedDecl();
|
|
if ( decl ) {
|
|
findNameEdit.SetWindowText( va( "%s/%s", declManager->GetDeclNameFromType( decl->GetType() ), decl->GetName() ) );
|
|
LoadSelectedDecl();
|
|
} else {
|
|
HTREEITEM item = declTree.GetSelectedItem();
|
|
idStr typeName, declName;
|
|
GetDeclName( item, typeName, declName );
|
|
if ( typeName.Length() ) {
|
|
findNameEdit.SetWindowText( va( "%s/%s*", typeName.c_str(), declName.c_str() ) );
|
|
}
|
|
SetBrowserStatus( va( "%d decls listed", numListedDecls ) );
|
|
}
|
|
}
|
|
*pResult = 0;
|
|
}
|
|
|
|
void DialogDeclBrowser::OnTreeDblclk( NMHDR *pNMHDR, LRESULT *pResult ) {
|
|
LoadSelectedDecl();
|
|
FocusDeclEditor();
|
|
*pResult = 1;
|
|
}
|
|
|
|
void DialogDeclBrowser::OnBnClickedReload() {
|
|
declManager->Reload( false );
|
|
ReloadDeclarations();
|
|
}
|
|
|
|
void DialogDeclBrowser::ReloadDeclarations( void ) {
|
|
idStr selectedType;
|
|
idStr selectedName;
|
|
const idDecl *selected = GetSelectedDecl();
|
|
if ( selected ) {
|
|
selectedType = declManager->GetDeclNameFromType( selected->GetType() );
|
|
selectedName = selected->GetName();
|
|
}
|
|
|
|
InitBaseDeclTree();
|
|
OnBnClickedFind();
|
|
|
|
if ( selectedType.Length() && selectedName.Length() ) {
|
|
declType_t type = declManager->GetDeclTypeFromName( selectedType );
|
|
SelectDeclInTree( type, selectedName );
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::SelectDeclInTree( declType_t type, const char *name ) {
|
|
if ( !name || !name[0] || type < 0 || type >= declManager->GetNumDeclTypes() ) {
|
|
return;
|
|
}
|
|
idStr path = declManager->GetDeclNameFromType( type );
|
|
path += "/";
|
|
path += name;
|
|
HTREEITEM item = declTree.FindItem( path );
|
|
if ( item ) {
|
|
declTree.SelectItem( item );
|
|
declTree.EnsureVisible( item );
|
|
LoadSelectedDecl();
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::FocusDeclEditor( void ) {
|
|
if ( declEditor.GetSafeHwnd() ) {
|
|
declEditor.SetFocus();
|
|
}
|
|
}
|
|
|
|
declType_t DialogDeclBrowser::GetSelectedNewType( void ) {
|
|
CString typeName;
|
|
int sel = newTypeCombo.GetCurSel();
|
|
if ( sel != CB_ERR ) {
|
|
newTypeCombo.GetLBText( sel, typeName );
|
|
} else {
|
|
newTypeCombo.GetWindowText( typeName );
|
|
}
|
|
return declManager->GetDeclTypeFromName( typeName );
|
|
}
|
|
|
|
void DialogDeclBrowser::GetDefaultFileForType( declType_t type, idStr &fileName ) const {
|
|
switch( type ) {
|
|
case DECL_TABLE:
|
|
case DECL_MATERIAL:
|
|
fileName = "materials/generated.mtr";
|
|
break;
|
|
case DECL_SKIN:
|
|
fileName = "skins/generated.skin";
|
|
break;
|
|
case DECL_SOUND:
|
|
fileName = "sound/generated.sndshd";
|
|
break;
|
|
case DECL_ENTITYDEF:
|
|
fileName = "def/generated.def";
|
|
break;
|
|
case DECL_MODELDEF:
|
|
fileName = "def/generated.def";
|
|
break;
|
|
case DECL_FX:
|
|
fileName = "fx/generated.fx";
|
|
break;
|
|
case DECL_PARTICLE:
|
|
fileName = "particles/generated.prt";
|
|
break;
|
|
case DECL_AF:
|
|
fileName = "af/generated.af";
|
|
break;
|
|
default:
|
|
fileName = "def/generated.decl";
|
|
break;
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::SetCreateDefaultsFromSelection( const idDecl *decl ) {
|
|
if ( !decl ) {
|
|
return;
|
|
}
|
|
if ( newTypeCombo.GetSafeHwnd() ) {
|
|
CString typeName = declManager->GetDeclNameFromType( decl->GetType() );
|
|
int index = newTypeCombo.FindStringExact( -1, typeName );
|
|
if ( index != CB_ERR ) {
|
|
newTypeCombo.SetCurSel( index );
|
|
}
|
|
}
|
|
if ( newFileEdit.GetSafeHwnd() ) {
|
|
newFileEdit.SetWindowText( decl->GetFileName() );
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::OnTypeChanged() {
|
|
declType_t type = GetSelectedNewType();
|
|
idStr fileName;
|
|
GetDefaultFileForType( type, fileName );
|
|
if ( newFileEdit.GetSafeHwnd() ) {
|
|
newFileEdit.SetWindowText( fileName.c_str() );
|
|
}
|
|
}
|
|
|
|
void DialogDeclBrowser::OnBnClickedCreate() {
|
|
CString nameText;
|
|
CString fileText;
|
|
newNameEdit.GetWindowText( nameText );
|
|
newFileEdit.GetWindowText( fileText );
|
|
nameText.TrimLeft();
|
|
nameText.TrimRight();
|
|
fileText.TrimLeft();
|
|
fileText.TrimRight();
|
|
|
|
if ( nameText.IsEmpty() ) {
|
|
MessageBox( "Enter a declaration name.", "Create declaration", MB_OK | MB_ICONINFORMATION );
|
|
return;
|
|
}
|
|
|
|
declType_t type = GetSelectedNewType();
|
|
if ( type < 0 || type >= declManager->GetNumDeclTypes() ) {
|
|
MessageBox( "Select a valid declaration type.", "Create declaration", MB_OK | MB_ICONERROR );
|
|
return;
|
|
}
|
|
|
|
idStr fileName;
|
|
if ( fileText.IsEmpty() ) {
|
|
GetDefaultFileForType( type, fileName );
|
|
} else {
|
|
fileName = fileText;
|
|
}
|
|
|
|
idStr path = declManager->GetDeclNameFromType( type );
|
|
path += "/";
|
|
path += (LPCTSTR)nameText;
|
|
if ( baseDeclTree.FindItem( path ) ) {
|
|
MessageBox( "Declaration already exists.", "Create declaration", MB_OK | MB_ICONERROR );
|
|
return;
|
|
}
|
|
|
|
idDecl *newDecl = declManager->CreateNewDecl( type, nameText, fileName, true );
|
|
if ( !newDecl ) {
|
|
MessageBox( "The declaration manager could not create the declaration.", "Create declaration", MB_OK | MB_ICONERROR );
|
|
return;
|
|
}
|
|
|
|
findNameEdit.SetWindowText( va( "%s/%s", declManager->GetDeclNameFromType( type ), newDecl->GetName() ) );
|
|
findTextEdit.SetWindowText( "" );
|
|
InitBaseDeclTree();
|
|
OnBnClickedFind();
|
|
SelectDeclInTree( type, newDecl->GetName() );
|
|
FocusDeclEditor();
|
|
}
|
|
|
|
void DialogDeclBrowser::SetBrowserStatus( const char *text ) {
|
|
if ( statusText.GetSafeHwnd() ) {
|
|
statusText.SetWindowText( text ? text : "" );
|
|
}
|
|
}
|
|
|
|
void DeclBrowserInit( const idDict *spawnArgs ) {
|
|
if ( renderSystem->IsFullScreen() ) {
|
|
common->Printf( "Cannot run the declaration editor in fullscreen mode.\n"
|
|
"Set r_fullscreen to 0 and vid_restart.\n" );
|
|
return;
|
|
}
|
|
|
|
InitAfx();
|
|
idKeyInput::ClearStates();
|
|
|
|
if ( g_Inspectors && g_Inspectors->GetSafeHwnd() ) {
|
|
g_Inspectors->ShowWindow( SW_SHOW );
|
|
g_Inspectors->SetMode( W_DECLS );
|
|
g_Inspectors->GetDeclBrowser().SetFocus();
|
|
return;
|
|
}
|
|
|
|
common->Printf( "Declaration editor is hosted in the Inspector Decls tab. Open the Inspector window first.\n" );
|
|
}
|
|
|
|
void DeclBrowserRun( void ) {
|
|
// No private message pump is needed. The declaration browser/editor now
|
|
// lives inside the Inspector dialog and uses Radiant's normal UI pump.
|
|
}
|
|
|
|
void DeclBrowserShutdown( void ) {
|
|
// Owned by CInspectorDialog.
|
|
}
|
|
|
|
void DeclBrowserReloadDeclarations( void ) {
|
|
if ( g_Inspectors && g_Inspectors->GetSafeHwnd() ) {
|
|
g_Inspectors->GetDeclBrowser().ReloadDeclarations();
|
|
}
|
|
}
|