Team Fortress 2 Source Code as on 22/4/2020
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.
 
 
 
 
 
 

500 lines
12 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "dme_controls/AttributeTextEntry.h"
#include "tier1/KeyValues.h"
#include "vgui_controls/Menu.h"
#include "datamodel/dmelement.h"
#include "dme_controls/AttributeTextPanel.h"
#include "vgui/MouseCode.h"
#include "vgui/KeyCode.h"
#include "vgui/IInput.h"
#include "movieobjects/dmeeditortypedictionary.h"
#include "dme_controls/inotifyui.h"
using namespace vgui;
// ----------------------------------------------------------------------------
// CAttributeTextEntry
CAttributeTextEntry::CAttributeTextEntry( Panel *parent, const char *panelName ) :
BaseClass( parent, panelName ),
m_bValueStored( false ),
m_flOriginalValue( 0.0f )
{
SetDragEnabled( true );
SetDropEnabled( true, 0.5f );
m_szOriginalText[ 0 ] = 0;
AddActionSignalTarget( this );
}
void CAttributeTextEntry::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetBorder(NULL);
//HFont font = pScheme->GetFont( "DmePropertyVerySmall", IsProportional() );
//SetFont(font);
}
//-----------------------------------------------------------------------------
// Returns the parent panel
//-----------------------------------------------------------------------------
inline CAttributeTextPanel *CAttributeTextEntry::GetParentAttributePanel()
{
return static_cast< CAttributeTextPanel * >( GetParent() );
}
//-----------------------------------------------------------------------------
// Drag + drop
//-----------------------------------------------------------------------------
bool CAttributeTextEntry::GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist )
{
menu->AddMenuItem( "Drop as Text", "#BxDropText", "droptext", this );
return true;
}
bool CAttributeTextEntry::IsDroppable( CUtlVector< KeyValues * >& msglist )
{
if ( !IsEnabled() )
return false;
if ( msglist.Count() != 1 )
return false;
KeyValues *msg = msglist[ 0 ];
Panel *draggedPanel = ( Panel * )msg->GetPtr( "panel", NULL );
if ( draggedPanel == GetParent() )
return false;
CAttributeTextPanel *pPanel = GetParentAttributePanel();
if ( !pPanel )
return false;
// If a specific text type is specified, then filter if it doesn't match
const char *pTextType = pPanel->GetTextType();
if ( pTextType[0] )
{
const char *pMsgTextType = msg->GetString( "texttype" );
if ( Q_stricmp( pTextType, pMsgTextType ) )
return false;
}
DmAttributeType_t t = pPanel->GetAttributeType();
switch ( t )
{
default:
break;
case AT_ELEMENT:
{
CDmElement *ptr = reinterpret_cast< CDmElement * >( g_pDataModel->GetElement( DmElementHandle_t( msg->GetInt( "root" ) ) ) );
if ( ptr )
{
return true;
}
return false;
}
break;
case AT_ELEMENT_ARRAY:
return false;
}
return true;
}
void CAttributeTextEntry::OnPanelDropped( CUtlVector< KeyValues * >& msglist )
{
if ( msglist.Count() != 1 )
return;
KeyValues *data = msglist[ 0 ];
Panel *draggedPanel = ( Panel * )data->GetPtr( "panel", NULL );
if ( draggedPanel == GetParent() )
return;
CAttributeTextPanel *pPanel = GetParentAttributePanel();
if ( !pPanel )
return;
// If a specific text type is specified, then filter if it doesn't match
const char *pTextType = pPanel->GetTextType();
if ( pTextType[0] )
{
const char *pMsgTextType = data->GetString( "texttype" );
if ( Q_stricmp( pTextType, pMsgTextType ) )
return;
}
const char *cmd = data->GetString( "command" );
if ( !Q_stricmp( cmd, "droptext" ) || !Q_stricmp( cmd, "default" ) )
{
DmAttributeType_t t = pPanel->GetAttributeType();
switch ( t )
{
default:
{
pPanel->SetDirty( true );
SetText( data->GetString( "text" ) );
if ( pPanel->IsAutoApply() )
{
pPanel->Apply();
}
}
break;
case AT_ELEMENT:
{
CDmElement *ptr = reinterpret_cast< CDmElement * >( g_pDataModel->GetElement( DmElementHandle_t( data->GetInt( "root" ) ) ) );
if ( !ptr )
{
break;
}
pPanel->SetDirty( true );
SetText( data->GetString( "text" ) );
if ( pPanel->IsAutoApply() )
{
pPanel->Apply();
}
}
break;
case AT_ELEMENT_ARRAY:
Assert( 0 );
break;
}
}
StoreInitialValue( true );
}
//-----------------------------------------------------------------------------
// Enter causes changes to be applied
//-----------------------------------------------------------------------------
void CAttributeTextEntry::OnKeyCodeTyped(KeyCode code)
{
bool bCtrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
switch ( code )
{
case KEY_ENTER:
{
CAttributeTextPanel *pPanel = GetParentAttributePanel();
if ( !pPanel->IsAutoApply() )
{
pPanel->Apply();
StoreInitialValue( true );
}
else
{
WriteValueToAttribute();
}
}
break;
// Override the base class undo feature, it behaves poorly when typing in data
case KEY_Z:
if ( bCtrl )
{
WriteInitialValueToAttribute( );
break;
}
// NOTE: Fall through to default if it's not Ctrl-Z
default:
BaseClass::OnKeyCodeTyped(code);
break;
}
}
void CAttributeTextEntry::OnTextChanged( KeyValues *data )
{
m_bValueStored = true;
}
//-----------------------------------------------------------------------------
// We'll only create an "undo" record if the values differ upon focus change
//-----------------------------------------------------------------------------
void CAttributeTextEntry::StoreInitialValue( bool bForce )
{
// Already storing value???
if ( m_bValueStored && !bForce )
return;
m_bValueStored = true;
CAttributeTextPanel *pPanel = GetParentAttributePanel();
Assert( pPanel );
switch ( pPanel->GetAttributeType() )
{
case AT_FLOAT:
m_flOriginalValue = pPanel->GetAttributeValue<float>( );
break;
case AT_INT:
m_nOriginalValue = pPanel->GetAttributeValue<int>( );
break;
case AT_BOOL:
m_bOriginalValue = pPanel->GetAttributeValue<bool>( );
break;
default:
GetText( m_szOriginalText, sizeof( m_szOriginalText ) );
break;
}
}
//-----------------------------------------------------------------------------
// Performs undo
//-----------------------------------------------------------------------------
void CAttributeTextEntry::WriteInitialValueToAttribute( )
{
// Already storing value???
if ( !m_bValueStored )
return;
CDisableUndoScopeGuard guard;
CAttributeTextPanel *pPanel = GetParentAttributePanel();
Assert( pPanel );
switch ( pPanel->GetAttributeType() )
{
case AT_FLOAT:
pPanel->SetAttributeValue( m_flOriginalValue );
break;
case AT_INT:
pPanel->SetAttributeValue( m_nOriginalValue );
break;
case AT_BOOL:
pPanel->SetAttributeValue<bool>( m_bOriginalValue );
break;
default:
pPanel->SetAttributeValueFromString( m_szOriginalText );
break;
}
pPanel->SetDirty( false );
pPanel->Refresh();
}
//-----------------------------------------------------------------------------
// We'll only create an "undo" record if the values differ upon focus change
//-----------------------------------------------------------------------------
void CAttributeTextEntry::OnSetFocus()
{
BaseClass::OnSetFocus();
StoreInitialValue();
}
//-----------------------------------------------------------------------------
// Called when focus is lost
//-----------------------------------------------------------------------------
template<class T>
void CAttributeTextEntry::ApplyMouseWheel( T newValue, T originalValue )
{
CAttributeTextPanel *pPanel = GetParentAttributePanel();
// Kind of an evil hack, but "undo" copies the "old value" off for doing undo, and that value is the new value because
// we haven't been tracking undo while manipulating this. So we'll turn off undo and set the value to the original value.
// In effect, all of the wheeling will drop out and it'll look just like we started at the original value and ended up at the
// final value...
{
CDisableUndoScopeGuard guard;
pPanel->SetAttributeValue( originalValue );
}
if ( pPanel->IsAutoApply() )
{
pPanel->Apply();
}
else
{
CElementTreeUndoScopeGuard guard( 0, pPanel->GetNotify(), "Set Attribute Value", "Set Attribute Value" );
pPanel->SetAttributeValue( newValue );
}
}
void CAttributeTextEntry::WriteValueToAttribute()
{
if ( !m_bValueStored )
return;
m_bValueStored = false;
char newText[ MAX_TEXT_LENGTH ];
GetText( newText, sizeof( newText ) );
CAttributeTextPanel *pPanel = GetParentAttributePanel();
Assert( pPanel );
switch (pPanel->GetAttributeType() )
{
case AT_FLOAT:
ApplyMouseWheel( (float)atof(newText), m_flOriginalValue );
break;
case AT_INT:
ApplyMouseWheel( atoi(newText), m_nOriginalValue );
break;
case AT_BOOL:
ApplyMouseWheel( atoi(newText) != 0, m_bOriginalValue );
break;
default:
if ( Q_strcmp( newText, m_szOriginalText ) )
{
pPanel->SetDirty( true );
if ( pPanel->IsAutoApply() )
{
pPanel->Apply();
StoreInitialValue( true );
}
}
else
{
pPanel->SetDirty( false );
}
break;
}
}
//-----------------------------------------------------------------------------
// Called when focus is lost
//-----------------------------------------------------------------------------
void CAttributeTextEntry::OnKillFocus()
{
BaseClass::OnKillFocus();
WriteValueToAttribute();
StoreInitialValue();
}
void CAttributeTextEntry::OnMouseWheeled( int delta )
{
// Must have *keyboard* focus for it to work
if ( !HasFocus() )
{
// Otherwise, let the base class scroll up + down
BaseClass::OnMouseWheeled( delta );
return;
}
CAttributeTextPanel *pPanel = GetParentAttributePanel();
if ( pPanel->GetDirty() )
{
if ( pPanel->IsAutoApply() )
{
pPanel->Apply();
StoreInitialValue( true );
}
else
{
// FIXME: Make this work for non-auto-apply panels
}
}
switch ( pPanel->GetAttributeType() )
{
case AT_FLOAT:
{
float deltaFactor;
if ( input()->IsKeyDown(KEY_LSHIFT) )
{
deltaFactor = ((float)delta) * 10.0f;
}
else if ( input()->IsKeyDown(KEY_LCONTROL) )
{
deltaFactor = ((float)delta) / 100.0;
}
else
{
deltaFactor = ((float)delta) / 10.0;
}
float val = pPanel->GetAttributeValue<float>() + deltaFactor;
if ( input()->IsKeyDown(KEY_LALT) )
{
//val = clamp(val, 0.0, 1.0);
val = (val > 1) ? 1 : ((val < 0) ? 0 : val);
}
{
// Note, these calls to Set won't create Undo Records,
// since we'll check the value in SetFocus/KillFocus so that we
// don't gum up the undo system with hundreds of records...
CDisableUndoScopeGuard guard;
pPanel->SetAttributeValue( val );
}
}
break;
case AT_INT:
{
if ( input()->IsKeyDown(KEY_LSHIFT) )
{
delta *= 10;
}
int val = pPanel->GetAttributeValue<int>() + delta;
{
// Note, these calls to Set won't create Undo Records,
// since we'll check the value in SetFocus/KillFocus so that we
// don't gum up the undo system with hundreds of records...
CDisableUndoScopeGuard guard;
pPanel->SetAttributeValue( val );
}
}
break;
case AT_BOOL:
{
bool val = !pPanel->GetAttributeValue<bool>();
{
// Note, these calls to Set won't create Undo Records,
// since we'll check the value in SetFocus/KillFocus so that we
// don't gum up the undo system with hundreds of records...
CDisableUndoScopeGuard guard;
pPanel->SetAttributeValue( val );
}
}
break;
default:
return;
}
pPanel->Refresh();
if ( pPanel->IsAutoApply() )
{
// NOTE: Don't call Apply since that generates an undo record
CElementTreeNotifyScopeGuard notify( "CAttributeTextEntry::OnMouseWheeled", NOTIFY_CHANGE_ATTRIBUTE_VALUE | NOTIFY_SETDIRTYFLAG, pPanel->GetNotify() );
}
else
{
pPanel->SetDirty( true );
}
//SetDirty(true);
//UpdateTime( m_flLastMouseTime );
//UpdateZoom( -10.0f * delta );
//UpdateTransform();
}
// ----------------------------------------------------------------------------