diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vgui2/src/VPanel.cpp | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'vgui2/src/VPanel.cpp')
| -rw-r--r-- | vgui2/src/VPanel.cpp | 782 |
1 files changed, 782 insertions, 0 deletions
diff --git a/vgui2/src/VPanel.cpp b/vgui2/src/VPanel.cpp new file mode 100644 index 0000000..dcdfb81 --- /dev/null +++ b/vgui2/src/VPanel.cpp @@ -0,0 +1,782 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include <stdio.h> + +#include <vgui/IPanel.h> +#include <vgui/IClientPanel.h> +#include <vgui/ISurface.h> +#include <vgui/IVGui.h> +#include <vgui/Cursor.h> + +#include "vgui_internal.h" +#include "VPanel.h" + +#include "tier0/minidump.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + + +// Lame copy from Panel +enum PinCorner_e +{ + PIN_TOPLEFT = 0, + PIN_TOPRIGHT, + PIN_BOTTOMLEFT, + PIN_BOTTOMRIGHT, + + // For sibling pinning + PIN_CENTER_TOP, + PIN_CENTER_RIGHT, + PIN_CENTER_BOTTOM, + PIN_CENTER_LEFT, + + NUM_PIN_POINTS, +}; + +float PinDeltas[NUM_PIN_POINTS][2] = +{ + { 0, 0 }, // PIN_TOPLEFT, + { 1, 0 }, // PIN_TOPRIGHT, + { 0, 1 }, // PIN_BOTTOMLEFT, + { 1, 1 }, // PIN_BOTTOMRIGHT, + { 0.5, 0 }, // PIN_CENTER_TOP, + { 1, 0.5 }, // PIN_CENTER_RIGHT, + { 0.5, 1 }, // PIN_CENTER_BOTTOM, + { 0, 0.5 }, // PIN_CENTER_LEFT, +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +VPanel::VPanel() +{ + _pos[0] = _pos[1] = 0; + _absPos[0] = _absPos[1] = 0; + _size[0] = _size[1] = 0; + + _minimumSize[0] = 0; + _minimumSize[1] = 0; + + _zpos = 0; + + _inset[0] = _inset[1] = _inset[2] = _inset[3] = 0; + _clipRect[0] = _clipRect[1] = _clipRect[2] = _clipRect[3] = 0; + + _visible = true; + _enabled = true; + _clientPanel = NULL; + _parent = NULL; + _plat = NULL; + _popup = false; + _isTopmostPopup = false; + _hPanel = INVALID_PANEL; + + _mouseInput = true; // by default you want mouse and kb input to this panel + _kbInput = true; + + _pinsibling = NULL; + _pinsibling_my_corner = PIN_TOPLEFT; + _pinsibling_their_corner = PIN_TOPLEFT; + + m_nThinkTraverseLevel = 0; + _clientPanelHandle = vgui::INVALID_PANEL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +VPanel::~VPanel() +{ + // Someone just deleted their parent Panel while it was being used in InternalSolveTraverse(). + // This will cause a difficult to debug crash, so we spew out the panel name here in hopes + // it will help track down the offender. + if ( m_nThinkTraverseLevel != 0 ) + { + Warning( "Deleting in-use vpanel: %s/%s %p.\n", GetName(), GetClassName(), this ); +#ifdef STAGING_ONLY + DebuggerBreak(); +#endif + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::TraverseLevel( int val ) +{ + // Bump up our traverse level. + m_nThinkTraverseLevel += m_nThinkTraverseLevel; + + // Bump up our client panel traverse level. + if ( Client() ) + { + VPANEL vp = g_pVGui->HandleToPanel( _clientPanelHandle ); + if ( vp == vgui::INVALID_PANEL ) + { + // This is really bad - we have a Client() pointer that is invalid. + Warning( "Panel '%s/%s' has invalid client: %p.\n", GetName(), GetClassName(), Client() ); +#ifdef STAGING_ONLY + DebuggerBreak(); +#endif + } + + if ( Client()->GetVPanel() ) + { + VPanel *vpanel = (VPanel *)Client()->GetVPanel(); + vpanel->m_nThinkTraverseLevel += vpanel->m_nThinkTraverseLevel; + } + } + + // This doesn't work. It appears we add all kinds of children to various panels in the + // InternalThinkTraverse functions, and that means the refcount is 0 when added, and + // then drops to -1 when we decrement the traverse level. +#if 0 + // Bump up our children traverse levels. + CUtlVector< VPanel * > &children = GetChildren(); + for ( int i = 0; i < children.Count(); ++i ) + { + VPanel *child = children[ i ]; + if ( child ) + child->m_nThinkTraverseLevel = Max( child->m_nThinkTraverseLevel + val, 0 ); + } +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::Init(IClientPanel *attachedClientPanel) +{ + _clientPanel = attachedClientPanel; + _clientPanelHandle = g_pVGui->PanelToHandle( attachedClientPanel ? attachedClientPanel->GetVPanel() : 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::Solve() +{ + short basePos[2]; + basePos[0] = _pos[0]; + basePos[1] = _pos[1]; + + int baseSize[2]; + GetSize( baseSize[0], baseSize[1] ); + + VPanel *parent = GetParent(); + if (IsPopup()) + { + // if we're a popup, draw at the highest level + parent = (VPanel *)g_pSurface->GetEmbeddedPanel(); + } + + int pabs[2]; + if ( parent ) + { + parent->GetAbsPos(pabs[0], pabs[1]); + } + + if ( _pinsibling ) + { + _pinsibling->Solve(); + + int sibPos[2]; + int sibSize[2]; + _pinsibling->GetInternalAbsPos( sibPos[0], sibPos[1] ); + _pinsibling->GetSize( sibSize[0], sibSize[1] ); + + for ( int i = 0; i < 2; i++ ) + { + if ( parent ) + { + sibPos[i] -= pabs[i]; + } + + // Determine which direction positive values move in. For center pins, we use screen relative signs. + int iSign = 1; + if ( i == 0 && (_pinsibling_their_corner == PIN_CENTER_LEFT || _pinsibling_their_corner == PIN_TOPLEFT || _pinsibling_their_corner == PIN_BOTTOMLEFT) ) + { + iSign = -1; + } + else if ( i == 1 && (_pinsibling_their_corner == PIN_CENTER_TOP || _pinsibling_their_corner == PIN_TOPLEFT || _pinsibling_their_corner == PIN_TOPRIGHT) ) + { + iSign = -1; + } + + int iPos = sibPos[i] + (sibSize[i] * PinDeltas[_pinsibling_their_corner][i]); + iPos -= (baseSize[i] * PinDeltas[_pinsibling_my_corner][i]); + iPos += basePos[i] * iSign; + + basePos[i] = iPos; + } + } + + int absX = basePos[0]; + int absY = basePos[1]; + _absPos[0] = basePos[0]; + _absPos[1] = basePos[1]; + + // put into parent space + int pinset[4] = {0, 0, 0, 0}; + if ( parent ) + { + parent->GetInset( pinset[0], pinset[1], pinset[2], pinset[3] ); + + absX += pabs[0] + pinset[0]; + absY += pabs[1] + pinset[1]; + + _absPos[0] = clamp( absX, -32767, 32767 ); + _absPos[1] = clamp( absY, -32767, 32767 ); + } + + // set initial bounds + _clipRect[0] = _absPos[0]; + _clipRect[1] = _absPos[1]; + + int absX2 = absX + baseSize[0]; + int absY2 = absY + baseSize[1]; + _clipRect[2] = clamp( absX2, -32767, 32767 ); + _clipRect[3] = clamp( absY2, -32767, 32767 ); + + // clip to parent, if we're not a popup + if ( parent && !IsPopup() ) + { + int pclip[4]; + parent->GetClipRect(pclip[0], pclip[1], pclip[2], pclip[3]); + + if (_clipRect[0] < pclip[0]) + { + _clipRect[0] = pclip[0]; + } + + if (_clipRect[1] < pclip[1]) + { + _clipRect[1] = pclip[1]; + } + + if(_clipRect[2] > pclip[2]) + { + _clipRect[2] = pclip[2] - pinset[2]; + } + + if(_clipRect[3] > pclip[3]) + { + _clipRect[3] = pclip[3] - pinset[3]; + } + + if ( _clipRect[0] > _clipRect[2] ) + { + _clipRect[2] = _clipRect[0]; + } + + if ( _clipRect[1] > _clipRect[3] ) + { + _clipRect[3] = _clipRect[1]; + } + } + + Assert( _clipRect[0] <= _clipRect[2] ); + Assert( _clipRect[1] <= _clipRect[3] ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::SetPos(int x, int y) +{ + _pos[0] = x; + _pos[1] = y; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::GetPos(int &x, int &y) +{ + x = _pos[0]; + y = _pos[1]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::SetSize(int wide,int tall) +{ + if (wide<_minimumSize[0]) + { + wide=_minimumSize[0]; + } + if (tall<_minimumSize[1]) + { + tall=_minimumSize[1]; + } + + if (_size[0] == wide && _size[1] == tall) + return; + + _size[0]=wide; + _size[1]=tall; + + Client()->OnSizeChanged(wide, tall); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::GetSize(int& wide,int& tall) +{ + wide=_size[0]; + tall=_size[1]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::SetMinimumSize(int wide,int tall) +{ + _minimumSize[0]=wide; + _minimumSize[1]=tall; + + // check if we're currently smaller than the new minimum size + int currentWidth = _size[0]; + if (currentWidth < wide) + { + currentWidth = wide; + } + int currentHeight = _size[1]; + if (currentHeight < tall) + { + currentHeight = tall; + } + + // resize to new minimum size if necessary + if (currentWidth != _size[0] || currentHeight != _size[1]) + { + SetSize(currentWidth, currentHeight); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::GetMinimumSize(int &wide, int &tall) +{ + wide = _minimumSize[0]; + tall = _minimumSize[1]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::SetVisible(bool state) +{ + if (_visible == state) + return; + + // need to tell the surface (in case special window processing needs to occur) + g_pSurface->SetPanelVisible((VPANEL)this, state); + + _visible = state; + + if( IsPopup() ) + { + vgui::g_pSurface->CalculateMouseVisible(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::SetEnabled(bool state) +{ + _enabled = state; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool VPanel::IsVisible() +{ + return _visible; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool VPanel::IsEnabled() +{ + return _enabled; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::GetAbsPos(int &x, int &y) +{ + x = _absPos[0]; + y = _absPos[1]; + + g_pSurface->OffsetAbsPos( x, y ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::GetInternalAbsPos(int &x, int &y) +{ + x = _absPos[0]; + y = _absPos[1]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::GetClipRect(int &x0, int &y0, int &x1, int &y1) +{ + x0 = _clipRect[0]; + y0 = _clipRect[1]; + x1 = _clipRect[2]; + y1 = _clipRect[3]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::SetInset(int left, int top, int right, int bottom) +{ + _inset[0] = left; + _inset[1] = top; + _inset[2] = right; + _inset[3] = bottom; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::GetInset(int &left, int &top, int &right, int &bottom) +{ + left = _inset[0]; + top = _inset[1]; + right = _inset[2]; + bottom = _inset[3]; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void VPanel::SetParent(VPanel *newParent) +{ + if (this == newParent) + return; + + if (_parent == newParent) + return; + + if (_parent != NULL) + { + _parent->_childDar.RemoveElement(this); + _parent = null; + } + + if (newParent != NULL) + { + _parent = newParent; + _parent->_childDar.PutElement(this); + SetZPos(_zpos); // re-sort parent's panel order if necessary + if (_parent->Client()) + { + _parent->Client()->OnChildAdded((VPANEL)this); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int VPanel::GetChildCount() +{ + return _childDar.GetCount(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +VPanel *VPanel::GetChild(int index) +{ + return _childDar[index]; +} + +CUtlVector< VPanel *> &VPanel::GetChildren() +{ + return _childDar; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +VPanel *VPanel::GetParent() +{ + return _parent; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the Z position of a panel and reorders it appropriately +//----------------------------------------------------------------------------- +void VPanel::SetZPos(int z) +{ + _zpos = z; + + if (_parent) + { + // find the child in the list + int childCount = _parent->GetChildCount(); + int i; + for (i = 0; i < childCount; i++) + { + if (_parent->GetChild(i) == this) + break; + } + + if (i == childCount) + return; + + while (1) + { + VPanel *prevChild = NULL, *nextChild = NULL; + + if ( i > 0 ) + { + prevChild = _parent->GetChild( i - 1 ); + } + if ( i <(childCount - 1) ) + { + nextChild = _parent->GetChild( i + 1 ); + } + + // check either side of the child to see if it should move + if ( i > 0 && prevChild && ( prevChild->_zpos > _zpos ) ) + { + // swap with the lower + _parent->_childDar.SetElementAt(prevChild, i); + _parent->_childDar.SetElementAt(this, i - 1); + i--; + } + else if (i < (childCount - 1) && nextChild && ( nextChild->_zpos < _zpos ) ) + { + // swap with the higher + _parent->_childDar.SetElementAt(nextChild, i); + _parent->_childDar.SetElementAt(this, i + 1); + i++; + } + else + { + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: returns the z position of this panel +//----------------------------------------------------------------------------- +int VPanel::GetZPos() +{ + return _zpos; +} + +//----------------------------------------------------------------------------- +// Purpose: Moves the panel to the front of the z-order +//----------------------------------------------------------------------------- +void VPanel::MoveToFront(void) +{ + g_pSurface->MovePopupToFront((VPANEL)this); + + if (_parent) + { + // move this panel to the end of it's parents list + _parent->_childDar.MoveElementToEnd(this); + + // Validate the Z order + int i = _parent->_childDar.GetCount() - 2; + while (i >= 0) + { + if (_parent->_childDar[i]->_zpos > _zpos) + { + // we can't be in front of this; swap positions + _parent->_childDar.SetElementAt(_parent->_childDar[i], i + 1); + _parent->_childDar.SetElementAt(this, i); + + // check the next value + i--; + } + else + { + // order valid + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Moves the panel to the back of the z-order +//----------------------------------------------------------------------------- +void VPanel::MoveToBack() +{ + if (_parent) + { + // move this panel to the end of it's parents list + _parent->_childDar.RemoveElement(this); + _parent->_childDar.InsertElementAt(this, 0); + + // Validate the Z order + int i = 1; + while (i < _parent->_childDar.GetCount()) + { + if (_parent->_childDar[i]->_zpos < _zpos) + { + // we can't be behind this; swap positions + _parent->_childDar.SetElementAt(_parent->_childDar[i], i - 1); + _parent->_childDar.SetElementAt(this, i); + + // check the next value + i++; + } + else + { + // order valid + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Iterates up the hierarchy looking to see if a panel has the specified ancestor +//----------------------------------------------------------------------------- +bool VPanel::HasParent(VPanel *potentialParent) +{ + if (this == potentialParent) + return true; + + if (_parent) + { + return _parent->HasParent(potentialParent); + } + + return false; +} + +SurfacePlat *VPanel::Plat() +{ + return _plat; +} + +void VPanel::SetPlat(SurfacePlat *Plat) +{ + _plat = Plat; +} + +bool VPanel::IsPopup() +{ + return _popup; +} + +void VPanel::SetPopup(bool state) +{ + _popup = state; +} + +bool VPanel::IsTopmostPopup() const +{ + return _isTopmostPopup; +} + +void VPanel::SetTopmostPopup( bool bEnable ) +{ + _isTopmostPopup = bEnable; +} + +bool VPanel::IsFullyVisible() +{ + // recursively check to see if the panel and all it's parents are visible + VPanel *panel = this; + while (panel) + { + if (!panel->_visible) + { + return false; + } + + panel = panel->_parent; + } + + // we're visible all the way up the hierarchy + return true; +} + +const char *VPanel::GetName() +{ + return Client()->GetName(); +} + +const char *VPanel::GetClassName() +{ + return Client()->GetClassName(); +} + +HScheme VPanel::GetScheme() +{ + return Client()->GetScheme(); +} + + +void VPanel::SendMessage(KeyValues *params, VPANEL ifrompanel) +{ + Client()->OnMessage(params, ifrompanel); +} + + +void VPanel::SetKeyBoardInputEnabled(bool state) +{ + _kbInput = state; +} + +void VPanel::SetMouseInputEnabled(bool state) +{ + _mouseInput = state; +} + +bool VPanel::IsKeyBoardInputEnabled() +{ + return _kbInput; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool VPanel::IsMouseInputEnabled() +{ + return _mouseInput; +} + +//----------------------------------------------------------------------------- +// Purpose: sibling pins +//----------------------------------------------------------------------------- +void VPanel::SetSiblingPin(VPanel *newSibling, byte iMyCornerToPin, byte iSiblingCornerToPinTo ) +{ + _pinsibling = newSibling; + _pinsibling_my_corner = iMyCornerToPin; + _pinsibling_their_corner = iSiblingCornerToPinTo; +} |