summaryrefslogtreecommitdiff
path: root/vgui2/src/VPanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vgui2/src/VPanel.cpp')
-rw-r--r--vgui2/src/VPanel.cpp782
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;
+}