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.
1082 lines
31 KiB
1082 lines
31 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Basic button control
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include <stdio.h>
|
|
#include <utlsymbol.h>
|
|
|
|
#include <vgui/IBorder.h>
|
|
#include <vgui/IInput.h>
|
|
#include <vgui/IScheme.h>
|
|
#include <vgui/ISurface.h>
|
|
#include <vgui/ISystem.h>
|
|
#include <vgui/IVGui.h>
|
|
#include <vgui/MouseCode.h>
|
|
#include <vgui/KeyCode.h>
|
|
#include <keyvalues.h>
|
|
|
|
#include <vgui_controls/Button.h>
|
|
#include <vgui_controls/FocusNavGroup.h>
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include <tier0/memdbgon.h>
|
|
|
|
using namespace vgui;
|
|
|
|
// DMX serializer fields.
|
|
BEGIN_DMXELEMENT_UNPACK_NAMESPACE_SIMPLE( vgui, Button )
|
|
DMXELEMENT_UNPACK_FIELD( "default foreground color", "255 255 255 255", Color, _defaultFgColor )
|
|
END_DMXELEMENT_UNPACK_NAMESPACE( vgui, Button, s_pUnpackParams )
|
|
|
|
|
|
// global list of all the names of all the sounds played by buttons
|
|
CUtlSymbolTable g_ButtonSoundNames;
|
|
|
|
DECLARE_BUILD_FACTORY_DEFAULT_TEXT( Button, Button );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Constructor
|
|
//-----------------------------------------------------------------------------
|
|
Button::Button(Panel *parent, const char *panelName, const char *text, Panel *pActionSignalTarget, const char *pCmd ) : Label(parent, panelName, text)
|
|
{
|
|
Init();
|
|
if ( pActionSignalTarget && pCmd )
|
|
{
|
|
AddActionSignalTarget( pActionSignalTarget );
|
|
SetCommand( pCmd );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Constructor
|
|
//-----------------------------------------------------------------------------
|
|
Button::Button(Panel *parent, const char *panelName, const wchar_t *wszText, Panel *pActionSignalTarget, const char *pCmd ) : Label(parent, panelName, wszText)
|
|
{
|
|
Init();
|
|
if ( pActionSignalTarget && pCmd )
|
|
{
|
|
AddActionSignalTarget( pActionSignalTarget );
|
|
SetCommand( pCmd );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::Init()
|
|
{
|
|
_buttonFlags.SetFlag( USE_CAPTURE_MOUSE | BUTTON_BORDER_ENABLED );
|
|
|
|
_mouseClickMask = 0;
|
|
_actionMessage = NULL;
|
|
_defaultBorder = NULL;
|
|
_depressedBorder = NULL;
|
|
_keyFocusBorder = NULL;
|
|
m_bSelectionStateSaved = false;
|
|
m_sArmedSoundName = UTL_INVAL_SYMBOL;
|
|
m_sDepressedSoundName = UTL_INVAL_SYMBOL;
|
|
m_sReleasedSoundName = UTL_INVAL_SYMBOL;
|
|
SetTextInset(6, 0);
|
|
SetMouseClickEnabled( MOUSE_LEFT, true );
|
|
SetButtonActivationType(ACTIVATE_ONPRESSEDANDRELEASED);
|
|
|
|
// labels have this off by default, but we need it on
|
|
SetPaintBackgroundEnabled( true );
|
|
|
|
_paint = true;
|
|
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _defaultFgColor, "defaultFgColor_override" );
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _defaultBgColor, "defaultBgColor_override" );
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _armedFgColor, "armedFgColor_override" );
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _armedBgColor, "armedBgColor_override" );
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _depressedFgColor, "depressedFgColor_override" );
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _depressedBgColor, "depressedBgColor_override" );
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _keyboardFocusColor, "keyboardFocusColor_override" );
|
|
REGISTER_COLOR_AS_OVERRIDABLE( _blinkFgColor, "blinkFgColor_override" );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Destructor
|
|
//-----------------------------------------------------------------------------
|
|
Button::~Button()
|
|
{
|
|
if (_actionMessage)
|
|
{
|
|
_actionMessage->deleteThis();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetButtonActivationType(ActivationType_t activationType)
|
|
{
|
|
_activationType = activationType;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set button border attribute enabled.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetButtonBorderEnabled( bool state )
|
|
{
|
|
if ( state != _buttonFlags.IsFlagSet( BUTTON_BORDER_ENABLED ) )
|
|
{
|
|
_buttonFlags.SetFlag( BUTTON_BORDER_ENABLED, state );
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set button selected state.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetSelected( bool state )
|
|
{
|
|
if ( _buttonFlags.IsFlagSet( SELECTED ) != state )
|
|
{
|
|
_buttonFlags.SetFlag( SELECTED, state );
|
|
RecalculateDepressedState();
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
void Button::SetBlink( bool state )
|
|
{
|
|
if ( _buttonFlags.IsFlagSet( BLINK ) != state )
|
|
{
|
|
_buttonFlags.SetFlag( BLINK, state );
|
|
RecalculateDepressedState();
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set button force depressed state.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::ForceDepressed(bool state)
|
|
{
|
|
if ( _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) != state )
|
|
{
|
|
_buttonFlags.SetFlag( FORCE_DEPRESSED, state );
|
|
RecalculateDepressedState();
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set button depressed state with respect to the force depressed state.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::RecalculateDepressedState( void )
|
|
{
|
|
bool newState;
|
|
if (!IsEnabled())
|
|
{
|
|
newState = false;
|
|
}
|
|
else
|
|
{
|
|
newState = _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) ? true : (_buttonFlags.IsFlagSet(ARMED) && _buttonFlags.IsFlagSet( SELECTED ) );
|
|
}
|
|
|
|
_buttonFlags.SetFlag( DEPRESSED, newState );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Sets whether or not the button captures all mouse input when depressed
|
|
// Defaults to true
|
|
// Should be set to false for things like menu items where there is a higher-level mouse capture
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetUseCaptureMouse( bool state )
|
|
{
|
|
_buttonFlags.SetFlag( USE_CAPTURE_MOUSE, state );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Check if mouse capture is enabled.
|
|
// Output : Returns true on success, false on failure.
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::IsUseCaptureMouseEnabled( void )
|
|
{
|
|
return _buttonFlags.IsFlagSet( USE_CAPTURE_MOUSE );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set armed state.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetArmed(bool state)
|
|
{
|
|
if ( _buttonFlags.IsFlagSet( ARMED ) != state )
|
|
{
|
|
_buttonFlags.SetFlag( ARMED, state );
|
|
RecalculateDepressedState();
|
|
InvalidateLayout(false);
|
|
|
|
// play any sounds specified
|
|
if (state && m_sArmedSoundName != UTL_INVAL_SYMBOL)
|
|
{
|
|
surface()->PlaySound(g_ButtonSoundNames.String(m_sArmedSoundName));
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Check armed state
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::IsArmed()
|
|
{
|
|
return _buttonFlags.IsFlagSet( ARMED );
|
|
}
|
|
|
|
|
|
KeyValues *Button::GetActionMessage()
|
|
{
|
|
return _actionMessage->MakeCopy();
|
|
}
|
|
|
|
void Button::PlayButtonReleasedSound()
|
|
{
|
|
// check for playing a transition sound
|
|
if ( m_sReleasedSoundName != UTL_INVAL_SYMBOL )
|
|
{
|
|
surface()->PlaySound( g_ButtonSoundNames.String( m_sReleasedSoundName ) );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Activate a button click.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::DoClick()
|
|
{
|
|
SetSelected(true);
|
|
FireActionSignal();
|
|
PlayButtonReleasedSound();
|
|
SetSelected(false);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Check selected state
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::IsSelected()
|
|
{
|
|
return _buttonFlags.IsFlagSet( SELECTED );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Check depressed state
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::IsDepressed()
|
|
{
|
|
return _buttonFlags.IsFlagSet( DEPRESSED );
|
|
}
|
|
|
|
bool Button::IsBlinking( void )
|
|
{
|
|
return _buttonFlags.IsFlagSet( BLINK );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Drawing focus box?
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::IsDrawingFocusBox()
|
|
{
|
|
return _buttonFlags.IsFlagSet( DRAW_FOCUS_BOX );
|
|
}
|
|
|
|
void Button::DrawFocusBox( bool bEnable )
|
|
{
|
|
_buttonFlags.SetFlag( DRAW_FOCUS_BOX, bEnable );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::NavigateTo()
|
|
{
|
|
BaseClass::NavigateTo();
|
|
|
|
SetArmed( true );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::NavigateFrom()
|
|
{
|
|
BaseClass::NavigateFrom();
|
|
|
|
SetArmed( false );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Paint button on screen
|
|
//-----------------------------------------------------------------------------
|
|
void Button::Paint(void)
|
|
{
|
|
if ( !ShouldPaint() )
|
|
return;
|
|
|
|
BaseClass::Paint();
|
|
|
|
if ( HasFocus() && IsEnabled() && IsDrawingFocusBox() )
|
|
{
|
|
int x0, y0, x1, y1;
|
|
int wide, tall;
|
|
GetSize(wide, tall);
|
|
x0 = 3, y0 = 3, x1 = wide - 4 , y1 = tall - 2;
|
|
DrawFocusBorder(x0, y0, x1, y1);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Perform graphical layout of button.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::PerformLayout()
|
|
{
|
|
// reset our border
|
|
SetBorder( GetBorder(_buttonFlags.IsFlagSet( DEPRESSED ), _buttonFlags.IsFlagSet( ARMED ), _buttonFlags.IsFlagSet( SELECTED ), HasFocus() ) );
|
|
|
|
// set our color
|
|
SetFgColor(GetButtonFgColor());
|
|
SetBgColor(GetButtonBgColor());
|
|
|
|
BaseClass::PerformLayout();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Get button foreground color
|
|
// Output : Color
|
|
//-----------------------------------------------------------------------------
|
|
Color Button::GetButtonFgColor()
|
|
{
|
|
if ( !_buttonFlags.IsFlagSet( BLINK ) )
|
|
{
|
|
if (_buttonFlags.IsFlagSet( DEPRESSED ))
|
|
return _depressedFgColor;
|
|
if (_buttonFlags.IsFlagSet( ARMED ))
|
|
return _armedFgColor;
|
|
return _defaultFgColor;
|
|
}
|
|
|
|
Color cBlendedColor;
|
|
|
|
if (_buttonFlags.IsFlagSet( DEPRESSED ))
|
|
cBlendedColor = _depressedFgColor;
|
|
else if (_buttonFlags.IsFlagSet( ARMED ))
|
|
cBlendedColor = _armedFgColor;
|
|
else
|
|
cBlendedColor = _defaultFgColor;
|
|
|
|
float fBlink = ( sinf( system()->GetTimeMillis() * 0.01f ) + 1.0f ) * 0.5f;
|
|
|
|
if ( _buttonFlags.IsFlagSet( BLINK ) )
|
|
{
|
|
cBlendedColor[ 0 ] = (float)cBlendedColor[ 0 ] * fBlink + (float)_blinkFgColor[ 0 ] * ( 1.0f - fBlink );
|
|
cBlendedColor[ 1 ] = (float)cBlendedColor[ 1 ] * fBlink + (float)_blinkFgColor[ 1 ] * ( 1.0f - fBlink );
|
|
cBlendedColor[ 2 ] = (float)cBlendedColor[ 2 ] * fBlink + (float)_blinkFgColor[ 2 ] * ( 1.0f - fBlink );
|
|
cBlendedColor[ 3 ] = (float)cBlendedColor[ 3 ] * fBlink + (float)_blinkFgColor[ 3 ] * ( 1.0f - fBlink );
|
|
}
|
|
|
|
return cBlendedColor;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Get button background color
|
|
//-----------------------------------------------------------------------------
|
|
Color Button::GetButtonBgColor()
|
|
{
|
|
if (_buttonFlags.IsFlagSet( DEPRESSED ))
|
|
return _depressedBgColor;
|
|
if (_buttonFlags.IsFlagSet( ARMED ))
|
|
return _armedBgColor;
|
|
return _defaultBgColor;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Called when key focus is received
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnSetFocus()
|
|
{
|
|
InvalidateLayout(false);
|
|
BaseClass::OnSetFocus();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Respond when focus is killed
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnKillFocus()
|
|
{
|
|
InvalidateLayout(false);
|
|
BaseClass::OnKillFocus();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::ApplySchemeSettings(IScheme *pScheme)
|
|
{
|
|
BaseClass::ApplySchemeSettings(pScheme);
|
|
|
|
// get the borders we need
|
|
_defaultBorder = pScheme->GetBorder("ButtonBorder");
|
|
_depressedBorder = pScheme->GetBorder("ButtonDepressedBorder");
|
|
_keyFocusBorder = pScheme->GetBorder("ButtonKeyFocusBorder");
|
|
|
|
_defaultFgColor = GetSchemeColor("Button.TextColor", Color(255, 255, 255, 255), pScheme);
|
|
_defaultBgColor = GetSchemeColor("Button.BgColor", Color(0, 0, 0, 255), pScheme);
|
|
|
|
_armedFgColor = GetSchemeColor("Button.ArmedTextColor", _defaultFgColor, pScheme);
|
|
_armedBgColor = GetSchemeColor("Button.ArmedBgColor", _defaultBgColor, pScheme);
|
|
|
|
_depressedFgColor = GetSchemeColor("Button.DepressedTextColor", _defaultFgColor, pScheme);
|
|
_depressedBgColor = GetSchemeColor("Button.DepressedBgColor", _defaultBgColor, pScheme);
|
|
_keyboardFocusColor = GetSchemeColor("Button.FocusBorderColor", Color(0,0,0,255), pScheme);
|
|
|
|
_blinkFgColor = GetSchemeColor("Button.BlinkColor", Color(255, 155, 0, 255), pScheme);
|
|
InvalidateLayout();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set default button colors.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetDefaultColor(Color fgColor, Color bgColor)
|
|
{
|
|
if (!(_defaultFgColor == fgColor && _defaultBgColor == bgColor))
|
|
{
|
|
_defaultFgColor = fgColor;
|
|
_defaultBgColor = bgColor;
|
|
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set armed button colors
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetArmedColor(Color fgColor, Color bgColor)
|
|
{
|
|
if (!(_armedFgColor == fgColor && _armedBgColor == bgColor))
|
|
{
|
|
_armedFgColor = fgColor;
|
|
_armedBgColor = bgColor;
|
|
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set depressed button colors
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetDepressedColor(Color fgColor, Color bgColor)
|
|
{
|
|
if (!(_depressedFgColor == fgColor && _depressedBgColor == bgColor))
|
|
{
|
|
_depressedFgColor = fgColor;
|
|
_depressedBgColor = bgColor;
|
|
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set blink button color
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetBlinkColor(Color fgColor)
|
|
{
|
|
if (!(_blinkFgColor == fgColor))
|
|
{
|
|
_blinkFgColor = fgColor;
|
|
|
|
InvalidateLayout(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set default button border attributes.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetDefaultBorder(IBorder *border)
|
|
{
|
|
_defaultBorder = border;
|
|
InvalidateLayout(false);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set depressed button border attributes.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetDepressedBorder(IBorder *border)
|
|
{
|
|
_depressedBorder = border;
|
|
InvalidateLayout(false);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set key focus button border attributes.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetKeyFocusBorder(IBorder *border)
|
|
{
|
|
_keyFocusBorder = border;
|
|
InvalidateLayout(false);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Get button border attributes.
|
|
//-----------------------------------------------------------------------------
|
|
IBorder *Button::GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
|
|
{
|
|
if ( _buttonFlags.IsFlagSet( BUTTON_BORDER_ENABLED ) )
|
|
{
|
|
// raised buttons with no armed state
|
|
if (depressed)
|
|
return _depressedBorder;
|
|
if (keyfocus)
|
|
return _keyFocusBorder;
|
|
if (IsEnabled() && _buttonFlags.IsFlagSet( DEFAULT_BUTTON ))
|
|
return _keyFocusBorder;
|
|
return _defaultBorder;
|
|
}
|
|
else
|
|
{
|
|
// flat buttons that raise
|
|
if (depressed)
|
|
return _depressedBorder;
|
|
if (armed)
|
|
return _defaultBorder;
|
|
}
|
|
|
|
return _defaultBorder;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets this button to be the button that is accessed by default
|
|
// when the user hits ENTER or SPACE
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetAsCurrentDefaultButton(int state)
|
|
{
|
|
bool bState = state ? true : false;
|
|
|
|
if ( _buttonFlags.IsFlagSet( DEFAULT_BUTTON ) != bState )
|
|
{
|
|
_buttonFlags.SetFlag( DEFAULT_BUTTON, bState );
|
|
if ( bState )
|
|
{
|
|
// post a message up notifying our nav group that we're now the default button
|
|
if (GetVParent())
|
|
{
|
|
KeyValues *msg = new KeyValues("CurrentDefaultButtonSet");
|
|
msg->SetInt("button", ToHandle() );
|
|
|
|
ivgui()->PostMessage(GetVParent(), msg, GetVPanel());
|
|
}
|
|
}
|
|
|
|
InvalidateLayout();
|
|
Repaint();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets this button to be the button that is accessed by default
|
|
// when the user hits ENTER or SPACE
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetAsDefaultButton(int state)
|
|
{
|
|
bool bState = state ? true : false;
|
|
|
|
if ( _buttonFlags.IsFlagSet( DEFAULT_BUTTON ) != bState )
|
|
{
|
|
_buttonFlags.SetFlag( DEFAULT_BUTTON, bState );
|
|
if ( bState )
|
|
{
|
|
// post a message up notifying our nav group that we're now the default button
|
|
if (GetVParent())
|
|
{
|
|
KeyValues *msg = new KeyValues("DefaultButtonSet");
|
|
msg->SetInt("button", ToHandle() );
|
|
|
|
ivgui()->PostMessage(GetVParent(), msg, GetVPanel());
|
|
}
|
|
}
|
|
|
|
InvalidateLayout();
|
|
Repaint();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets rollover sound
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetArmedSound(const char *sound)
|
|
{
|
|
if (sound)
|
|
{
|
|
m_sArmedSoundName = g_ButtonSoundNames.AddString(sound);
|
|
}
|
|
else
|
|
{
|
|
m_sArmedSoundName = UTL_INVAL_SYMBOL;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetDepressedSound(const char *sound)
|
|
{
|
|
if (sound)
|
|
{
|
|
m_sDepressedSoundName = g_ButtonSoundNames.AddString(sound);
|
|
}
|
|
else
|
|
{
|
|
m_sDepressedSoundName = UTL_INVAL_SYMBOL;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetReleasedSound(const char *sound)
|
|
{
|
|
if (sound)
|
|
{
|
|
m_sReleasedSoundName = g_ButtonSoundNames.AddString(sound);
|
|
}
|
|
else
|
|
{
|
|
m_sReleasedSoundName = UTL_INVAL_SYMBOL;
|
|
}
|
|
}
|
|
|
|
inline int Button::MouseCodeToMask( MouseCode code )
|
|
{
|
|
// MouseCodes do not start at zero. Make them start at zero before trying to fit them into a 32 bit mask..
|
|
// Otherwise, you would be trying to set bit 107 of an integer, and that would be bad.
|
|
const int recode = code - MOUSE_FIRST;
|
|
AssertMsg1( recode >= 0 && recode < 32, "MouseCode %d is invalid and cannot fit into a 32-bit mask\n", code );
|
|
return 1 << recode ;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Set button to be mouse clickable or not.
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetMouseClickEnabled(MouseCode code,bool state)
|
|
{
|
|
if (state)
|
|
{
|
|
_mouseClickMask |= MouseCodeToMask(code); //set bit to 1
|
|
}
|
|
else
|
|
{
|
|
_mouseClickMask &= ~MouseCodeToMask(code); //set bit to 0
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Check if button is mouse clickable
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::IsMouseClickEnabled(MouseCode code)
|
|
{
|
|
if ( _mouseClickMask & MouseCodeToMask(code) )
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets the command to send when the button is pressed
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetCommand( const char *command )
|
|
{
|
|
SetCommand(new KeyValues("Command", "command", command));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets the message to send when the button is pressed
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SetCommand( KeyValues *message )
|
|
{
|
|
// delete the old message
|
|
if (_actionMessage)
|
|
{
|
|
_actionMessage->deleteThis();
|
|
}
|
|
|
|
_actionMessage = message;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Peeks at the message to send when button is pressed
|
|
// Input : -
|
|
// Output : KeyValues
|
|
//-----------------------------------------------------------------------------
|
|
KeyValues *Button::GetCommand()
|
|
{
|
|
return _actionMessage;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Message targets that the button has been pressed
|
|
//-----------------------------------------------------------------------------
|
|
void Button::FireActionSignal()
|
|
{
|
|
// message-based action signal
|
|
if (_actionMessage)
|
|
{
|
|
// see if it's a url
|
|
if ( !stricmp(_actionMessage->GetName(), "command") )
|
|
{
|
|
char const *szCommand = _actionMessage->GetString("command", "");
|
|
if ( !strnicmp( szCommand, "url ", strlen("url "))
|
|
&& strstr(szCommand, "://") )
|
|
{
|
|
// it's a command to launch a url, run it
|
|
system()->ShellExecute("open", _actionMessage->GetString("command", " ") + 4);
|
|
}
|
|
if ( szCommand[0] == '#' && szCommand[1] == '#' )
|
|
{
|
|
szCommand += 2;
|
|
if ( char const *szEnd = Q_strstr( szCommand, "##" ) )
|
|
{
|
|
KeyValues *pFixedCmd = _actionMessage->MakeCopy();
|
|
char *chBuffer = ( char * ) stackalloc( szEnd - szCommand + 1 );
|
|
Q_snprintf( chBuffer, szEnd - szCommand + 1, "%.*s", szEnd - szCommand, szCommand );
|
|
pFixedCmd->SetString( "command", chBuffer );
|
|
PostActionSignal( pFixedCmd );
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
PostActionSignal(_actionMessage->MakeCopy());
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: gets info about the button
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::RequestInfo(KeyValues *outputData)
|
|
{
|
|
if (!stricmp(outputData->GetName(), "CanBeDefaultButton"))
|
|
{
|
|
outputData->SetInt("result", CanBeDefaultButton() ? 1 : 0);
|
|
return true;
|
|
}
|
|
else if (!stricmp(outputData->GetName(), "GetState"))
|
|
{
|
|
outputData->SetInt("state", IsSelected());
|
|
return true;
|
|
}
|
|
else if ( !stricmp( outputData->GetName(), "GetCommand" ))
|
|
{
|
|
if ( _actionMessage )
|
|
{
|
|
outputData->SetString( "command", _actionMessage->GetString( "command", "" ) );
|
|
}
|
|
else
|
|
{
|
|
outputData->SetString( "command", "" );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
return BaseClass::RequestInfo(outputData);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
bool Button::CanBeDefaultButton(void)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Get control settings for editing
|
|
//-----------------------------------------------------------------------------
|
|
void Button::GetSettings( KeyValues *outResourceData )
|
|
{
|
|
BaseClass::GetSettings(outResourceData);
|
|
|
|
if (_actionMessage)
|
|
{
|
|
outResourceData->SetString("command", _actionMessage->GetString("command", ""));
|
|
}
|
|
outResourceData->SetInt("default", _buttonFlags.IsFlagSet( DEFAULT_BUTTON ) );
|
|
if ( m_bSelectionStateSaved )
|
|
{
|
|
outResourceData->SetInt( "selected", IsSelected() );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::ApplySettings( KeyValues *inResourceData )
|
|
{
|
|
BaseClass::ApplySettings(inResourceData);
|
|
|
|
const char *cmd = inResourceData->GetString("command", "");
|
|
if (*cmd)
|
|
{
|
|
// add in the command
|
|
SetCommand(cmd);
|
|
}
|
|
|
|
// set default button state
|
|
int defaultButton = inResourceData->GetInt("default");
|
|
if (defaultButton && CanBeDefaultButton())
|
|
{
|
|
SetAsDefaultButton(true);
|
|
}
|
|
|
|
// saved selection state
|
|
int iSelected = inResourceData->GetInt( "selected", -1 );
|
|
if ( iSelected != -1 )
|
|
{
|
|
SetSelected( iSelected != 0 );
|
|
m_bSelectionStateSaved = true;
|
|
}
|
|
|
|
const char *sound = inResourceData->GetString("sound_armed", "");
|
|
if (*sound)
|
|
{
|
|
SetArmedSound(sound);
|
|
}
|
|
sound = inResourceData->GetString("sound_depressed", "");
|
|
if (*sound)
|
|
{
|
|
SetDepressedSound(sound);
|
|
}
|
|
sound = inResourceData->GetString("sound_released", "");
|
|
if (*sound)
|
|
{
|
|
SetReleasedSound(sound);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Describes editing details
|
|
//-----------------------------------------------------------------------------
|
|
const char *Button::GetDescription( void )
|
|
{
|
|
static char buf[1024];
|
|
Q_snprintf(buf, sizeof(buf), "%s, string command, int default", BaseClass::GetDescription());
|
|
return buf;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnSetState(int state)
|
|
{
|
|
SetSelected(state ? true : false );
|
|
Repaint();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnCursorEntered()
|
|
{
|
|
if (IsEnabled())
|
|
{
|
|
NavigateTo();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnCursorExited()
|
|
{
|
|
if ( !_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) )
|
|
{
|
|
NavigateFrom();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnMousePressed(MouseCode code)
|
|
{
|
|
if (!IsEnabled())
|
|
return;
|
|
|
|
if (!IsMouseClickEnabled(code))
|
|
return;
|
|
|
|
if (_activationType == ACTIVATE_ONPRESSED)
|
|
{
|
|
if ( IsKeyBoardInputEnabled() )
|
|
{
|
|
RequestFocus();
|
|
}
|
|
DoClick();
|
|
return;
|
|
}
|
|
|
|
// play activation sound
|
|
if (m_sDepressedSoundName != UTL_INVAL_SYMBOL)
|
|
{
|
|
surface()->PlaySound(g_ButtonSoundNames.String(m_sDepressedSoundName));
|
|
}
|
|
|
|
if (IsUseCaptureMouseEnabled() && _activationType == ACTIVATE_ONPRESSEDANDRELEASED)
|
|
{
|
|
{
|
|
if ( IsKeyBoardInputEnabled() )
|
|
{
|
|
RequestFocus();
|
|
}
|
|
SetSelected(true);
|
|
Repaint();
|
|
}
|
|
|
|
// lock mouse input to going to this button
|
|
input()->SetMouseCapture(GetVPanel());
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnMouseDoublePressed(MouseCode code)
|
|
{
|
|
OnMousePressed(code);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnMouseReleased(MouseCode code)
|
|
{
|
|
// ensure mouse capture gets released
|
|
if (IsUseCaptureMouseEnabled())
|
|
{
|
|
input()->SetMouseCapture(NULL);
|
|
}
|
|
|
|
if (_activationType == ACTIVATE_ONPRESSED)
|
|
return;
|
|
|
|
if (!IsMouseClickEnabled(code))
|
|
return;
|
|
|
|
if (!IsSelected() && _activationType == ACTIVATE_ONPRESSEDANDRELEASED)
|
|
return;
|
|
|
|
// it has to be both enabled and (mouse over the button or using a key) to fire
|
|
if ( IsEnabled() && ( GetVPanel() == input()->GetMouseOver() || _buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) ) )
|
|
{
|
|
DoClick();
|
|
}
|
|
else
|
|
{
|
|
SetSelected(false);
|
|
}
|
|
|
|
// make sure the button gets unselected
|
|
Repaint();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnKeyCodePressed(KeyCode code)
|
|
{
|
|
KeyCode localCode = GetBaseButtonCode( code );
|
|
|
|
if( ( localCode == KEY_XBUTTON_A ) && IsEnabled() )
|
|
{
|
|
SetArmed( true );
|
|
_buttonFlags.SetFlag( BUTTON_KEY_DOWN );
|
|
if( _activationType != ACTIVATE_ONRELEASED )
|
|
{
|
|
DoClick();
|
|
}
|
|
}
|
|
else if (code == KEY_SPACE || code == KEY_ENTER)
|
|
{
|
|
SetArmed(true);
|
|
_buttonFlags.SetFlag( BUTTON_KEY_DOWN );
|
|
OnMousePressed(MOUSE_LEFT);
|
|
if (IsUseCaptureMouseEnabled()) // undo the mouse capture since its a fake mouse click!
|
|
{
|
|
input()->SetMouseCapture(NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_buttonFlags.ClearFlag( BUTTON_KEY_DOWN );
|
|
BaseClass::OnKeyCodePressed( code );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void Button::OnKeyCodeReleased( KeyCode keycode )
|
|
{
|
|
vgui::KeyCode code = GetBaseButtonCode( keycode );
|
|
|
|
if ( _buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) && ( code == KEY_XBUTTON_A || code == KEY_XBUTTON_START ) )
|
|
{
|
|
SetArmed( true );
|
|
if( _activationType != ACTIVATE_ONPRESSED )
|
|
{
|
|
DoClick();
|
|
}
|
|
}
|
|
else if (_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) && (code == KEY_SPACE || code == KEY_ENTER))
|
|
{
|
|
SetArmed(true);
|
|
OnMouseReleased(MOUSE_LEFT);
|
|
}
|
|
else
|
|
{
|
|
BaseClass::OnKeyCodeReleased( keycode );
|
|
}
|
|
_buttonFlags.ClearFlag( BUTTON_KEY_DOWN );
|
|
|
|
if ( !IsGameConsole() )
|
|
{
|
|
SetArmed(false);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Override this to draw different focus border
|
|
//-----------------------------------------------------------------------------
|
|
void Button::DrawFocusBorder(int tx0, int ty0, int tx1, int ty1)
|
|
{
|
|
surface()->DrawSetColor(_keyboardFocusColor);
|
|
DrawDashedLine(tx0, ty0, tx1, ty0+1, 1, 1); // top
|
|
DrawDashedLine(tx0, ty0, tx0+1, ty1, 1, 1); // left
|
|
DrawDashedLine(tx0, ty1-1, tx1, ty1, 1, 1); // bottom
|
|
DrawDashedLine(tx1-1, ty0, tx1, ty1, 1, 1); // right
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Size the object to its button and text. - only works from in ApplySchemeSettings or PerformLayout()
|
|
//-----------------------------------------------------------------------------
|
|
void Button::SizeToContents()
|
|
{
|
|
int wide, tall;
|
|
GetContentSize(wide, tall);
|
|
SetSize(wide + Label::Content, tall + Label::Content);
|
|
}
|
|
|
|
void Button::GetSizerMinimumSize(int &wide, int &tall)
|
|
{
|
|
GetContentSize(wide, tall);
|
|
wide += Label::Content;
|
|
tall += Label::Content;
|
|
}
|