//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Basic button control // // $NoKeywords: $ //=============================================================================// #include #include #include #include #include #include #include #include #include #include #include #include "URLButton.h" #include // memdbgon must be the last include file in a .cpp file!!! #include using namespace vgui; DECLARE_BUILD_FACTORY_DEFAULT_TEXT( URLButton, URLButton ); //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- URLButton::URLButton(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 //----------------------------------------------------------------------------- URLButton::URLButton(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 URLButton::Init() { _buttonFlags.SetFlag( USE_CAPTURE_MOUSE | BUTTON_BORDER_ENABLED ); _mouseClickMask = 0; _actionMessage = NULL; m_bSelectionStateSaved = false; SetTextInset(0, 0); SetMouseClickEnabled( MOUSE_LEFT, true ); SetButtonActivationType(ACTIVATE_ONPRESSEDANDRELEASED); // labels have this off by default, but we need it on SetPaintBackgroundEnabled( true ); } //----------------------------------------------------------------------------- // Purpose: Destructor //----------------------------------------------------------------------------- URLButton::~URLButton() { if (_actionMessage) { _actionMessage->deleteThis(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::SetButtonActivationType(ActivationType_t activationType) { _activationType = activationType; } //----------------------------------------------------------------------------- // Purpose: Set button border attribute enabled. //----------------------------------------------------------------------------- void URLButton::SetButtonBorderEnabled( bool state ) { if ( state != _buttonFlags.IsFlagSet( BUTTON_BORDER_ENABLED ) ) { _buttonFlags.SetFlag( BUTTON_BORDER_ENABLED, state ); InvalidateLayout(false); } } //----------------------------------------------------------------------------- // Purpose: Set button selected state. //----------------------------------------------------------------------------- void URLButton::SetSelected( bool state ) { if ( _buttonFlags.IsFlagSet( SELECTED ) != state ) { _buttonFlags.SetFlag( SELECTED, state ); RecalculateDepressedState(); InvalidateLayout(false); } } //----------------------------------------------------------------------------- // Purpose: Set button force depressed state. //----------------------------------------------------------------------------- void URLButton::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 URLButton::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 URLButton::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 URLButton::IsUseCaptureMouseEnabled( void ) { return _buttonFlags.IsFlagSet( USE_CAPTURE_MOUSE ); } //----------------------------------------------------------------------------- // Purpose: Set armed state. //----------------------------------------------------------------------------- void URLButton::SetArmed(bool state) { if ( _buttonFlags.IsFlagSet( ARMED ) != state ) { _buttonFlags.SetFlag( ARMED, state ); RecalculateDepressedState(); InvalidateLayout(false); } } //----------------------------------------------------------------------------- // Purpose: Check armed state //----------------------------------------------------------------------------- bool URLButton::IsArmed() { return _buttonFlags.IsFlagSet( ARMED ); } KeyValues *URLButton::GetActionMessage() { return _actionMessage->MakeCopy(); } //----------------------------------------------------------------------------- // Purpose: Activate a button click. //----------------------------------------------------------------------------- void URLButton::DoClick() { SetSelected(true); FireActionSignal(); SetSelected(false); } //----------------------------------------------------------------------------- // Purpose: Check selected state //----------------------------------------------------------------------------- bool URLButton::IsSelected() { return _buttonFlags.IsFlagSet( SELECTED ); } //----------------------------------------------------------------------------- // Purpose: Check depressed state //----------------------------------------------------------------------------- bool URLButton::IsDepressed() { return _buttonFlags.IsFlagSet( DEPRESSED ); } //----------------------------------------------------------------------------- // Drawing focus box? //----------------------------------------------------------------------------- bool URLButton::IsDrawingFocusBox() { return _buttonFlags.IsFlagSet( DRAW_FOCUS_BOX ); } void URLButton::DrawFocusBox( bool bEnable ) { _buttonFlags.SetFlag( DRAW_FOCUS_BOX, bEnable ); } //----------------------------------------------------------------------------- // Purpose: Paint button on screen //----------------------------------------------------------------------------- void URLButton::Paint(void) { BaseClass::Paint(); int x, y; int controlWidth, controlHeight, textWidth, textHeight; GetSize(controlWidth, controlHeight); GetContentSize(textWidth, textHeight); x = textWidth; y = controlHeight - 4; surface()->DrawSetColor(GetButtonFgColor()); surface()->DrawLine(0, y, x, y); } //----------------------------------------------------------------------------- // Purpose: Perform graphical layout of button. //----------------------------------------------------------------------------- void URLButton::PerformLayout() { // set our color SetFgColor(GetButtonFgColor()); SetBgColor(GetButtonBgColor()); BaseClass::PerformLayout(); } //----------------------------------------------------------------------------- // Purpose: Get button foreground color // Output : Color //----------------------------------------------------------------------------- Color URLButton::GetButtonFgColor() { return _defaultFgColor; } //----------------------------------------------------------------------------- // Purpose: Get button background color //----------------------------------------------------------------------------- Color URLButton::GetButtonBgColor() { return _defaultBgColor; } //----------------------------------------------------------------------------- // Purpose: Called when key focus is received //----------------------------------------------------------------------------- void URLButton::OnSetFocus() { InvalidateLayout(false); BaseClass::OnSetFocus(); } //----------------------------------------------------------------------------- // Purpose: Respond when focus is killed //----------------------------------------------------------------------------- void URLButton::OnKillFocus() { InvalidateLayout(false); BaseClass::OnKillFocus(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::ApplySchemeSettings(IScheme *pScheme) { BaseClass::ApplySchemeSettings(pScheme); _defaultFgColor = GetSchemeColor("Button.TextColor", Color(255, 255, 255, 255), pScheme); _defaultBgColor = GetSchemeColor("Button.BgColor", Color(0, 0, 0, 255), pScheme); InvalidateLayout(); } //----------------------------------------------------------------------------- // Purpose: Set button to be mouse clickable or not. //----------------------------------------------------------------------------- void URLButton::SetMouseClickEnabled(MouseCode code,bool state) { if(state) { //set bit to 1 _mouseClickMask|=1<<((int)(code+1)); } else { //set bit to 0 _mouseClickMask&=~(1<<((int)(code+1))); } } //----------------------------------------------------------------------------- // Purpose: sets the command to send when the button is pressed //----------------------------------------------------------------------------- void URLButton::SetCommand( const char *command ) { SetCommand(new KeyValues("Command", "command", command)); } //----------------------------------------------------------------------------- // Purpose: sets the message to send when the button is pressed //----------------------------------------------------------------------------- void URLButton::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 *URLButton::GetCommand() { return _actionMessage; } //----------------------------------------------------------------------------- // Purpose: Message targets that the button has been pressed //----------------------------------------------------------------------------- void URLButton::FireActionSignal() { // message-based action signal if (_actionMessage) { // see if it's a url if (!stricmp(_actionMessage->GetName(), "command") && !strnicmp(_actionMessage->GetString("command", ""), "url ", strlen("url ")) && strstr(_actionMessage->GetString("command", ""), "://")) { // it's a command to launch a url, run it system()->ShellExecute("open", _actionMessage->GetString("command", " ") + 4); } PostActionSignal(_actionMessage->MakeCopy()); } } //----------------------------------------------------------------------------- // Purpose: gets info about the button //----------------------------------------------------------------------------- bool URLButton::RequestInfo(KeyValues *outputData) { 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: Get control settings for editing //----------------------------------------------------------------------------- void URLButton::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 URLButton::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings(inResourceData); const char *cmd = inResourceData->GetString("command", ""); if (*cmd) { // add in the command SetCommand(cmd); } // saved selection state int iSelected = inResourceData->GetInt( "selected", -1 ); if ( iSelected != -1 ) { SetSelected( iSelected != 0 ); m_bSelectionStateSaved = true; } } //----------------------------------------------------------------------------- // Purpose: Describes editing details //----------------------------------------------------------------------------- const char *URLButton::GetDescription( void ) { static char buf[1024]; Q_snprintf(buf, sizeof(buf), "%s, string command, int default", BaseClass::GetDescription()); return buf; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::OnSetState(int state) { SetSelected((bool)state); Repaint(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::OnCursorEntered() { if (IsEnabled()) { SetArmed(true); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::OnCursorExited() { if ( !_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) ) { SetArmed(false); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::OnMousePressed(MouseCode code) { if (!IsEnabled()) return; if (_activationType == ACTIVATE_ONPRESSED) { if ( IsKeyBoardInputEnabled() ) { RequestFocus(); } DoClick(); return; } if (IsUseCaptureMouseEnabled() && _activationType == ACTIVATE_ONPRESSEDANDRELEASED) { { if ( IsKeyBoardInputEnabled() ) { RequestFocus(); } SetSelected(true); Repaint(); } // lock mouse input to going to this button input()->SetMouseCapture(GetVPanel()); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::OnMouseDoublePressed(MouseCode code) { OnMousePressed(code); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void URLButton::OnMouseReleased(MouseCode code) { // ensure mouse capture gets released if (IsUseCaptureMouseEnabled()) { input()->SetMouseCapture(NULL); } if (_activationType == ACTIVATE_ONPRESSED) 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 URLButton::OnKeyCodePressed(KeyCode code) { 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 URLButton::OnKeyCodeReleased(KeyCode code) { if (_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) && (code == KEY_SPACE || code == KEY_ENTER)) { SetArmed(true); OnMouseReleased(MOUSE_LEFT); } else { BaseClass::OnKeyCodeReleased(code); } _buttonFlags.ClearFlag( BUTTON_KEY_DOWN ); SetArmed(false); } //----------------------------------------------------------------------------- // Purpose: Size the object to its button and text. - only works from in ApplySchemeSettings or PerformLayout() //----------------------------------------------------------------------------- void URLButton::SizeToContents() { int wide, tall; GetContentSize(wide, tall); SetSize(wide + Label::Content, tall + Label::Content); }