You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
766 lines
19 KiB
766 lines
19 KiB
5 years ago
|
//========= 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 );
|
||
|
}
|