//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //===========================================================================// #include #include // for ceil() #define PROTECTED_THINGS_DISABLE #include "tier1/utlstring.h" #include "vgui/Cursor.h" #include "vgui/MouseCode.h" #include "vgui/IBorder.h" #include "vgui/IInput.h" #include "vgui/ILocalize.h" #include "vgui/IPanel.h" #include "vgui/ISurface.h" #include "vgui/IScheme.h" #include "vgui/KeyCode.h" #include "vgui_controls/AnimationController.h" #include "vgui_controls/Controls.h" #include "vgui_controls/Frame.h" #include "vgui_controls/Button.h" #include "vgui_controls/Menu.h" #include "vgui_controls/MenuButton.h" #include "vgui_controls/TextImage.h" #include "KeyValues.h" #include // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" using namespace vgui; static const int DEFAULT_SNAP_RANGE = 10; // number of pixels distance before the frame will snap to an edge static const int CAPTION_TITLE_BORDER = 7; static const int CAPTION_TITLE_BORDER_SMALL = 0; namespace { //----------------------------------------------------------------------------- // Purpose: Invisible panel to handle dragging/resizing frames //----------------------------------------------------------------------------- class GripPanel : public Panel { public: GripPanel(Frame *dragFrame, const char *name, int xdir, int ydir) : Panel(dragFrame, name) { _frame = dragFrame; _dragging = false; _dragMultX = xdir; _dragMultY = ydir; SetPaintEnabled(false); SetPaintBackgroundEnabled(false); SetPaintBorderEnabled(false); m_iSnapRange = DEFAULT_SNAP_RANGE; if (xdir == 1 && ydir == 1) { // bottom-right grip gets an image SetPaintEnabled(true); SetPaintBackgroundEnabled(true); } SetBlockDragChaining( true ); } // Purpose- handle window resizing // Input- dx, dy, the offet of the mouse pointer from where we started dragging virtual void moved(int dx, int dy) { if (!_frame->IsSizeable()) return; // Start off with x, y at the coords of where we started to drag int newX = _dragOrgPos[0], newY =_dragOrgPos[1]; // Start off with width and tall equal from window when we started to drag int newWide = _dragOrgSize[0], newTall = _dragOrgSize[1]; // get window's minimum size int minWide, minTall; _frame->GetMinimumSize( minWide, minTall); // Handle width resizing newWide += (dx * _dragMultX); // Handle the position of the corner x position if (_dragMultX == -1) { // only move if we are not at the minimum // if we are at min we have to force the proper offset (dx) if (newWide < minWide) { dx=_dragOrgSize[0]-minWide; } newX += dx; // move window to its new position } // Handle height resizing newTall += (dy * _dragMultY); // Handle position of corner y position if (_dragMultY == -1) { if (newTall < minTall) { dy=_dragOrgSize[1]-minTall; } newY += dy; } if ( _frame->GetClipToParent() ) { // If any coordinate is out of range, snap it back if ( newX < 0 ) newX = 0; if ( newY < 0 ) newY = 0; int sx, sy; surface()->GetScreenSize( sx, sy ); int w, h; _frame->GetSize( w, h ); if ( newX + w > sx ) { newX = sx - w; } if ( newY + h > sy ) { newY = sy - h; } } // set new position _frame->SetPos(newX, newY); // set the new size // if window is below min size it will automatically pop to min size _frame->SetSize(newWide, newTall); _frame->InvalidateLayout(); _frame->Repaint(); } void OnCursorMoved(int x, int y) { if (!_dragging) return; if (!input()->IsMouseDown(MOUSE_LEFT)) { // for some reason we're marked as dragging when the mouse is released // trigger a release OnMouseReleased(MOUSE_LEFT); return; } input()->GetCursorPos(x, y); moved((x - _dragStart[0]), ( y - _dragStart[1])); _frame->Repaint(); } void OnMousePressed(MouseCode code) { if (code == MOUSE_LEFT) { _dragging=true; int x,y; input()->GetCursorPos(x,y); _dragStart[0]=x; _dragStart[1]=y; _frame->GetPos(_dragOrgPos[0],_dragOrgPos[1]); _frame->GetSize(_dragOrgSize[0],_dragOrgSize[1]); input()->SetMouseCapture(GetVPanel()); // if a child doesn't have focus, get it for ourselves VPANEL focus = input()->GetFocus(); if (!focus || !ipanel()->HasParent(focus, _frame->GetVPanel())) { _frame->RequestFocus(); } _frame->Repaint(); } else { GetParent()->OnMousePressed(code); } } void OnMouseDoublePressed(MouseCode code) { GetParent()->OnMouseDoublePressed(code); } void Paint() { // draw the grab handle in the bottom right of the frame surface()->DrawSetTextFont(_marlettFont); surface()->DrawSetTextPos(0, 0); // thin highlight lines surface()->DrawSetTextColor(GetFgColor()); surface()->DrawUnicodeChar('p'); } void PaintBackground() { // draw the grab handle in the bottom right of the frame surface()->DrawSetTextFont(_marlettFont); surface()->DrawSetTextPos(0, 0); // thick shadow lines surface()->DrawSetTextColor(GetBgColor()); surface()->DrawUnicodeChar('o'); } void OnMouseReleased(MouseCode code) { _dragging = false; input()->SetMouseCapture(NULL); } void OnMouseCaptureLost() { Panel::OnMouseCaptureLost(); _dragging = false; } void ApplySchemeSettings(IScheme *pScheme) { Panel::ApplySchemeSettings(pScheme); bool isSmall = ((Frame *)GetParent())->IsSmallCaption(); _marlettFont = pScheme->GetFont( isSmall ? "MarlettSmall" : "Marlett", IsProportional()); SetFgColor(GetSchemeColor("FrameGrip.Color1", pScheme)); SetBgColor(GetSchemeColor("FrameGrip.Color2", pScheme)); const char *snapRange = pScheme->GetResourceString("Frame.AutoSnapRange"); if (snapRange && *snapRange) { m_iSnapRange = atoi(snapRange); } } protected: Frame *_frame; int _dragMultX; int _dragMultY; bool _dragging; int _dragOrgPos[2]; int _dragOrgSize[2]; int _dragStart[2]; int m_iSnapRange; HFont _marlettFont; }; //----------------------------------------------------------------------------- // Purpose: Handles caption grip input for moving dialogs around //----------------------------------------------------------------------------- class CaptionGripPanel : public GripPanel { public: CaptionGripPanel(Frame* frame, const char *name) : GripPanel(frame, name, 0, 0) { } void moved(int dx, int dy) { if (!_frame->IsMoveable()) return; int newX = _dragOrgPos[0] + dx; int newY = _dragOrgPos[1] + dy; if (m_iSnapRange) { // first check docking to desktop int wx, wy, ww, wt; surface()->GetWorkspaceBounds(wx, wy, ww, wt); getInsideSnapPosition(wx, wy, ww, wt, newX, newY); // now lets check all windows and see if we snap to those // root panel VPANEL root = surface()->GetEmbeddedPanel(); // cycle through panels // look for panels that are visible and are popups that we can dock to for (int i = 0; i < ipanel()->GetChildCount(root); ++i) { VPANEL child = ipanel()->GetChild(root, i); tryToDock (child, newX, newY); } } if ( _frame->GetClipToParent() ) { // If any coordinate is out of range, snap it back if ( newX < 0 ) newX = 0; if ( newY < 0 ) newY = 0; int sx, sy; surface()->GetScreenSize( sx, sy ); int w, h; _frame->GetSize( w, h ); if ( newX + w > sx ) { newX = sx - w; } if ( newY + h > sy ) { newY = sy - h; } } _frame->SetPos(newX, newY); } void tryToDock(VPANEL window, int &newX, int & newY) { // bail if child is this window if ( window == _frame->GetVPanel()) return; int cx, cy, cw, ct; if ( (ipanel()->IsVisible(window)) && (ipanel()->IsPopup(window)) ) { // position ipanel()->GetAbsPos(window, cx, cy); // dimensions ipanel()->GetSize(window, cw, ct); bool snapped = getOutsideSnapPosition (cx, cy, cw, ct, newX, newY); if (snapped) { // if we snapped, we're done with this path // dont try to snap to kids return; } } // check all children for (int i = 0; i < ipanel()->GetChildCount(window); ++i) { VPANEL child = ipanel()->GetChild(window, i); tryToDock(child, newX, newY); } } // Purpose: To calculate the windows new x,y position if it snaps // Will snap to the INSIDE of a window (eg desktop sides // Input: boundX boundY, position of candidate window we are seeing if we snap to // boundWide, boundTall, width and height of window we are seeing if we snap to // Output: snapToX, snapToY new coords for window, unchanged if we dont snap // Returns true if we snapped, false if we did not snap. bool getInsideSnapPosition(int boundX, int boundY, int boundWide, int boundTall, int &snapToX, int &snapToY) { int wide, tall; _frame->GetSize(wide, tall); Assert (wide > 0); Assert (tall > 0); bool snapped=false; if (abs(snapToX - boundX) < m_iSnapRange) { snapToX = boundX; snapped=true; } else if (abs((snapToX + wide) - (boundX + boundWide)) < m_iSnapRange) { snapToX = boundX + boundWide - wide; snapped=true; } if (abs(snapToY - boundY) < m_iSnapRange) { snapToY = boundY; snapped=true; } else if (abs((snapToY + tall) - (boundY + boundTall)) < m_iSnapRange) { snapToY = boundY + boundTall - tall; snapped=true; } return snapped; } // Purpose: To calculate the windows new x,y position if it snaps // Will snap to the OUTSIDE edges of a window (i.e. will stick peers together // Input: left, top, position of candidate window we are seeing if we snap to // boundWide, boundTall, width and height of window we are seeing if we snap to // Output: snapToX, snapToY new coords for window, unchanged if we dont snap // Returns true if we snapped, false if we did not snap. bool getOutsideSnapPosition(int left, int top, int boundWide, int boundTall, int &snapToX, int &snapToY) { Assert (boundWide >= 0); Assert (boundTall >= 0); bool snapped=false; int right=left+boundWide; int bottom=top+boundTall; int wide, tall; _frame->GetSize(wide, tall); Assert (wide > 0); Assert (tall > 0); // we now see if we are going to be able to snap to a window side, and not // just snap to the "open air" // want to make it so that if any part of the window can dock to the candidate, it will // is this window horizontally snappable to the candidate bool horizSnappable=( // top of window is in range ((snapToY > top) && (snapToY < bottom)) // bottom of window is in range || ((snapToY+tall > top) && (snapToY+tall < bottom)) // window is just plain bigger than the window we wanna dock to || ((snapToY < top) && (snapToY+tall > bottom)) ); // is this window vertically snappable to the candidate bool vertSnappable= ( // left of window is in range ((snapToX > left) && (snapToX < right)) // right of window is in range || ((snapToX+wide > left) && (snapToX+wide < right)) // window is just plain bigger than the window we wanna dock to || ((snapToX < left) && (snapToX+wide > right)) ); // if neither, might as well bail if ( !(horizSnappable || vertSnappable) ) return false; //if we're within the snap threshold then snap if ( (snapToX <= (right+m_iSnapRange)) && (snapToX >= (right-m_iSnapRange)) ) { if (horizSnappable) { //disallow "open air" snaps snapped=true; snapToX = right; } } else if ((snapToX + wide) >= (left-m_iSnapRange) && (snapToX + wide) <= (left+m_iSnapRange)) { if (horizSnappable) { snapped=true; snapToX = left-wide; } } if ( (snapToY <= (bottom+m_iSnapRange)) && (snapToY >= (bottom-m_iSnapRange)) ) { if (vertSnappable) { snapped=true; snapToY = bottom; } } else if ((snapToY + tall) <= (top+m_iSnapRange) && (snapToY + tall) >= (top-m_iSnapRange)) { if (vertSnappable) { snapped=true; snapToY = top-tall; } } return snapped; } }; } namespace vgui { //----------------------------------------------------------------------------- // Purpose: overrides normal button drawing to use different colors & borders //----------------------------------------------------------------------------- class FrameButton : public Button { private: IBorder *_brightBorder, *_depressedBorder, *_disabledBorder; Color _enabledFgColor, _enabledBgColor; Color _disabledFgColor, _disabledBgColor; bool _disabledLook; public: static int GetButtonSide( Frame *pFrame ) { if ( pFrame->IsSmallCaption() ) { return 12; } return 18; } FrameButton(Panel *parent, const char *name, const char *text) : Button(parent, name, text) { SetSize( FrameButton::GetButtonSide( (Frame *)parent ), FrameButton::GetButtonSide( (Frame *)parent ) ); _brightBorder = NULL; _depressedBorder = NULL; _disabledBorder = NULL; _disabledLook = true; SetContentAlignment(Label::a_northwest); SetTextInset(2, 1); SetBlockDragChaining( true ); } virtual void ApplySchemeSettings(IScheme *pScheme) { Button::ApplySchemeSettings(pScheme); _enabledFgColor = GetSchemeColor("FrameTitleButton.FgColor", pScheme); _enabledBgColor = GetSchemeColor("FrameTitleButton.BgColor", pScheme); _disabledFgColor = GetSchemeColor("FrameTitleButton.DisabledFgColor", pScheme); _disabledBgColor = GetSchemeColor("FrameTitleButton.DisabledBgColor", pScheme); _brightBorder = pScheme->GetBorder("TitleButtonBorder"); _depressedBorder = pScheme->GetBorder("TitleButtonDepressedBorder"); _disabledBorder = pScheme->GetBorder("TitleButtonDisabledBorder"); SetDisabledLook(_disabledLook); } virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus) { if (_disabledLook) { return _disabledBorder; } if (depressed) { return _depressedBorder; } return _brightBorder; } virtual void SetDisabledLook(bool state) { _disabledLook = state; if (!_disabledLook) { SetDefaultColor(_enabledFgColor, _enabledBgColor); SetArmedColor(_enabledFgColor, _enabledBgColor); SetDepressedColor(_enabledFgColor, _enabledBgColor); } else { // setup disabled colors SetDefaultColor(_disabledFgColor, _disabledBgColor); SetArmedColor(_disabledFgColor, _disabledBgColor); SetDepressedColor(_disabledFgColor, _disabledBgColor); } } virtual void PerformLayout() { Button::PerformLayout(); Repaint(); } // Don't request focus. // This will keep items in the listpanel selected. virtual void OnMousePressed(MouseCode code) { if (!IsEnabled()) return; if (!IsMouseClickEnabled(code)) return; if (IsUseCaptureMouseEnabled()) { { SetSelected(true); Repaint(); } // lock mouse input to going to this button input()->SetMouseCapture(GetVPanel()); } } }; //----------------------------------------------------------------------------- // Purpose: icon button //----------------------------------------------------------------------------- class FrameSystemButton : public MenuButton { DECLARE_CLASS_SIMPLE( FrameSystemButton, MenuButton ); private: IImage *_enabled, *_disabled; Color _enCol, _disCol; bool _respond; CUtlString m_EnabledImage; CUtlString m_DisabledImage; public: FrameSystemButton(Panel *parent, const char *panelName) : MenuButton(parent, panelName, "") { _disabled = _enabled = NULL; _respond = true; SetEnabled(false); // This menu will open if we use the left or right mouse button SetMouseClickEnabled( MOUSE_RIGHT, true ); SetBlockDragChaining( true ); } void SetImages( const char *pEnabledImage, const char *pDisabledImage = NULL ) { m_EnabledImage = pEnabledImage; m_DisabledImage = pDisabledImage ? pDisabledImage : pEnabledImage; } void GetImageSize( int &w, int &h ) { w = h = 0; int tw = 0, th = 0; if ( _enabled ) { _enabled->GetSize( w, h ); } if ( _disabled ) { _disabled->GetSize( tw, th ); } if ( tw > w ) { w = tw; } if ( th > h ) { h = th; } } virtual void ApplySchemeSettings(IScheme *pScheme) { BaseClass::ApplySchemeSettings(pScheme); _enCol = GetSchemeColor("FrameSystemButton.FgColor", pScheme); _disCol = GetSchemeColor("FrameSystemButton.BgColor", pScheme); const char *pEnabledImage = m_EnabledImage.Length() ? m_EnabledImage.Get() : pScheme->GetResourceString( "FrameSystemButton.Icon" ); const char *pDisabledImage = m_DisabledImage.Length() ? m_DisabledImage.Get() : pScheme->GetResourceString( "FrameSystemButton.DisabledIcon" ); _enabled = scheme()->GetImage( pEnabledImage, false); _disabled = scheme()->GetImage( pDisabledImage, false); SetTextInset(0, 0); // get our iconic image SetEnabled(IsEnabled()); } virtual IBorder *GetBorder(bool depressed, bool armed, bool selected, bool keyfocus) { return NULL; } virtual void SetEnabled(bool state) { Button::SetEnabled(state); if (IsEnabled()) { if ( _enabled ) { SetImageAtIndex(0, _enabled, 0); } SetBgColor(_enCol); SetDefaultColor(_enCol, _enCol); SetArmedColor(_enCol, _enCol); SetDepressedColor(_enCol, _enCol); } else { if ( _disabled ) { SetImageAtIndex(0, _disabled, 0); } SetBgColor(_disCol); SetDefaultColor(_disCol, _disCol); SetArmedColor(_disCol, _disCol); SetDepressedColor(_disCol, _disCol); } } void SetResponsive(bool state) { _respond = state; } virtual void OnMousePressed(MouseCode code) { // button may look enabled but not be responsive if (!_respond) return; BaseClass::OnMousePressed(code); } virtual void OnMouseDoublePressed(MouseCode code) { // button may look enabled but not be responsive if (!_respond) return; // only close if left is double pressed if (code == MOUSE_LEFT) { // double click on the icon closes the window // But only if the menu contains a 'close' item vgui::Menu *pMenu = GetMenu(); if ( pMenu && pMenu->FindChildByName("Close") ) { PostMessage(GetVParent(), new KeyValues("CloseFrameButtonPressed")); } } } }; } // namespace vgui //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- Frame::Frame(Panel *parent, const char *panelName, bool showTaskbarIcon /*=true*/, bool bPopup /*=true*/ ) : EditablePanel(parent, panelName) { // frames start invisible, to avoid having window flicker in on taskbar SetVisible(false); if ( bPopup ) { MakePopup(showTaskbarIcon); } m_hPreviousModal = 0; _title=null; _moveable=true; _sizeable=true; m_bHasFocus=false; _flashWindow=false; _drawTitleBar = true; m_bPreviouslyVisible = false; m_bFadingOut = false; m_bDisableFadeEffect = false; m_flTransitionEffectTime = 0.0f; m_flFocusTransitionEffectTime = 0.0f; m_bDeleteSelfOnClose = false; m_iClientInsetX = 5; m_iClientInsetY = 5; m_iClientInsetXOverridden = false; m_iTitleTextInsetX = 28; m_bClipToParent = false; m_bSmallCaption = false; m_bChainKeysToParent = false; m_bPrimed = false; m_hCustomTitleFont = INVALID_FONT; SetTitle("#Frame_Untitled", parent ? false : true); // add ourselves to the build group SetBuildGroup(GetBuildGroup()); SetMinimumSize(128,66); GetFocusNavGroup().SetFocusTopLevel(true); #if !defined( _X360 ) _sysMenu = NULL; // add dragging grips _topGrip = new GripPanel(this, "frame_topGrip", 0, -1); _bottomGrip = new GripPanel(this, "frame_bottomGrip", 0, 1); _leftGrip = new GripPanel(this, "frame_leftGrip", -1, 0); _rightGrip = new GripPanel(this, "frame_rightGrip", 1, 0); _topLeftGrip = new GripPanel(this, "frame_tlGrip", -1, -1); _topRightGrip = new GripPanel(this, "frame_trGrip", 1, -1); _bottomLeftGrip = new GripPanel(this, "frame_blGrip", -1, 1); _bottomRightGrip = new GripPanel(this, "frame_brGrip", 1, 1); _captionGrip = new CaptionGripPanel(this, "frame_caption" ); _captionGrip->SetCursor(dc_arrow); _minimizeButton = new FrameButton(this, "frame_minimize","0"); _minimizeButton->AddActionSignalTarget(this); _minimizeButton->SetCommand(new KeyValues("Minimize")); _maximizeButton = new FrameButton(this, "frame_maximize", "1"); //!! no maximize handler implemented yet, so leave maximize button disabled SetMaximizeButtonVisible(false); char str[] = { 0x6F, 0 }; _minimizeToSysTrayButton = new FrameButton(this, "frame_mintosystray", str); _minimizeToSysTrayButton->SetCommand("MinimizeToSysTray"); SetMinimizeToSysTrayButtonVisible(false); _closeButton = new FrameButton(this, "frame_close", "r"); _closeButton->AddActionSignalTarget(this); _closeButton->SetCommand(new KeyValues("CloseFrameButtonPressed")); if (!surface()->SupportsFeature(ISurface::FRAME_MINIMIZE_MAXIMIZE)) { SetMinimizeButtonVisible(false); SetMaximizeButtonVisible(false); } if (parent) { // vgui doesn't support subwindow minimization SetMinimizeButtonVisible(false); SetMaximizeButtonVisible(false); } _menuButton = new FrameSystemButton(this, "frame_menu"); _menuButton->SetMenu(GetSysMenu()); #endif SetupResizeCursors(); REGISTER_COLOR_AS_OVERRIDABLE( m_InFocusBgColor, "infocus_bgcolor_override" ); REGISTER_COLOR_AS_OVERRIDABLE( m_OutOfFocusBgColor, "outoffocus_bgcolor_override" ); REGISTER_COLOR_AS_OVERRIDABLE( _titleBarBgColor, "titlebarbgcolor_override" ); REGISTER_COLOR_AS_OVERRIDABLE( _titleBarDisabledBgColor, "titlebardisabledbgcolor_override" ); REGISTER_COLOR_AS_OVERRIDABLE( _titleBarFgColor, "titlebarfgcolor_override" ); REGISTER_COLOR_AS_OVERRIDABLE( _titleBarDisabledFgColor, "titlebardisabledfgcolor_override" ); } //----------------------------------------------------------------------------- // Purpose: Destructor //----------------------------------------------------------------------------- Frame::~Frame() { if ( input()->GetAppModalSurface() == GetVPanel() ) { vgui::input()->ReleaseAppModalSurface(); if ( m_hPreviousModal != 0 ) { vgui::input()->SetAppModalSurface( m_hPreviousModal ); m_hPreviousModal = 0; } } #if !defined( _X360 ) delete _topGrip; delete _bottomGrip; delete _leftGrip; delete _rightGrip; delete _topLeftGrip; delete _topRightGrip; delete _bottomLeftGrip; delete _bottomRightGrip; delete _captionGrip; delete _minimizeButton; delete _maximizeButton; delete _closeButton; delete _menuButton; delete _minimizeToSysTrayButton; #endif delete _title; } //----------------------------------------------------------------------------- // Purpose: Setup the grips on the edges of the panel to resize it. //----------------------------------------------------------------------------- void Frame::SetupResizeCursors() { #if !defined( _X360 ) if (IsSizeable()) { _topGrip->SetCursor(dc_sizens); _bottomGrip->SetCursor(dc_sizens); _leftGrip->SetCursor(dc_sizewe); _rightGrip->SetCursor(dc_sizewe); _topLeftGrip->SetCursor(dc_sizenwse); _topRightGrip->SetCursor(dc_sizenesw); _bottomLeftGrip->SetCursor(dc_sizenesw); _bottomRightGrip->SetCursor(dc_sizenwse); _bottomRightGrip->SetPaintEnabled(true); _bottomRightGrip->SetPaintBackgroundEnabled(true); } else { // not resizable, so just use the default cursor _topGrip->SetCursor(dc_arrow); _bottomGrip->SetCursor(dc_arrow); _leftGrip->SetCursor(dc_arrow); _rightGrip->SetCursor(dc_arrow); _topLeftGrip->SetCursor(dc_arrow); _topRightGrip->SetCursor(dc_arrow); _bottomLeftGrip->SetCursor(dc_arrow); _bottomRightGrip->SetCursor(dc_arrow); _bottomRightGrip->SetPaintEnabled(false); _bottomRightGrip->SetPaintBackgroundEnabled(false); } #endif } //----------------------------------------------------------------------------- // Purpose: Bring the frame to the front and requests focus, ensures it's not minimized //----------------------------------------------------------------------------- void Frame::Activate() { MoveToFront(); if ( IsKeyBoardInputEnabled() ) { RequestFocus(); } SetVisible(true); SetEnabled(true); if (m_bFadingOut) { // we were fading out, make sure to fade back in m_bFadingOut = false; m_bPreviouslyVisible = false; } surface()->SetMinimized(GetVPanel(), false); } //----------------------------------------------------------------------------- // Sets up, cleans up modal dialogs //----------------------------------------------------------------------------- void Frame::DoModal( ) { // move to the middle of the screen MoveToCenterOfScreen(); InvalidateLayout(); Activate(); m_hPreviousModal = vgui::input()->GetAppModalSurface(); vgui::input()->SetAppModalSurface( GetVPanel() ); } //----------------------------------------------------------------------------- // Closes a modal dialog //----------------------------------------------------------------------------- void Frame::CloseModal() { vgui::input()->ReleaseAppModalSurface(); if ( m_hPreviousModal != 0 ) { vgui::input()->SetAppModalSurface( m_hPreviousModal ); m_hPreviousModal = 0; } PostMessage( this, new KeyValues("Close") ); } //----------------------------------------------------------------------------- // Purpose: activates the dialog // if dialog is not currently visible it starts it minimized and flashing in the taskbar //----------------------------------------------------------------------------- void Frame::ActivateMinimized() { if ( ( IsVisible() && !IsMinimized() ) || !surface()->SupportsFeature( ISurface::FRAME_MINIMIZE_MAXIMIZE ) ) { Activate(); } else { ipanel()->MoveToBack(GetVPanel()); surface()->SetMinimized(GetVPanel(), true); SetVisible(true); SetEnabled(true); if (m_bFadingOut) { // we were fading out, make sure to fade back in m_bFadingOut = false; m_bPreviouslyVisible = false; } FlashWindow(); } } //----------------------------------------------------------------------------- // Purpose: returns true if the dialog is currently minimized //----------------------------------------------------------------------------- bool Frame::IsMinimized() { return surface()->IsMinimized(GetVPanel()); } //----------------------------------------------------------------------------- // Purpose: Center the dialog on the screen //----------------------------------------------------------------------------- void Frame::MoveToCenterOfScreen() { int wx, wy, ww, wt; surface()->GetWorkspaceBounds(wx, wy, ww, wt); SetPos((ww - GetWide()) / 2, (wt - GetTall()) / 2); } void Frame::LayoutProportional( FrameButton *bt ) { float scale = 1.0; if( IsProportional() ) { int screenW, screenH; surface()->GetScreenSize( screenW, screenH ); int proW,proH; surface()->GetProportionalBase( proW, proH ); scale = ( (float)( screenH ) / (float)( proH ) ); } bt->SetSize( (int)( FrameButton::GetButtonSide( this ) * scale ), (int)( FrameButton::GetButtonSide( this ) * scale ) ); bt->SetTextInset( (int)( ceil( 2 * scale ) ), (int) ( ceil(1 * scale ) ) ); } //----------------------------------------------------------------------------- // Purpose: per-frame thinking, used for transition effects // only gets called if the Frame is visible //----------------------------------------------------------------------------- void Frame::OnThink() { BaseClass::OnThink(); // check for transition effects if (IsVisible() && m_flTransitionEffectTime > 0 && ( !m_bDisableFadeEffect )) { if (m_bFadingOut) { // we're fading out, see if we're done so we can fully hide the window if (GetAlpha() < ( IsX360() ? 64 : 1 )) { FinishClose(); } } else if (!m_bPreviouslyVisible) { // need to fade-in m_bPreviouslyVisible = true; // fade in if (IsX360()) { SetAlpha(64); } else { SetAlpha(0); } GetAnimationController()->RunAnimationCommand(this, "alpha", 255.0f, 0.0f, m_flTransitionEffectTime, AnimationController::INTERPOLATOR_LINEAR); } } // check for focus changes bool hasFocus = false; if (input()) { VPANEL focus = input()->GetFocus(); if (focus && ipanel()->HasParent(focus, GetVPanel())) { if ( input()->GetAppModalSurface() == 0 || input()->GetAppModalSurface() == GetVPanel() ) { hasFocus = true; } } } if (hasFocus != m_bHasFocus) { // Because vgui focus is message based, and focus gets reset to NULL when a focused panel is deleted, we defer the flashing/transition // animation for an extra frame in case something is deleted, a message is sent, and then we become the focused panel again on the // next frame if ( !m_bPrimed ) { m_bPrimed = true; return; } m_bPrimed = false; m_bHasFocus = hasFocus; OnFrameFocusChanged(m_bHasFocus); } else { m_bPrimed = false; } } //----------------------------------------------------------------------------- // Purpose: Called when the frame focus changes //----------------------------------------------------------------------------- void Frame::OnFrameFocusChanged(bool bHasFocus) { #if !defined( _X360 ) // enable/disable the frame buttons _minimizeButton->SetDisabledLook(!bHasFocus); _maximizeButton->SetDisabledLook(!bHasFocus); _closeButton->SetDisabledLook(!bHasFocus); _minimizeToSysTrayButton->SetDisabledLook(!bHasFocus); _menuButton->SetEnabled(bHasFocus); _minimizeButton->InvalidateLayout(); _maximizeButton->InvalidateLayout(); _minimizeToSysTrayButton->InvalidateLayout(); _closeButton->InvalidateLayout(); _menuButton->InvalidateLayout(); #endif if (bHasFocus) { _title->SetColor(_titleBarFgColor); } else { _title->SetColor(_titleBarDisabledFgColor); } // set our background color if (bHasFocus) { if (m_flFocusTransitionEffectTime && ( !m_bDisableFadeEffect )) { GetAnimationController()->RunAnimationCommand(this, "BgColor", m_InFocusBgColor, 0.0f, m_bDisableFadeEffect ? 0.0f : m_flTransitionEffectTime, AnimationController::INTERPOLATOR_LINEAR); } else { SetBgColor(m_InFocusBgColor); } } else { if (m_flFocusTransitionEffectTime && ( !m_bDisableFadeEffect )) { GetAnimationController()->RunAnimationCommand(this, "BgColor", m_OutOfFocusBgColor, 0.0f, m_bDisableFadeEffect ? 0.0f : m_flTransitionEffectTime, AnimationController::INTERPOLATOR_LINEAR); } else { SetBgColor(m_OutOfFocusBgColor); } } // Stop flashing when we get focus if (bHasFocus && _flashWindow) { FlashWindowStop(); } } int Frame::GetDraggerSize() { const int DRAGGER_SIZE = 5; if ( m_bSmallCaption ) { return 3; } return DRAGGER_SIZE; } int Frame::GetCornerSize() { const int CORNER_SIZE = 8; if ( m_bSmallCaption ) { return 6; } return CORNER_SIZE; } int Frame::GetBottomRightSize() { const int BOTTOMRIGHTSIZE = 18; if ( m_bSmallCaption ) { return 12; } return BOTTOMRIGHTSIZE; } int Frame::GetCaptionHeight() { const int CAPTIONHEIGHT = 23; if ( m_bSmallCaption ) { return 12; } return CAPTIONHEIGHT; } //----------------------------------------------------------------------------- // Purpose: Recalculate the position of all items //----------------------------------------------------------------------------- void Frame::PerformLayout() { // chain back BaseClass::PerformLayout(); // move everything into place int wide, tall; GetSize(wide, tall); #if !defined( _X360 ) int DRAGGER_SIZE = GetDraggerSize(); int CORNER_SIZE = GetCornerSize(); int CORNER_SIZE2 = CORNER_SIZE * 2; int BOTTOMRIGHTSIZE = GetBottomRightSize(); _topGrip->SetBounds(CORNER_SIZE, 0, wide - CORNER_SIZE2, DRAGGER_SIZE); _leftGrip->SetBounds(0, CORNER_SIZE, DRAGGER_SIZE, tall - CORNER_SIZE2); _topLeftGrip->SetBounds(0, 0, CORNER_SIZE, CORNER_SIZE); _topRightGrip->SetBounds(wide - CORNER_SIZE, 0, CORNER_SIZE, CORNER_SIZE); _bottomLeftGrip->SetBounds(0, tall - CORNER_SIZE, CORNER_SIZE, CORNER_SIZE); // make the bottom-right grip larger _bottomGrip->SetBounds(CORNER_SIZE, tall - DRAGGER_SIZE, wide - (CORNER_SIZE + BOTTOMRIGHTSIZE), DRAGGER_SIZE); _rightGrip->SetBounds(wide - DRAGGER_SIZE, CORNER_SIZE, DRAGGER_SIZE, tall - (CORNER_SIZE + BOTTOMRIGHTSIZE)); _bottomRightGrip->SetBounds(wide - BOTTOMRIGHTSIZE, tall - BOTTOMRIGHTSIZE, BOTTOMRIGHTSIZE, BOTTOMRIGHTSIZE); _captionGrip->SetSize(wide-10,GetCaptionHeight()); _topGrip->MoveToFront(); _bottomGrip->MoveToFront(); _leftGrip->MoveToFront(); _rightGrip->MoveToFront(); _topLeftGrip->MoveToFront(); _topRightGrip->MoveToFront(); _bottomLeftGrip->MoveToFront(); _bottomRightGrip->MoveToFront(); _maximizeButton->MoveToFront(); _menuButton->MoveToFront(); _minimizeButton->MoveToFront(); _minimizeToSysTrayButton->MoveToFront(); _menuButton->SetBounds(5+2, 5+3, GetCaptionHeight()-5, GetCaptionHeight()-5); #endif float scale = 1; if (IsProportional()) { int screenW, screenH; surface()->GetScreenSize( screenW, screenH ); int proW,proH; surface()->GetProportionalBase( proW, proH ); scale = ( (float)( screenH ) / (float)( proH ) ); } #if !defined( _X360 ) int offset_start = (int)( 20 * scale ); int offset = offset_start; int top_border_offset = (int) ( ( 5+3 ) * scale ); if ( m_bSmallCaption ) { top_border_offset = (int) ( ( 3 ) * scale ); } int side_border_offset = (int) ( 5 * scale ); // push the buttons against the east side if (_closeButton->IsVisible()) { _closeButton->SetPos((wide-side_border_offset)-offset,top_border_offset); offset += offset_start; LayoutProportional( _closeButton ); } if (_minimizeToSysTrayButton->IsVisible()) { _minimizeToSysTrayButton->SetPos((wide-side_border_offset)-offset,top_border_offset); offset += offset_start; LayoutProportional( _minimizeToSysTrayButton ); } if (_maximizeButton->IsVisible()) { _maximizeButton->SetPos((wide-side_border_offset)-offset,top_border_offset); offset += offset_start; LayoutProportional( _maximizeButton ); } if (_minimizeButton->IsVisible()) { _minimizeButton->SetPos((wide-side_border_offset)-offset,top_border_offset); offset += offset_start; LayoutProportional( _minimizeButton ); } #endif } //----------------------------------------------------------------------------- // Purpose: Set the text in the title bar. //----------------------------------------------------------------------------- void Frame::SetTitle(const char *title, bool surfaceTitle) { if (!_title) { _title = new TextImage( "" ); } Assert(title); _title->SetText(title); // see if the combobox text has changed, and if so, post a message detailing the new text const char *newTitle = title; // check if the new text is a localized string, if so undo it wchar_t unicodeText[128]; unicodeText[0] = 0; if (*newTitle == '#') { // try lookup in localization tables StringIndex_t unlocalizedTextSymbol = g_pVGuiLocalize->FindIndex(newTitle + 1); if (unlocalizedTextSymbol != INVALID_LOCALIZE_STRING_INDEX) { // we have a new text value wcsncpy( unicodeText, g_pVGuiLocalize->GetValueByIndex(unlocalizedTextSymbol), sizeof( unicodeText) / sizeof(wchar_t) ); } } else { g_pVGuiLocalize->ConvertANSIToUnicode( newTitle, unicodeText, sizeof(unicodeText) ); } if (surfaceTitle) { surface()->SetTitle(GetVPanel(), unicodeText); } Repaint(); } //----------------------------------------------------------------------------- // Purpose: Sets the unicode text in the title bar //----------------------------------------------------------------------------- void Frame::SetTitle(const wchar_t *title, bool surfaceTitle) { if (!_title) { _title = new TextImage( "" ); } _title->SetText(title); if (surfaceTitle) { surface()->SetTitle(GetVPanel(), title); } Repaint(); } //----------------------------------------------------------------------------- // Purpose: Set the text in the title bar. //----------------------------------------------------------------------------- void Frame::InternalSetTitle(const char *title) { SetTitle(title, true); } //----------------------------------------------------------------------------- // Purpose: Set the movability of the panel //----------------------------------------------------------------------------- void Frame::SetMoveable(bool state) { _moveable=state; } //----------------------------------------------------------------------------- // Purpose: Set the resizability of the panel //----------------------------------------------------------------------------- void Frame::SetSizeable(bool state) { _sizeable=state; SetupResizeCursors(); } // When moving via caption, don't let any part of window go outside parent's bounds void Frame::SetClipToParent( bool state ) { m_bClipToParent = state; } bool Frame::GetClipToParent() const { return m_bClipToParent; } //----------------------------------------------------------------------------- // Purpose: Check the movability of the panel //----------------------------------------------------------------------------- bool Frame::IsMoveable() { return _moveable; } //----------------------------------------------------------------------------- // Purpose: Check the resizability of the panel //----------------------------------------------------------------------------- bool Frame::IsSizeable() { return _sizeable; } //----------------------------------------------------------------------------- // Purpose: Get the size of the panel inside the frame edges. //----------------------------------------------------------------------------- void Frame::GetClientArea(int &x, int &y, int &wide, int &tall) { x = m_iClientInsetX; GetSize(wide, tall); if (_drawTitleBar) { int captionTall = surface()->GetFontTall(_title->GetFont()); int border = m_bSmallCaption ? CAPTION_TITLE_BORDER_SMALL : CAPTION_TITLE_BORDER; int yinset = m_bSmallCaption ? 0 : m_iClientInsetY; yinset += m_iTitleTextInsetYOverride; y = yinset + captionTall + border + 1; tall = (tall - yinset) - y; } if ( m_bSmallCaption ) { tall -= 5; } wide = (wide - m_iClientInsetX) - x; } // //----------------------------------------------------------------------------- // Purpose: applies user configuration settings //----------------------------------------------------------------------------- void Frame::ApplyUserConfigSettings(KeyValues *userConfig) { // calculate defaults int wx, wy, ww, wt; vgui::surface()->GetWorkspaceBounds(wx, wy, ww, wt); int x, y, wide, tall; GetBounds(x, y, wide, tall); bool bNoSettings = false; if (_moveable) { // check to see if anything is set if (!userConfig->FindKey("xpos", false)) { bNoSettings = true; } // get the user config position // default to where we're currently at x = userConfig->GetInt("xpos", x); y = userConfig->GetInt("ypos", y); } if (_sizeable) { wide = userConfig->GetInt("wide", wide); tall = userConfig->GetInt("tall", tall); // Make sure it's no larger than the workspace if ( wide > ww ) { wide = ww; } if ( tall > wt ) { tall = wt; } } // see if the dialog has a place on the screen it wants to start if (bNoSettings && GetDefaultScreenPosition(x, y, wide, tall)) { bNoSettings = false; } // make sure it conforms to the minimum size of the dialog int minWide, minTall; GetMinimumSize(minWide, minTall); if (wide < minWide) { wide = minWide; } if (tall < minTall) { tall = minTall; } // make sure it's on the screen if (x + wide > ww) { x = wx + ww - wide; } if (y + tall > wt) { y = wy + wt - tall; } if (x < wx) { x = wx; } if (y < wy) { y = wy; } SetBounds(x, y, wide, tall); if (bNoSettings) { // since nothing was set, default our position to the middle of the screen MoveToCenterOfScreen(); } BaseClass::ApplyUserConfigSettings(userConfig); } //----------------------------------------------------------------------------- // Purpose: returns user config settings for this control //----------------------------------------------------------------------------- void Frame::GetUserConfigSettings(KeyValues *userConfig) { if (_moveable) { int x, y; GetPos(x, y); userConfig->SetInt("xpos", x); userConfig->SetInt("ypos", y); } if (_sizeable) { int w, t; GetSize(w, t); userConfig->SetInt("wide", w); userConfig->SetInt("tall", t); } BaseClass::GetUserConfigSettings(userConfig); } //----------------------------------------------------------------------------- // Purpose: optimization, return true if this control has any user config settings //----------------------------------------------------------------------------- bool Frame::HasUserConfigSettings() { return true; } //----------------------------------------------------------------------------- // Purpose: gets the default position and size on the screen to appear the first time (defaults to centered) //----------------------------------------------------------------------------- bool Frame::GetDefaultScreenPosition(int &x, int &y, int &wide, int &tall) { return false; } //----------------------------------------------------------------------------- // Purpose: draws title bar //----------------------------------------------------------------------------- void Frame::PaintBackground() { // take the panel with focus and check up tree for this panel // if you find it, than some child of you has the focus, so // you should be focused Color titleColor = _titleBarDisabledBgColor; if (m_bHasFocus) { titleColor = _titleBarBgColor; } BaseClass::PaintBackground(); if (_drawTitleBar) { int wide = GetWide(); int tall = surface()->GetFontTall(_title->GetFont()); // caption surface()->DrawSetColor(titleColor); int inset = m_bSmallCaption ? 3 : 5; int captionHeight = m_bSmallCaption ? 14: 28; surface()->DrawFilledRect(inset, inset, wide - inset, captionHeight ); if (_title) { int nTitleX = m_iTitleTextInsetXOverride ? m_iTitleTextInsetXOverride : m_iTitleTextInsetX; int nTitleWidth = wide - 72; #if !defined( _X360 ) if ( _menuButton && _menuButton->IsVisible() ) { int mw, mh; _menuButton->GetImageSize( mw, mh ); nTitleX += mw; nTitleWidth -= mw; } #endif int nTitleY; if ( m_iTitleTextInsetYOverride ) { nTitleY = m_iTitleTextInsetYOverride; } else { nTitleY = m_bSmallCaption ? 2 : 9; } _title->SetPos( nTitleX, nTitleY ); _title->SetSize( nTitleWidth, tall); _title->Paint(); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Frame::ApplySchemeSettings(IScheme *pScheme) { // always chain back BaseClass::ApplySchemeSettings(pScheme); SetOverridableColor( &_titleBarFgColor, GetSchemeColor("FrameTitleBar.TextColor", pScheme) ); SetOverridableColor( &_titleBarBgColor, GetSchemeColor("FrameTitleBar.BgColor", pScheme) ); SetOverridableColor( &_titleBarDisabledFgColor, GetSchemeColor("FrameTitleBar.DisabledTextColor", pScheme) ); SetOverridableColor( &_titleBarDisabledBgColor, GetSchemeColor("FrameTitleBar.DisabledBgColor", pScheme) ); const char *font = NULL; if ( m_bSmallCaption ) { font = pScheme->GetResourceString("FrameTitleBar.SmallFont"); } else { font = pScheme->GetResourceString("FrameTitleBar.Font"); } HFont titlefont; if ( m_hCustomTitleFont ) { titlefont = m_hCustomTitleFont; } else { titlefont = pScheme->GetFont((font && *font) ? font : "Default", IsProportional()); } _title->SetFont( titlefont ); _title->ResizeImageToContent(); #if !defined( _X360 ) HFont marfont = (HFont)0; if ( m_bSmallCaption ) { marfont = pScheme->GetFont( "MarlettSmall", IsProportional() ); } else { marfont = pScheme->GetFont( "Marlett", IsProportional() ); } _minimizeButton->SetFont(marfont); _maximizeButton->SetFont(marfont); _minimizeToSysTrayButton->SetFont(marfont); _closeButton->SetFont(marfont); #endif m_flTransitionEffectTime = atof(pScheme->GetResourceString("Frame.TransitionEffectTime")); m_flFocusTransitionEffectTime = atof(pScheme->GetResourceString("Frame.FocusTransitionEffectTime")); SetOverridableColor( &m_InFocusBgColor, pScheme->GetColor("Frame.BgColor", GetBgColor()) ); SetOverridableColor( &m_OutOfFocusBgColor, pScheme->GetColor("Frame.OutOfFocusBgColor", m_InFocusBgColor) ); const char *resourceString = pScheme->GetResourceString("Frame.ClientInsetX"); if ( resourceString ) { m_iClientInsetX = atoi(resourceString); } resourceString = pScheme->GetResourceString("Frame.ClientInsetY"); if ( resourceString ) { m_iClientInsetY = atoi(resourceString); } resourceString = pScheme->GetResourceString("Frame.TitleTextInsetX"); if ( resourceString ) { m_iTitleTextInsetX = atoi(resourceString); } SetBgColor(m_InFocusBgColor); SetBorder(pScheme->GetBorder("FrameBorder")); OnFrameFocusChanged( m_bHasFocus ); } // Disables the fade-in/out-effect even if configured in the scheme settings void Frame::DisableFadeEffect( void ) { m_flFocusTransitionEffectTime = 0.f; m_flTransitionEffectTime = 0.f; } void Frame::SetFadeEffectDisableOverride( bool disabled ) { m_bDisableFadeEffect = disabled; } //----------------------------------------------------------------------------- // Purpose: Apply settings loaded from a resource file //----------------------------------------------------------------------------- void Frame::ApplySettings(KeyValues *inResourceData) { // Don't change the frame's visibility, remove that setting from the config data inResourceData->SetInt("visible", -1); BaseClass::ApplySettings(inResourceData); SetCloseButtonVisible( inResourceData->GetBool( "setclosebuttonvisible", true ) ); if( !inResourceData->GetInt("settitlebarvisible", 1 ) ) // if "title" is "0" then don't draw the title bar { SetTitleBarVisible( false ); } // set the title const char *title = inResourceData->GetString("title", ""); if (title && *title) { SetTitle(title, true); } const char *titlefont = inResourceData->GetString("title_font", ""); if ( titlefont && titlefont[0] ) { IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); if ( pScheme ) { m_hCustomTitleFont = pScheme->GetFont( titlefont ); } } KeyValues *pKV = inResourceData->FindKey( "clientinsetx_override", false ); if ( pKV ) { m_iClientInsetX = pKV->GetInt(); m_iClientInsetXOverridden = true; } } //----------------------------------------------------------------------------- // Purpose: Apply settings loaded from a resource file //----------------------------------------------------------------------------- void Frame::GetSettings(KeyValues *outResourceData) { BaseClass::GetSettings(outResourceData); outResourceData->SetInt("settitlebarvisible", _drawTitleBar ); if (_title) { char buf[256]; _title->GetUnlocalizedText( buf, 255 ); if (buf[0]) { outResourceData->SetString("title", buf); } } if ( m_iClientInsetXOverridden ) { outResourceData->SetInt( "clientinsetx_override", m_iClientInsetX ); } } //----------------------------------------------------------------------------- // Purpose: returns a description of the settings possible for a frame //----------------------------------------------------------------------------- const char *Frame::GetDescription() { static char buf[512]; Q_snprintf(buf, sizeof(buf), "%s, string title", BaseClass::GetDescription()); return buf; } //----------------------------------------------------------------------------- // Purpose: Go invisible when a close message is recieved. //----------------------------------------------------------------------------- void Frame::OnClose() { // if we're modal, release that before we hide the window else the wrong window will get focus if (input()->GetAppModalSurface() == GetVPanel()) { input()->ReleaseAppModalSurface(); if ( m_hPreviousModal != 0 ) { vgui::input()->SetAppModalSurface( m_hPreviousModal ); m_hPreviousModal = 0; } } BaseClass::OnClose(); if (m_flTransitionEffectTime && !m_bDisableFadeEffect) { // begin the hide transition effect GetAnimationController()->RunAnimationCommand(this, "alpha", 0.0f, 0.0f, m_flTransitionEffectTime, AnimationController::INTERPOLATOR_LINEAR); m_bFadingOut = true; // move us to the back of the draw order (so that fading out over the top of other dialogs doesn't look wierd) surface()->MovePopupToBack(GetVPanel()); } else { // hide us immediately FinishClose(); } } //----------------------------------------------------------------------------- // Purpose: Close button in frame pressed //----------------------------------------------------------------------------- void Frame::OnCloseFrameButtonPressed() { OnCommand("Close"); } //----------------------------------------------------------------------------- // Purpose: Command handling //----------------------------------------------------------------------------- void Frame::OnCommand(const char *command) { if (!stricmp(command, "Close")) { Close(); } else if (!stricmp(command, "CloseModal")) { CloseModal(); } else if (!stricmp(command, "Minimize")) { OnMinimize(); } else if (!stricmp(command, "MinimizeToSysTray")) { OnMinimizeToSysTray(); } else { BaseClass::OnCommand(command); } } //----------------------------------------------------------------------------- // Purpose: Get the system menu //----------------------------------------------------------------------------- Menu *Frame::GetSysMenu() { #if !defined( _X360 ) if (!_sysMenu) { _sysMenu = new Menu(this, NULL); _sysMenu->SetVisible(false); _sysMenu->AddActionSignalTarget(this); _sysMenu->AddMenuItem("Minimize", "#SysMenu_Minimize", "Minimize", this); _sysMenu->AddMenuItem("Maximize", "#SysMenu_Maximize", "Maximize", this); _sysMenu->AddMenuItem("Close", "#SysMenu_Close", "Close", this); // check for enabling/disabling menu items // this might have to be done at other times as well. Panel *menuItem = _sysMenu->FindChildByName("Minimize"); if (menuItem) { menuItem->SetEnabled(_minimizeButton->IsVisible()); } menuItem = _sysMenu->FindChildByName("Maximize"); if (menuItem) { menuItem->SetEnabled(_maximizeButton->IsVisible()); } menuItem = _sysMenu->FindChildByName("Close"); if (menuItem) { menuItem->SetEnabled(_closeButton->IsVisible()); } } return _sysMenu; #else return NULL; #endif } //----------------------------------------------------------------------------- // Purpose: Set the system menu //----------------------------------------------------------------------------- void Frame::SetSysMenu(Menu *menu) { #if !defined( _X360 ) if (menu == _sysMenu) return; _sysMenu->MarkForDeletion(); _sysMenu = menu; _menuButton->SetMenu(_sysMenu); #endif } //----------------------------------------------------------------------------- // Set the system menu images //----------------------------------------------------------------------------- void Frame::SetImages( const char *pEnabledImage, const char *pDisabledImage ) { #if !defined( _X360 ) _menuButton->SetImages( pEnabledImage, pDisabledImage ); #endif } //----------------------------------------------------------------------------- // Purpose: Close the window //----------------------------------------------------------------------------- void Frame::Close() { OnClose(); } //----------------------------------------------------------------------------- // Purpose: Finishes closing the dialog //----------------------------------------------------------------------------- void Frame::FinishClose() { SetVisible(false); m_bPreviouslyVisible = false; m_bFadingOut = false; OnFinishedClose(); if (m_bDeleteSelfOnClose) { // Must be last because if vgui is not running then this will call delete this!!! MarkForDeletion(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void Frame::OnFinishedClose() { } //----------------------------------------------------------------------------- // Purpose: Minimize the window on the taskbar. //----------------------------------------------------------------------------- void Frame::OnMinimize() { surface()->SetMinimized(GetVPanel(), true); } //----------------------------------------------------------------------------- // Purpose: Does nothing by default //----------------------------------------------------------------------------- void Frame::OnMinimizeToSysTray() { } //----------------------------------------------------------------------------- // Purpose: Respond to mouse presses //----------------------------------------------------------------------------- void Frame::OnMousePressed(MouseCode code) { if (!IsBuildGroupEnabled()) { // if a child doesn't have focus, get it for ourselves VPANEL focus = input()->GetFocus(); if (!focus || !ipanel()->HasParent(focus, GetVPanel())) { RequestFocus(); } } BaseClass::OnMousePressed(code); } //----------------------------------------------------------------------------- // Purpose: Toggle visibility of the system menu button //----------------------------------------------------------------------------- void Frame::SetMenuButtonVisible(bool state) { #if !defined( _X360 ) _menuButton->SetVisible(state); #endif } //----------------------------------------------------------------------------- // Purpose: Toggle respond of the system menu button // it will look enabled or disabled in response to the title bar // but may not activate. //----------------------------------------------------------------------------- void Frame::SetMenuButtonResponsive(bool state) { #if !defined( _X360 ) _menuButton->SetResponsive(state); #endif } //----------------------------------------------------------------------------- // Purpose: Toggle visibility of the minimize button //----------------------------------------------------------------------------- void Frame::SetMinimizeButtonVisible(bool state) { #if !defined( _X360 ) _minimizeButton->SetVisible(state); #endif } //----------------------------------------------------------------------------- // Purpose: Toggle visibility of the maximize button //----------------------------------------------------------------------------- void Frame::SetMaximizeButtonVisible(bool state) { #if !defined( _X360 ) _maximizeButton->SetVisible(state); #endif } //----------------------------------------------------------------------------- // Purpose: Toggles visibility of the minimize-to-systray icon (defaults to false) //----------------------------------------------------------------------------- void Frame::SetMinimizeToSysTrayButtonVisible(bool state) { #if !defined( _X360 ) _minimizeToSysTrayButton->SetVisible(state); #endif } //----------------------------------------------------------------------------- // Purpose: Toggle visibility of the close button //----------------------------------------------------------------------------- void Frame::SetCloseButtonVisible(bool state) { #if !defined( _X360 ) _closeButton->SetVisible(state); #endif } //----------------------------------------------------------------------------- // Purpose: soaks up any remaining messages //----------------------------------------------------------------------------- void Frame::OnKeyCodeReleased(KeyCode code) { } //----------------------------------------------------------------------------- // Purpose: soaks up any remaining messages //----------------------------------------------------------------------------- void Frame::OnKeyFocusTicked() { } //----------------------------------------------------------------------------- // Purpose: Toggles window flash state on a timer //----------------------------------------------------------------------------- void Frame::InternalFlashWindow() { if (_flashWindow) { // toggle icon flashing _nextFlashState = true; surface()->FlashWindow(GetVPanel(), _nextFlashState); _nextFlashState = !_nextFlashState; PostMessage(this, new KeyValues("FlashWindow"), 1.8f); } } //----------------------------------------------------------------------------- // Purpose: Adds the child to the focus nav group //----------------------------------------------------------------------------- void Frame::OnChildAdded(VPANEL child) { BaseClass::OnChildAdded(child); } //----------------------------------------------------------------------------- // Purpose: Flash the window system tray button until the frame gets focus //----------------------------------------------------------------------------- void Frame::FlashWindow() { _flashWindow = true; _nextFlashState = true; InternalFlashWindow(); } //----------------------------------------------------------------------------- // Purpose: Stops any window flashing //----------------------------------------------------------------------------- void Frame::FlashWindowStop() { surface()->FlashWindow(GetVPanel(), false); _flashWindow = false; } //----------------------------------------------------------------------------- // Purpose: load the control settings - should be done after all the children are added to the dialog //----------------------------------------------------------------------------- void Frame::LoadControlSettings( const char *dialogResourceName, const char *pathID, KeyValues *pPreloadedKeyValues, KeyValues *pConditions ) { BaseClass::LoadControlSettings( dialogResourceName, pathID, pPreloadedKeyValues, pConditions ); // set the focus on the default control Panel *defaultFocus = GetFocusNavGroup().GetDefaultPanel(); if (defaultFocus) { defaultFocus->RequestFocus(); } } //----------------------------------------------------------------------------- // Purpose: Checks for ctrl+shift+b hits to enter build mode // Activates any hotkeys / default buttons // Swallows any unhandled input //----------------------------------------------------------------------------- void Frame::OnKeyCodeTyped(KeyCode code) { bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT)); bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL)); bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT)); if ( IsX360() ) { vgui::Panel *pMap = FindChildByName( "ControllerMap" ); if ( pMap && pMap->IsKeyBoardInputEnabled() ) { pMap->OnKeyCodeTyped( code ); return; } } if ( ctrl && shift && alt && code == KEY_B) { // enable build mode ActivateBuildMode(); } else if (ctrl && shift && alt && code == KEY_R) { // reload the scheme VPANEL top = surface()->GetEmbeddedPanel(); if (top) { // reload the data file scheme()->ReloadSchemes(); Panel *panel = ipanel()->GetPanel(top, GetModuleName()); if (panel) { // make the top-level panel reload it's scheme, it will chain down to all the child panels panel->InvalidateLayout(false, true); } } } else if (alt && code == KEY_F4) { // user has hit the close PostMessage(this, new KeyValues("CloseFrameButtonPressed")); } else if (code == KEY_ENTER) { // check for a default button VPANEL panel = GetFocusNavGroup().GetCurrentDefaultButton(); if (panel && ipanel()->IsVisible( panel ) && ipanel()->IsEnabled( panel )) { // Activate the button PostMessage(panel, new KeyValues("Hotkey")); } } else if ( code == KEY_ESCAPE && surface()->SupportsFeature(ISurface::ESCAPE_KEY) && input()->GetAppModalSurface() == GetVPanel() ) { // ESC cancels, unless we're in the engine - in the engine ESC flips between the UI and the game CloseModal(); } // Usually don't chain back as Frames are the end of the line for key presses, unless // m_bChainKeysToParent is set else if ( m_bChainKeysToParent ) { BaseClass::OnKeyCodeTyped( code ); } else { input()->OnKeyCodeUnhandled( (int)code ); } } //----------------------------------------------------------------------------- // Purpose: If true, then OnKeyCodeTyped messages continue up past the Frame // Input : state - //----------------------------------------------------------------------------- void Frame::SetChainKeysToParent( bool state ) { m_bChainKeysToParent = state; } //----------------------------------------------------------------------------- // Purpose: If true, then OnKeyCodeTyped messages continue up past the Frame // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Frame::CanChainKeysToParent() const { return m_bChainKeysToParent; } //----------------------------------------------------------------------------- // Purpose: Checks for ctrl+shift+b hits to enter build mode // Activates any hotkeys / default buttons // Swallows any unhandled input //----------------------------------------------------------------------------- void Frame::OnKeyTyped(wchar_t unichar) { Panel *panel = GetFocusNavGroup().FindPanelByHotkey(unichar); if (panel) { // tell the panel to Activate PostMessage(panel, new KeyValues("Hotkey")); } } //----------------------------------------------------------------------------- // Purpose: sets all title bar controls //----------------------------------------------------------------------------- void Frame::SetTitleBarVisible( bool state ) { _drawTitleBar = state; SetMenuButtonVisible(state); SetMinimizeButtonVisible(state); SetMaximizeButtonVisible(state); SetCloseButtonVisible(state); } //----------------------------------------------------------------------------- // Purpose: sets the frame to delete itself on close //----------------------------------------------------------------------------- void Frame::SetDeleteSelfOnClose( bool state ) { m_bDeleteSelfOnClose = state; } //----------------------------------------------------------------------------- // Purpose: updates localized text //----------------------------------------------------------------------------- void Frame::OnDialogVariablesChanged( KeyValues *dialogVariables ) { StringIndex_t index = _title->GetUnlocalizedTextSymbol(); if (index != INVALID_LOCALIZE_STRING_INDEX) { // reconstruct the string from the variables wchar_t buf[1024]; g_pVGuiLocalize->ConstructString(buf, sizeof(buf), index, dialogVariables); SetTitle(buf, true); } } //----------------------------------------------------------------------------- // Purpose: Handles staying on screen when the screen size changes //----------------------------------------------------------------------------- void Frame::OnScreenSizeChanged(int iOldWide, int iOldTall) { BaseClass::OnScreenSizeChanged(iOldWide, iOldTall); if (IsProportional()) return; // make sure we're completely on screen int iNewWide, iNewTall; surface()->GetScreenSize(iNewWide, iNewTall); int x, y, wide, tall; GetBounds(x, y, wide, tall); // make sure the bottom-right corner is on the screen first if (x + wide > iNewWide) { x = iNewWide - wide; } if (y + tall > iNewTall) { y = iNewTall - tall; } // make sure the top-left is visible x = max( 0, x ); y = max( 0, y ); // apply SetPos(x, y); } //----------------------------------------------------------------------------- // Purpose: For supporting thin caption bars // Input : state - //----------------------------------------------------------------------------- void Frame::SetSmallCaption( bool state ) { m_bSmallCaption = state; InvalidateLayout(); } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool Frame::IsSmallCaption() const { return m_bSmallCaption; } //----------------------------------------------------------------------------- // Purpose: Static method to place a frame under the cursor //----------------------------------------------------------------------------- void Frame::PlaceUnderCursor( ) { // get cursor position, this is local to this text edit window int cursorX, cursorY; input()->GetCursorPos( cursorX, cursorY ); // relayout the menu immediately so that we know it's size InvalidateLayout(true); int w, h; GetSize( w, h ); // work out where the cursor is and therefore the best place to put the frame int sw, sh; surface()->GetScreenSize( sw, sh ); // Try to center it first int x, y; x = cursorX - ( w / 2 ); y = cursorY - ( h / 2 ); // Clamp to various sides if ( x + w > sw ) { x = sw - w; } if ( y + h > sh ) { y = sh - h; } if ( x < 0 ) { x = 0; } if ( y < 0 ) { y = 0; } SetPos( x, y ); }