aboutsummaryrefslogtreecommitdiff
path: root/mp/src/vgui2/vgui_controls/Splitter.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/vgui2/vgui_controls/Splitter.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/vgui2/vgui_controls/Splitter.cpp')
-rw-r--r--mp/src/vgui2/vgui_controls/Splitter.cpp1530
1 files changed, 765 insertions, 765 deletions
diff --git a/mp/src/vgui2/vgui_controls/Splitter.cpp b/mp/src/vgui2/vgui_controls/Splitter.cpp
index fc127a38..96bde986 100644
--- a/mp/src/vgui2/vgui_controls/Splitter.cpp
+++ b/mp/src/vgui2/vgui_controls/Splitter.cpp
@@ -1,765 +1,765 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//===========================================================================//
-
-#include <vgui/IScheme.h>
-#include <vgui/Cursor.h>
-#include <vgui/IInput.h>
-#include <vgui_controls/Splitter.h>
-#include "tier1/KeyValues.h"
-#include <limits.h>
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-using namespace vgui;
-
-
-enum
-{
- SPLITTER_HANDLE_WIDTH = 4
-};
-
-
-//-----------------------------------------------------------------------------
-// Splitter handle
-//-----------------------------------------------------------------------------
-namespace vgui
-{
-
-class SplitterHandle : public Panel
-{
- DECLARE_CLASS_SIMPLE( SplitterHandle, Panel );
-
-public:
- SplitterHandle( Splitter *parent, const char *name, SplitterMode_t mode, int nIndex );
- ~SplitterHandle();
-
- virtual void ApplySchemeSettings( IScheme *pScheme );
- virtual void OnMousePressed( MouseCode code );
- virtual void OnMouseReleased( MouseCode code );
- virtual void OnCursorMoved( int x, int y );
- virtual void OnMouseDoublePressed( MouseCode code );
-
-private:
- SplitterMode_t m_nMode;
- int m_nIndex;
- bool m_bDragging;
-};
-
-} // end namespace vgui
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-//-----------------------------------------------------------------------------
-SplitterHandle::SplitterHandle( Splitter *parent, const char *name, SplitterMode_t mode, int nIndex ) : BaseClass( parent, name )
-{
- int w, h;
- parent->GetSize( w, h );
-
- if ( mode == SPLITTER_MODE_HORIZONTAL )
- {
- SetSize( w, SPLITTER_HANDLE_WIDTH );
- SetCursor( dc_sizens );
- }
- else
- {
- SetSize( SPLITTER_HANDLE_WIDTH, h );
- SetCursor( dc_sizewe );
- }
-
- SetVisible( true );
- SetPaintBackgroundEnabled( false );
- SetPaintEnabled( false );
- SetPaintBorderEnabled( true );
- m_bDragging = false;
- m_nIndex = nIndex;
- m_nMode = mode;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor
-//-----------------------------------------------------------------------------
-SplitterHandle::~SplitterHandle()
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// Scheme settings
-//-----------------------------------------------------------------------------
-void SplitterHandle::ApplySchemeSettings(IScheme *pScheme)
-{
- // Cache off background color stored in SetSplitterColor
- Color c = GetBgColor();
- SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
- BaseClass::ApplySchemeSettings(pScheme);
- SetBgColor( c );
-}
-
-
-//-----------------------------------------------------------------------------
-// Capture mouse when dragging
-//-----------------------------------------------------------------------------
-void SplitterHandle::OnMousePressed(MouseCode code)
-{
- if ( !m_bDragging )
- {
- input()->SetMouseCapture(GetVPanel());
- m_bDragging = true;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Release mouse capture when finished dragging
-//-----------------------------------------------------------------------------
-void SplitterHandle::OnMouseReleased(MouseCode code)
-{
- if ( m_bDragging )
- {
- input()->SetMouseCapture(NULL);
- m_bDragging = false;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// While dragging, update the splitter position
-//-----------------------------------------------------------------------------
-void SplitterHandle::OnCursorMoved(int x, int y)
-{
- if (m_bDragging)
- {
- input()->GetCursorPos( x, y );
- Splitter *pSplitter = assert_cast<Splitter*>( GetParent() );
- pSplitter->ScreenToLocal( x,y );
- pSplitter->SetSplitterPosition( m_nIndex, (m_nMode == SPLITTER_MODE_HORIZONTAL) ? y : x );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Double-click: make both panels on either side of the splitter equal size
-//-----------------------------------------------------------------------------
-void SplitterHandle::OnMouseDoublePressed( MouseCode code )
-{
- Splitter *pSplitter = assert_cast<Splitter*>( GetParent() );
- pSplitter->EvenlyRespaceSplitters();
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Returns a panel that chains user configs
-//-----------------------------------------------------------------------------
-namespace vgui
-{
-
-class SplitterChildPanel : public EditablePanel
-{
- DECLARE_CLASS_SIMPLE( SplitterChildPanel, EditablePanel );
-
-public:
- SplitterChildPanel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
- {
- SetPaintBackgroundEnabled( false );
- SetPaintEnabled( false );
- SetPaintBorderEnabled( false );
- }
-
- virtual ~SplitterChildPanel() {}
-
- // Children may have user config settings
- bool HasUserConfigSettings()
- {
- return true;
- }
-};
-
-} // end namespace vgui
-
-//-----------------------------------------------------------------------------
-//
-// Splitter panel
-//
-//-----------------------------------------------------------------------------
-vgui::Panel *Splitter_V_Factory()
-{
- return new Splitter( NULL, NULL, SPLITTER_MODE_VERTICAL, 1 );
-}
-
-vgui::Panel *Splitter_H_Factory()
-{
- return new Splitter( NULL, NULL, SPLITTER_MODE_HORIZONTAL, 1 );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-//-----------------------------------------------------------------------------
-Splitter::Splitter( Panel *parent, const char *name, SplitterMode_t mode, int nCount ) : BaseClass( parent, name )
-{
- Assert( nCount >= 1 );
- m_Mode = mode;
-
- SetPaintBackgroundEnabled( false );
- SetPaintEnabled( false );
- SetPaintBorderEnabled( false );
-
- RecreateSplitters( nCount );
-
- EvenlyRespaceSplitters();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor
-//-----------------------------------------------------------------------------
-Splitter::~Splitter()
-{
- m_Splitters.RemoveAll();
-}
-
-void Splitter::RecreateSplitters( int nCount )
-{
- int i;
- int c = m_Splitters.Count();
- for ( i = 0; i < c; ++i )
- {
- delete m_Splitters[ i ].m_pPanel;
- delete m_Splitters[ i ].m_pHandle;
- }
- m_Splitters.RemoveAll();
-
- for ( i = 0; i < (nCount + 1); ++i )
- {
- char pBuffer[512];
- Q_snprintf( pBuffer, sizeof(pBuffer), "child%d", i );
-
- int nIndex = m_Splitters.AddToTail( );
- SplitterChildPanel *pEditablePanel = new SplitterChildPanel( this, pBuffer );
- m_Splitters[nIndex].m_pPanel = pEditablePanel;
- m_Splitters[nIndex].m_bLocked = false;
- m_Splitters[nIndex].m_nLockedSize = 0;
- }
-
- // We do this in 2 loops so that the first N children are actual child panels
- for ( i = 0; i < nCount; ++i )
- {
- SplitterHandle *pHandle = new SplitterHandle( this, "SplitterHandle", m_Mode, i );
- m_Splitters[i].m_pHandle = pHandle;
- pHandle->MoveToFront();
- }
- m_Splitters[nCount].m_pHandle = NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// Sets the splitter color
-//-----------------------------------------------------------------------------
-void Splitter::SetSplitterColor( Color c )
-{
- int nCount = m_Splitters.Count() - 1;
- if ( c.a() != 0 )
- {
- for ( int i = 0; i < nCount; ++i )
- {
- m_Splitters[i].m_pHandle->SetBgColor( c );
- m_Splitters[i].m_pHandle->SetPaintBackgroundEnabled( true );
- }
- }
- else
- {
- for ( int i = 0; i < nCount; ++i )
- {
- m_Splitters[i].m_pHandle->SetPaintBackgroundEnabled( false );
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Enables borders on the splitters
-//-----------------------------------------------------------------------------
-void Splitter::EnableBorders( bool bEnable )
-{
- int nCount = m_Splitters.Count() - 1;
- for ( int i = 0; i < nCount; ++i )
- {
- m_Splitters[i].m_pHandle->SetPaintBorderEnabled( bEnable );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// controls splitters
-//-----------------------------------------------------------------------------
-int Splitter::GetSplitterCount() const
-{
- return m_Splitters.Count() - 1;
-}
-
-
-//-----------------------------------------------------------------------------
-// controls splitters
-//-----------------------------------------------------------------------------
-int Splitter::GetSubPanelCount() const
-{
- return m_Splitters.Count();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Applies resouce settings
-//-----------------------------------------------------------------------------
-void Splitter::ApplySettings(KeyValues *inResourceData)
-{
- BaseClass::ApplySettings(inResourceData);
-
- // Look for splitter positions
- int nSplitterCount = GetSplitterCount();
- for ( int i = 0; i < nSplitterCount; ++i )
- {
- char pBuffer[512];
- Q_snprintf( pBuffer, sizeof(pBuffer), "splitter%d", i );
-
- int nSplitterPos = inResourceData->GetInt( pBuffer , -1 );
- if ( nSplitterPos >= 0 )
- {
- SetSplitterPosition( i, nSplitterPos );
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-int Splitter::GetPosRange()
-{
- int w, h;
- GetSize( w, h );
- int nPosRange = (m_Mode == SPLITTER_MODE_HORIZONTAL) ? h : w;
- return nPosRange;
-}
-
-
-//-----------------------------------------------------------------------------
-// Locks the size of a particular child in pixels.
-//-----------------------------------------------------------------------------
-void Splitter::LockChildSize( int nChildIndex, int nSize )
-{
- Assert( nChildIndex < m_Splitters.Count() );
- SplitterInfo_t &info = m_Splitters[nChildIndex];
- nSize += SPLITTER_HANDLE_WIDTH;
- if ( !info.m_bLocked || (info.m_nLockedSize != nSize) )
- {
- float flPrevPos = (nChildIndex > 0) ? m_Splitters[nChildIndex-1].m_flPos : 0.0f;
- float flOldSize = info.m_flPos - flPrevPos;
- float flDelta = nSize - flOldSize;
- int nCount = m_Splitters.Count();
- for ( int i = nChildIndex; i < nCount-1; ++i )
- {
- m_Splitters[i].m_flPos += flDelta;
- }
- m_Splitters[nCount-1].m_flPos = GetPosRange();
-
- info.m_bLocked = true;
- info.m_nLockedSize = nSize;
- InvalidateLayout();
- }
-}
-
-void Splitter::UnlockChildSize( int nChildIndex )
-{
- Assert( nChildIndex < m_Splitters.Count() );
- SplitterInfo_t &info = m_Splitters[nChildIndex];
- if ( info.m_bLocked )
- {
- info.m_bLocked = false;
-
- float flPrevPos = (nChildIndex > 0) ? m_Splitters[nChildIndex-1].m_flPos : 0.0f;
- float flBelowSize = GetPosRange() - flPrevPos;
-
- int nLockedSize = ComputeLockedSize( nChildIndex + 1 );
- int nUnlockedCount = 1;
- int nCount = m_Splitters.Count();
- for ( int i = nChildIndex + 1; i < nCount; ++i )
- {
- if ( !m_Splitters[i].m_bLocked )
- {
- ++nUnlockedCount;
- }
- }
-
- float flUnlockedSize = ( flBelowSize - nLockedSize ) / nUnlockedCount;
-
- for ( int i = nChildIndex; i < nCount; ++i )
- {
- if ( !m_Splitters[i].m_bLocked )
- {
- m_Splitters[i].m_flPos = flPrevPos + flUnlockedSize;
- }
- else
- {
- m_Splitters[i].m_flPos = flPrevPos + m_Splitters[i].m_nLockedSize;
- }
- flPrevPos = m_Splitters[i].m_flPos;
- }
- InvalidateLayout();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Called when size changes
-//-----------------------------------------------------------------------------
-void Splitter::OnSizeChanged( int newWide, int newTall )
-{
- BaseClass::OnSizeChanged( newWide, newTall );
-
- // Don't resize if it's degenerate and won't show up anyway...
- if ( newTall <= 0 || newWide <= 0 )
- return;
-
- int nLockedSize = 0;
- float flUnlockedSize = 0.0f;
- int nCount = m_Splitters.Count();
- float flLastPos = 0.0f;
- int nUnlockedCount = 0;
- for ( int i = 0; i < nCount; ++i )
- {
- SplitterInfo_t &info = m_Splitters[i];
- if ( info.m_bLocked )
- {
- nLockedSize += info.m_nLockedSize;
- }
- else
- {
- ++nUnlockedCount;
- flUnlockedSize += info.m_flPos - flLastPos;
- }
- flLastPos = info.m_flPos;
- }
-
- int nNewTotalSize = (m_Mode == SPLITTER_MODE_HORIZONTAL) ? newTall : newWide;
- int nNewUnlockedSize = nNewTotalSize - nLockedSize;
- if ( nNewUnlockedSize < nUnlockedCount * SPLITTER_HANDLE_WIDTH )
- {
- nNewUnlockedSize = nUnlockedCount * SPLITTER_HANDLE_WIDTH;
- }
-
- float flRatio = nNewUnlockedSize / flUnlockedSize;
- float flLastPrevPos = 0.0f;
- flLastPos = 0.0f;
- for ( int i = 0; i < nCount - 1; ++i )
- {
- SplitterInfo_t &info = m_Splitters[i];
- if ( info.m_bLocked )
- {
- flLastPrevPos = info.m_flPos;
- info.m_flPos = flLastPos + info.m_nLockedSize;
- }
- else
- {
- float flNewSize = info.m_flPos - flLastPrevPos;
- flNewSize *= flRatio;
- flLastPrevPos = info.m_flPos;
- info.m_flPos = flLastPos + flNewSize;
- }
- flLastPos = info.m_flPos;
- }
-
- // Clamp the bottom to 1.0
- m_Splitters[nCount-1].m_flPos = nNewTotalSize;
-}
-
-
-//-----------------------------------------------------------------------------
-// Splitter position
-//-----------------------------------------------------------------------------
-int Splitter::GetSplitterPosition( int nIndex )
-{
- return (int)( m_Splitters[nIndex].m_flPos + 0.5f );
-}
-
-void Splitter::SetSplitterPosition( int nIndex, int nPos )
-{
- int nPosRange = GetPosRange();
- if ( nPosRange == 0 )
- return;
-
- // If we're locked to a sibling, move the previous sibling first
- while ( ( nIndex >= 0 ) && m_Splitters[nIndex].m_bLocked )
- {
- nPos -= m_Splitters[nIndex].m_nLockedSize;
- --nIndex;
- }
- if ( nIndex < 0 )
- return;
-
- // Clamp to the valid positional range
- int i;
- int nMinPos = 0;
- for ( i = 0; i < nIndex; ++i )
- {
- if ( !m_Splitters[i].m_bLocked )
- {
- nMinPos += SPLITTER_HANDLE_WIDTH;
- }
- else
- {
- nMinPos += m_Splitters[i].m_nLockedSize;
- }
- }
-
- int nMaxPos = nPosRange - SPLITTER_HANDLE_WIDTH;
- int c = GetSplitterCount();
- for ( i = nIndex + 1; i < c; ++i )
- {
- if ( !m_Splitters[i].m_bLocked )
- {
- nMaxPos -= SPLITTER_HANDLE_WIDTH;
- }
- else
- {
- nMaxPos -= m_Splitters[i].m_nLockedSize;
- }
- }
- nPos = clamp( nPos, nMinPos, nMaxPos );
-
- m_Splitters[nIndex].m_flPos = nPos;
- int p = nPos;
- for ( i = nIndex - 1 ; i >= 0; --i )
- {
- int nMinPrevPos;
- int nMaxPrevPos;
- if ( !m_Splitters[i+1].m_bLocked )
- {
- nMinPrevPos = -INT_MAX;
- nMaxPrevPos = nPos - SPLITTER_HANDLE_WIDTH;
- }
- else
- {
- nMinPrevPos = nMaxPrevPos = p - m_Splitters[i+1].m_nLockedSize;
- }
-
- int nCurPos = GetSplitterPosition( i );
- if ( nMaxPrevPos < nCurPos || nMinPrevPos > nCurPos )
- {
- m_Splitters[ i ].m_flPos = nMaxPrevPos;
- p = nMaxPrevPos;
- }
- else
- {
- p = m_Splitters[ i ].m_flPos;
- }
- }
-
- for ( i = nIndex + 1 ; i < c; ++i )
- {
- int nMinNextPos;
- int nMaxNextPos;
- if ( !m_Splitters[i].m_bLocked )
- {
- nMinNextPos = nPos + SPLITTER_HANDLE_WIDTH;
- nMaxNextPos = INT_MAX;
- }
- else
- {
- nMinNextPos = nMaxNextPos = nPos + m_Splitters[i].m_nLockedSize;
- }
-
- int nCurPos = GetSplitterPosition( i );
- if ( nMinNextPos > nCurPos || nMaxNextPos < nCurPos )
- {
- m_Splitters[ i ].m_flPos = nMinNextPos;
- nPos = nMinNextPos;
- }
- else
- {
- nPos = m_Splitters[ i ].m_flPos;
- }
- }
-
- InvalidateLayout();
-}
-
-
-//-----------------------------------------------------------------------------
-// Computes the locked size
-//-----------------------------------------------------------------------------
-int Splitter::ComputeLockedSize( int nStartingIndex )
-{
- int nLockedSize = 0;
- int nCount = m_Splitters.Count();
- for ( int i = nStartingIndex; i < nCount; ++i )
- {
- if ( m_Splitters[i].m_bLocked )
- {
- nLockedSize += m_Splitters[i].m_nLockedSize;
- }
- }
- return nLockedSize;
-}
-
-
-//-----------------------------------------------------------------------------
-// Evenly respaces all the splitters
-//-----------------------------------------------------------------------------
-void Splitter::EvenlyRespaceSplitters( )
-{
- int nSplitterCount = GetSubPanelCount();
- if ( nSplitterCount == 0 )
- return;
-
- int nLockedSize = ComputeLockedSize( 0 );
- float flUnlockedSize = (float)( GetPosRange() - nLockedSize );
- float flDPos = flUnlockedSize / (float)nSplitterCount;
- if ( flDPos < SPLITTER_HANDLE_WIDTH )
- {
- flDPos = SPLITTER_HANDLE_WIDTH;
- }
- float flPos = 0.0f;
- for ( int i = 0; i < nSplitterCount; ++i )
- {
- if ( !m_Splitters[i].m_bLocked )
- {
- flPos += flDPos;
- }
- else
- {
- flPos += m_Splitters[i].m_nLockedSize;
- }
- m_Splitters[i].m_flPos = flPos;
- }
-
- InvalidateLayout();
-}
-
-void Splitter::RespaceSplitters( float *flFractions )
-{
- int nSplitterCount = GetSubPanelCount();
- if ( nSplitterCount == 0 )
- return;
-
- float flPos = 0.0f;
- int nPosRange = GetPosRange();
- for ( int i = 0; i < nSplitterCount; ++i )
- {
- flPos += flFractions[i];
- m_Splitters[i].m_flPos = flPos * nPosRange;
- }
-
- Assert( flPos == 1.0f );
-
- InvalidateLayout();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: sets user settings
-//-----------------------------------------------------------------------------
-void Splitter::ApplyUserConfigSettings(KeyValues *userConfig)
-{
- BaseClass::ApplyUserConfigSettings( userConfig );
-
- // read the splitter sizes
- int c = m_Splitters.Count();
- float *pFractions = (float*)_alloca( c * sizeof(float) );
- float flTotalSize = 0.0f;
- for ( int i = 0; i < c; i++ )
- {
- char name[128];
- _snprintf(name, sizeof(name), "%d_splitter_pos", i);
- pFractions[i] = userConfig->GetFloat( name, flTotalSize + SPLITTER_HANDLE_WIDTH + 1 );
- flTotalSize = pFractions[i];
- }
-
- if ( flTotalSize != 0.0f )
- {
- int nPosRange = GetPosRange();
- for ( int i = 0; i < c; ++i )
- {
- pFractions[i] /= flTotalSize;
- m_Splitters[i].m_flPos = pFractions[i] * nPosRange;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: returns user config settings for this control
-//-----------------------------------------------------------------------------
-void Splitter::GetUserConfigSettings(KeyValues *userConfig)
-{
- BaseClass::GetUserConfigSettings( userConfig );
-
- // save which columns are hidden
- int c = m_Splitters.Count();
- for ( int i = 0 ; i < c; i++ )
- {
- char name[128];
- _snprintf(name, sizeof(name), "%d_splitter_pos", i);
- userConfig->SetFloat( name, m_Splitters[i].m_flPos );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Called to perform layout
-//-----------------------------------------------------------------------------
-void Splitter::PerformLayout( )
-{
- BaseClass::PerformLayout();
-
- int nSplitterCount = GetSubPanelCount();
- if ( nSplitterCount == 0 )
- return;
-
- int w, h;
- GetSize( w, h );
-
- int nLastPos = 0;
- for ( int i = 0; i < nSplitterCount; ++i )
- {
- Panel *pChild = m_Splitters[i].m_pPanel;
- SplitterHandle *pHandle = m_Splitters[i].m_pHandle;
- int nSplitterPos = (int)( m_Splitters[i].m_flPos + 0.5f );
-
- if ( m_Mode == SPLITTER_MODE_HORIZONTAL )
- {
- pChild->SetPos( 0, nLastPos );
- pChild->SetSize( w, nSplitterPos - nLastPos );
- if ( pHandle )
- {
- pHandle->SetPos( 0, nSplitterPos );
- pHandle->SetSize( w, SPLITTER_HANDLE_WIDTH );
- }
- }
- else
- {
- pChild->SetPos( nLastPos, 0 );
- pChild->SetSize( nSplitterPos - nLastPos, h );
- if ( pHandle )
- {
- pHandle->SetPos( nSplitterPos, 0 );
- pHandle->SetSize( SPLITTER_HANDLE_WIDTH, h );
- }
- }
-
- nLastPos = nSplitterPos + SPLITTER_HANDLE_WIDTH;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void Splitter::GetSettings( KeyValues *outResourceData )
-{
- BaseClass::GetSettings( outResourceData );
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include <vgui/IScheme.h>
+#include <vgui/Cursor.h>
+#include <vgui/IInput.h>
+#include <vgui_controls/Splitter.h>
+#include "tier1/KeyValues.h"
+#include <limits.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+enum
+{
+ SPLITTER_HANDLE_WIDTH = 4
+};
+
+
+//-----------------------------------------------------------------------------
+// Splitter handle
+//-----------------------------------------------------------------------------
+namespace vgui
+{
+
+class SplitterHandle : public Panel
+{
+ DECLARE_CLASS_SIMPLE( SplitterHandle, Panel );
+
+public:
+ SplitterHandle( Splitter *parent, const char *name, SplitterMode_t mode, int nIndex );
+ ~SplitterHandle();
+
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+ virtual void OnMousePressed( MouseCode code );
+ virtual void OnMouseReleased( MouseCode code );
+ virtual void OnCursorMoved( int x, int y );
+ virtual void OnMouseDoublePressed( MouseCode code );
+
+private:
+ SplitterMode_t m_nMode;
+ int m_nIndex;
+ bool m_bDragging;
+};
+
+} // end namespace vgui
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+SplitterHandle::SplitterHandle( Splitter *parent, const char *name, SplitterMode_t mode, int nIndex ) : BaseClass( parent, name )
+{
+ int w, h;
+ parent->GetSize( w, h );
+
+ if ( mode == SPLITTER_MODE_HORIZONTAL )
+ {
+ SetSize( w, SPLITTER_HANDLE_WIDTH );
+ SetCursor( dc_sizens );
+ }
+ else
+ {
+ SetSize( SPLITTER_HANDLE_WIDTH, h );
+ SetCursor( dc_sizewe );
+ }
+
+ SetVisible( true );
+ SetPaintBackgroundEnabled( false );
+ SetPaintEnabled( false );
+ SetPaintBorderEnabled( true );
+ m_bDragging = false;
+ m_nIndex = nIndex;
+ m_nMode = mode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+SplitterHandle::~SplitterHandle()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Scheme settings
+//-----------------------------------------------------------------------------
+void SplitterHandle::ApplySchemeSettings(IScheme *pScheme)
+{
+ // Cache off background color stored in SetSplitterColor
+ Color c = GetBgColor();
+ SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
+ BaseClass::ApplySchemeSettings(pScheme);
+ SetBgColor( c );
+}
+
+
+//-----------------------------------------------------------------------------
+// Capture mouse when dragging
+//-----------------------------------------------------------------------------
+void SplitterHandle::OnMousePressed(MouseCode code)
+{
+ if ( !m_bDragging )
+ {
+ input()->SetMouseCapture(GetVPanel());
+ m_bDragging = true;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Release mouse capture when finished dragging
+//-----------------------------------------------------------------------------
+void SplitterHandle::OnMouseReleased(MouseCode code)
+{
+ if ( m_bDragging )
+ {
+ input()->SetMouseCapture(NULL);
+ m_bDragging = false;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// While dragging, update the splitter position
+//-----------------------------------------------------------------------------
+void SplitterHandle::OnCursorMoved(int x, int y)
+{
+ if (m_bDragging)
+ {
+ input()->GetCursorPos( x, y );
+ Splitter *pSplitter = assert_cast<Splitter*>( GetParent() );
+ pSplitter->ScreenToLocal( x,y );
+ pSplitter->SetSplitterPosition( m_nIndex, (m_nMode == SPLITTER_MODE_HORIZONTAL) ? y : x );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Double-click: make both panels on either side of the splitter equal size
+//-----------------------------------------------------------------------------
+void SplitterHandle::OnMouseDoublePressed( MouseCode code )
+{
+ Splitter *pSplitter = assert_cast<Splitter*>( GetParent() );
+ pSplitter->EvenlyRespaceSplitters();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Returns a panel that chains user configs
+//-----------------------------------------------------------------------------
+namespace vgui
+{
+
+class SplitterChildPanel : public EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( SplitterChildPanel, EditablePanel );
+
+public:
+ SplitterChildPanel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
+ {
+ SetPaintBackgroundEnabled( false );
+ SetPaintEnabled( false );
+ SetPaintBorderEnabled( false );
+ }
+
+ virtual ~SplitterChildPanel() {}
+
+ // Children may have user config settings
+ bool HasUserConfigSettings()
+ {
+ return true;
+ }
+};
+
+} // end namespace vgui
+
+//-----------------------------------------------------------------------------
+//
+// Splitter panel
+//
+//-----------------------------------------------------------------------------
+vgui::Panel *Splitter_V_Factory()
+{
+ return new Splitter( NULL, NULL, SPLITTER_MODE_VERTICAL, 1 );
+}
+
+vgui::Panel *Splitter_H_Factory()
+{
+ return new Splitter( NULL, NULL, SPLITTER_MODE_HORIZONTAL, 1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+Splitter::Splitter( Panel *parent, const char *name, SplitterMode_t mode, int nCount ) : BaseClass( parent, name )
+{
+ Assert( nCount >= 1 );
+ m_Mode = mode;
+
+ SetPaintBackgroundEnabled( false );
+ SetPaintEnabled( false );
+ SetPaintBorderEnabled( false );
+
+ RecreateSplitters( nCount );
+
+ EvenlyRespaceSplitters();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+Splitter::~Splitter()
+{
+ m_Splitters.RemoveAll();
+}
+
+void Splitter::RecreateSplitters( int nCount )
+{
+ int i;
+ int c = m_Splitters.Count();
+ for ( i = 0; i < c; ++i )
+ {
+ delete m_Splitters[ i ].m_pPanel;
+ delete m_Splitters[ i ].m_pHandle;
+ }
+ m_Splitters.RemoveAll();
+
+ for ( i = 0; i < (nCount + 1); ++i )
+ {
+ char pBuffer[512];
+ Q_snprintf( pBuffer, sizeof(pBuffer), "child%d", i );
+
+ int nIndex = m_Splitters.AddToTail( );
+ SplitterChildPanel *pEditablePanel = new SplitterChildPanel( this, pBuffer );
+ m_Splitters[nIndex].m_pPanel = pEditablePanel;
+ m_Splitters[nIndex].m_bLocked = false;
+ m_Splitters[nIndex].m_nLockedSize = 0;
+ }
+
+ // We do this in 2 loops so that the first N children are actual child panels
+ for ( i = 0; i < nCount; ++i )
+ {
+ SplitterHandle *pHandle = new SplitterHandle( this, "SplitterHandle", m_Mode, i );
+ m_Splitters[i].m_pHandle = pHandle;
+ pHandle->MoveToFront();
+ }
+ m_Splitters[nCount].m_pHandle = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the splitter color
+//-----------------------------------------------------------------------------
+void Splitter::SetSplitterColor( Color c )
+{
+ int nCount = m_Splitters.Count() - 1;
+ if ( c.a() != 0 )
+ {
+ for ( int i = 0; i < nCount; ++i )
+ {
+ m_Splitters[i].m_pHandle->SetBgColor( c );
+ m_Splitters[i].m_pHandle->SetPaintBackgroundEnabled( true );
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < nCount; ++i )
+ {
+ m_Splitters[i].m_pHandle->SetPaintBackgroundEnabled( false );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Enables borders on the splitters
+//-----------------------------------------------------------------------------
+void Splitter::EnableBorders( bool bEnable )
+{
+ int nCount = m_Splitters.Count() - 1;
+ for ( int i = 0; i < nCount; ++i )
+ {
+ m_Splitters[i].m_pHandle->SetPaintBorderEnabled( bEnable );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// controls splitters
+//-----------------------------------------------------------------------------
+int Splitter::GetSplitterCount() const
+{
+ return m_Splitters.Count() - 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// controls splitters
+//-----------------------------------------------------------------------------
+int Splitter::GetSubPanelCount() const
+{
+ return m_Splitters.Count();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Applies resouce settings
+//-----------------------------------------------------------------------------
+void Splitter::ApplySettings(KeyValues *inResourceData)
+{
+ BaseClass::ApplySettings(inResourceData);
+
+ // Look for splitter positions
+ int nSplitterCount = GetSplitterCount();
+ for ( int i = 0; i < nSplitterCount; ++i )
+ {
+ char pBuffer[512];
+ Q_snprintf( pBuffer, sizeof(pBuffer), "splitter%d", i );
+
+ int nSplitterPos = inResourceData->GetInt( pBuffer , -1 );
+ if ( nSplitterPos >= 0 )
+ {
+ SetSplitterPosition( i, nSplitterPos );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int Splitter::GetPosRange()
+{
+ int w, h;
+ GetSize( w, h );
+ int nPosRange = (m_Mode == SPLITTER_MODE_HORIZONTAL) ? h : w;
+ return nPosRange;
+}
+
+
+//-----------------------------------------------------------------------------
+// Locks the size of a particular child in pixels.
+//-----------------------------------------------------------------------------
+void Splitter::LockChildSize( int nChildIndex, int nSize )
+{
+ Assert( nChildIndex < m_Splitters.Count() );
+ SplitterInfo_t &info = m_Splitters[nChildIndex];
+ nSize += SPLITTER_HANDLE_WIDTH;
+ if ( !info.m_bLocked || (info.m_nLockedSize != nSize) )
+ {
+ float flPrevPos = (nChildIndex > 0) ? m_Splitters[nChildIndex-1].m_flPos : 0.0f;
+ float flOldSize = info.m_flPos - flPrevPos;
+ float flDelta = nSize - flOldSize;
+ int nCount = m_Splitters.Count();
+ for ( int i = nChildIndex; i < nCount-1; ++i )
+ {
+ m_Splitters[i].m_flPos += flDelta;
+ }
+ m_Splitters[nCount-1].m_flPos = GetPosRange();
+
+ info.m_bLocked = true;
+ info.m_nLockedSize = nSize;
+ InvalidateLayout();
+ }
+}
+
+void Splitter::UnlockChildSize( int nChildIndex )
+{
+ Assert( nChildIndex < m_Splitters.Count() );
+ SplitterInfo_t &info = m_Splitters[nChildIndex];
+ if ( info.m_bLocked )
+ {
+ info.m_bLocked = false;
+
+ float flPrevPos = (nChildIndex > 0) ? m_Splitters[nChildIndex-1].m_flPos : 0.0f;
+ float flBelowSize = GetPosRange() - flPrevPos;
+
+ int nLockedSize = ComputeLockedSize( nChildIndex + 1 );
+ int nUnlockedCount = 1;
+ int nCount = m_Splitters.Count();
+ for ( int i = nChildIndex + 1; i < nCount; ++i )
+ {
+ if ( !m_Splitters[i].m_bLocked )
+ {
+ ++nUnlockedCount;
+ }
+ }
+
+ float flUnlockedSize = ( flBelowSize - nLockedSize ) / nUnlockedCount;
+
+ for ( int i = nChildIndex; i < nCount; ++i )
+ {
+ if ( !m_Splitters[i].m_bLocked )
+ {
+ m_Splitters[i].m_flPos = flPrevPos + flUnlockedSize;
+ }
+ else
+ {
+ m_Splitters[i].m_flPos = flPrevPos + m_Splitters[i].m_nLockedSize;
+ }
+ flPrevPos = m_Splitters[i].m_flPos;
+ }
+ InvalidateLayout();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when size changes
+//-----------------------------------------------------------------------------
+void Splitter::OnSizeChanged( int newWide, int newTall )
+{
+ BaseClass::OnSizeChanged( newWide, newTall );
+
+ // Don't resize if it's degenerate and won't show up anyway...
+ if ( newTall <= 0 || newWide <= 0 )
+ return;
+
+ int nLockedSize = 0;
+ float flUnlockedSize = 0.0f;
+ int nCount = m_Splitters.Count();
+ float flLastPos = 0.0f;
+ int nUnlockedCount = 0;
+ for ( int i = 0; i < nCount; ++i )
+ {
+ SplitterInfo_t &info = m_Splitters[i];
+ if ( info.m_bLocked )
+ {
+ nLockedSize += info.m_nLockedSize;
+ }
+ else
+ {
+ ++nUnlockedCount;
+ flUnlockedSize += info.m_flPos - flLastPos;
+ }
+ flLastPos = info.m_flPos;
+ }
+
+ int nNewTotalSize = (m_Mode == SPLITTER_MODE_HORIZONTAL) ? newTall : newWide;
+ int nNewUnlockedSize = nNewTotalSize - nLockedSize;
+ if ( nNewUnlockedSize < nUnlockedCount * SPLITTER_HANDLE_WIDTH )
+ {
+ nNewUnlockedSize = nUnlockedCount * SPLITTER_HANDLE_WIDTH;
+ }
+
+ float flRatio = nNewUnlockedSize / flUnlockedSize;
+ float flLastPrevPos = 0.0f;
+ flLastPos = 0.0f;
+ for ( int i = 0; i < nCount - 1; ++i )
+ {
+ SplitterInfo_t &info = m_Splitters[i];
+ if ( info.m_bLocked )
+ {
+ flLastPrevPos = info.m_flPos;
+ info.m_flPos = flLastPos + info.m_nLockedSize;
+ }
+ else
+ {
+ float flNewSize = info.m_flPos - flLastPrevPos;
+ flNewSize *= flRatio;
+ flLastPrevPos = info.m_flPos;
+ info.m_flPos = flLastPos + flNewSize;
+ }
+ flLastPos = info.m_flPos;
+ }
+
+ // Clamp the bottom to 1.0
+ m_Splitters[nCount-1].m_flPos = nNewTotalSize;
+}
+
+
+//-----------------------------------------------------------------------------
+// Splitter position
+//-----------------------------------------------------------------------------
+int Splitter::GetSplitterPosition( int nIndex )
+{
+ return (int)( m_Splitters[nIndex].m_flPos + 0.5f );
+}
+
+void Splitter::SetSplitterPosition( int nIndex, int nPos )
+{
+ int nPosRange = GetPosRange();
+ if ( nPosRange == 0 )
+ return;
+
+ // If we're locked to a sibling, move the previous sibling first
+ while ( ( nIndex >= 0 ) && m_Splitters[nIndex].m_bLocked )
+ {
+ nPos -= m_Splitters[nIndex].m_nLockedSize;
+ --nIndex;
+ }
+ if ( nIndex < 0 )
+ return;
+
+ // Clamp to the valid positional range
+ int i;
+ int nMinPos = 0;
+ for ( i = 0; i < nIndex; ++i )
+ {
+ if ( !m_Splitters[i].m_bLocked )
+ {
+ nMinPos += SPLITTER_HANDLE_WIDTH;
+ }
+ else
+ {
+ nMinPos += m_Splitters[i].m_nLockedSize;
+ }
+ }
+
+ int nMaxPos = nPosRange - SPLITTER_HANDLE_WIDTH;
+ int c = GetSplitterCount();
+ for ( i = nIndex + 1; i < c; ++i )
+ {
+ if ( !m_Splitters[i].m_bLocked )
+ {
+ nMaxPos -= SPLITTER_HANDLE_WIDTH;
+ }
+ else
+ {
+ nMaxPos -= m_Splitters[i].m_nLockedSize;
+ }
+ }
+ nPos = clamp( nPos, nMinPos, nMaxPos );
+
+ m_Splitters[nIndex].m_flPos = nPos;
+ int p = nPos;
+ for ( i = nIndex - 1 ; i >= 0; --i )
+ {
+ int nMinPrevPos;
+ int nMaxPrevPos;
+ if ( !m_Splitters[i+1].m_bLocked )
+ {
+ nMinPrevPos = -INT_MAX;
+ nMaxPrevPos = nPos - SPLITTER_HANDLE_WIDTH;
+ }
+ else
+ {
+ nMinPrevPos = nMaxPrevPos = p - m_Splitters[i+1].m_nLockedSize;
+ }
+
+ int nCurPos = GetSplitterPosition( i );
+ if ( nMaxPrevPos < nCurPos || nMinPrevPos > nCurPos )
+ {
+ m_Splitters[ i ].m_flPos = nMaxPrevPos;
+ p = nMaxPrevPos;
+ }
+ else
+ {
+ p = m_Splitters[ i ].m_flPos;
+ }
+ }
+
+ for ( i = nIndex + 1 ; i < c; ++i )
+ {
+ int nMinNextPos;
+ int nMaxNextPos;
+ if ( !m_Splitters[i].m_bLocked )
+ {
+ nMinNextPos = nPos + SPLITTER_HANDLE_WIDTH;
+ nMaxNextPos = INT_MAX;
+ }
+ else
+ {
+ nMinNextPos = nMaxNextPos = nPos + m_Splitters[i].m_nLockedSize;
+ }
+
+ int nCurPos = GetSplitterPosition( i );
+ if ( nMinNextPos > nCurPos || nMaxNextPos < nCurPos )
+ {
+ m_Splitters[ i ].m_flPos = nMinNextPos;
+ nPos = nMinNextPos;
+ }
+ else
+ {
+ nPos = m_Splitters[ i ].m_flPos;
+ }
+ }
+
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the locked size
+//-----------------------------------------------------------------------------
+int Splitter::ComputeLockedSize( int nStartingIndex )
+{
+ int nLockedSize = 0;
+ int nCount = m_Splitters.Count();
+ for ( int i = nStartingIndex; i < nCount; ++i )
+ {
+ if ( m_Splitters[i].m_bLocked )
+ {
+ nLockedSize += m_Splitters[i].m_nLockedSize;
+ }
+ }
+ return nLockedSize;
+}
+
+
+//-----------------------------------------------------------------------------
+// Evenly respaces all the splitters
+//-----------------------------------------------------------------------------
+void Splitter::EvenlyRespaceSplitters( )
+{
+ int nSplitterCount = GetSubPanelCount();
+ if ( nSplitterCount == 0 )
+ return;
+
+ int nLockedSize = ComputeLockedSize( 0 );
+ float flUnlockedSize = (float)( GetPosRange() - nLockedSize );
+ float flDPos = flUnlockedSize / (float)nSplitterCount;
+ if ( flDPos < SPLITTER_HANDLE_WIDTH )
+ {
+ flDPos = SPLITTER_HANDLE_WIDTH;
+ }
+ float flPos = 0.0f;
+ for ( int i = 0; i < nSplitterCount; ++i )
+ {
+ if ( !m_Splitters[i].m_bLocked )
+ {
+ flPos += flDPos;
+ }
+ else
+ {
+ flPos += m_Splitters[i].m_nLockedSize;
+ }
+ m_Splitters[i].m_flPos = flPos;
+ }
+
+ InvalidateLayout();
+}
+
+void Splitter::RespaceSplitters( float *flFractions )
+{
+ int nSplitterCount = GetSubPanelCount();
+ if ( nSplitterCount == 0 )
+ return;
+
+ float flPos = 0.0f;
+ int nPosRange = GetPosRange();
+ for ( int i = 0; i < nSplitterCount; ++i )
+ {
+ flPos += flFractions[i];
+ m_Splitters[i].m_flPos = flPos * nPosRange;
+ }
+
+ Assert( flPos == 1.0f );
+
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets user settings
+//-----------------------------------------------------------------------------
+void Splitter::ApplyUserConfigSettings(KeyValues *userConfig)
+{
+ BaseClass::ApplyUserConfigSettings( userConfig );
+
+ // read the splitter sizes
+ int c = m_Splitters.Count();
+ float *pFractions = (float*)_alloca( c * sizeof(float) );
+ float flTotalSize = 0.0f;
+ for ( int i = 0; i < c; i++ )
+ {
+ char name[128];
+ _snprintf(name, sizeof(name), "%d_splitter_pos", i);
+ pFractions[i] = userConfig->GetFloat( name, flTotalSize + SPLITTER_HANDLE_WIDTH + 1 );
+ flTotalSize = pFractions[i];
+ }
+
+ if ( flTotalSize != 0.0f )
+ {
+ int nPosRange = GetPosRange();
+ for ( int i = 0; i < c; ++i )
+ {
+ pFractions[i] /= flTotalSize;
+ m_Splitters[i].m_flPos = pFractions[i] * nPosRange;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns user config settings for this control
+//-----------------------------------------------------------------------------
+void Splitter::GetUserConfigSettings(KeyValues *userConfig)
+{
+ BaseClass::GetUserConfigSettings( userConfig );
+
+ // save which columns are hidden
+ int c = m_Splitters.Count();
+ for ( int i = 0 ; i < c; i++ )
+ {
+ char name[128];
+ _snprintf(name, sizeof(name), "%d_splitter_pos", i);
+ userConfig->SetFloat( name, m_Splitters[i].m_flPos );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called to perform layout
+//-----------------------------------------------------------------------------
+void Splitter::PerformLayout( )
+{
+ BaseClass::PerformLayout();
+
+ int nSplitterCount = GetSubPanelCount();
+ if ( nSplitterCount == 0 )
+ return;
+
+ int w, h;
+ GetSize( w, h );
+
+ int nLastPos = 0;
+ for ( int i = 0; i < nSplitterCount; ++i )
+ {
+ Panel *pChild = m_Splitters[i].m_pPanel;
+ SplitterHandle *pHandle = m_Splitters[i].m_pHandle;
+ int nSplitterPos = (int)( m_Splitters[i].m_flPos + 0.5f );
+
+ if ( m_Mode == SPLITTER_MODE_HORIZONTAL )
+ {
+ pChild->SetPos( 0, nLastPos );
+ pChild->SetSize( w, nSplitterPos - nLastPos );
+ if ( pHandle )
+ {
+ pHandle->SetPos( 0, nSplitterPos );
+ pHandle->SetSize( w, SPLITTER_HANDLE_WIDTH );
+ }
+ }
+ else
+ {
+ pChild->SetPos( nLastPos, 0 );
+ pChild->SetSize( nSplitterPos - nLastPos, h );
+ if ( pHandle )
+ {
+ pHandle->SetPos( nSplitterPos, 0 );
+ pHandle->SetSize( SPLITTER_HANDLE_WIDTH, h );
+ }
+ }
+
+ nLastPos = nSplitterPos + SPLITTER_HANDLE_WIDTH;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void Splitter::GetSettings( KeyValues *outResourceData )
+{
+ BaseClass::GetSettings( outResourceData );
+}