2025-05-17 14:17:12 -04:00
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
2008-09-15 01:07:45 -05:00
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
# include <stdio.h>
# include <vgui/IInput.h>
# include <vgui/IPanel.h>
# include <vgui/ILocalize.h>
# include <vgui/IScheme.h>
# include <vgui/ISurface.h>
# include <KeyValues.h>
# include <vgui/MouseCode.h>
# include <vgui_controls/SectionedListPanel.h>
# include <vgui_controls/Button.h>
# include <vgui_controls/Controls.h>
# include <vgui_controls/Label.h>
# include <vgui_controls/ScrollBar.h>
# include <vgui_controls/TextImage.h>
# include <vgui_controls/ImageList.h>
# include "UtlVector.h"
// memdbgon must be the last include file in a .cpp file!!!
# include <tier0/memdbgon.h>
using namespace vgui ;
enum
{
BUTTON_HEIGHT_DEFAULT = 20 ,
BUTTON_HEIGHT_SPACER = 7 ,
SECTION_GAP = 8 ,
COLUMN_DATA_INDENT = 6 ,
COLUMN_DATA_GAP = 2 ,
} ;
namespace vgui
{
//-----------------------------------------------------------------------------
// Purpose: header label that separates and names each section
//-----------------------------------------------------------------------------
class CSectionHeader : public Label
{
DECLARE_CLASS_SIMPLE ( CSectionHeader , Label ) ;
public :
CSectionHeader ( SectionedListPanel * parent , const char * name , int sectionID ) : Label ( parent , name , " " )
{
m_pListPanel = parent ;
m_iSectionID = sectionID ;
SetTextImageIndex ( - 1 ) ;
ClearImages ( ) ;
SetPaintBackgroundEnabled ( false ) ;
}
CSectionHeader ( SectionedListPanel * parent , const wchar_t * name , int sectionID ) : Label ( parent , " SectionHeader " , " " )
{
SetText ( name ) ;
SetVisible ( false ) ;
m_pListPanel = parent ;
m_iSectionID = sectionID ;
SetTextImageIndex ( - 1 ) ;
ClearImages ( ) ;
}
void ApplySchemeSettings ( IScheme * pScheme )
{
BaseClass : : ApplySchemeSettings ( pScheme ) ;
SetFgColor ( GetSchemeColor ( " SectionedListPanel.HeaderTextColor " , pScheme ) ) ;
m_SectionDividerColor = GetSchemeColor ( " SectionedListPanel.DividerColor " , pScheme ) ;
SetBgColor ( GetSchemeColor ( " SectionedListPanelHeader.BgColor " , GetBgColor ( ) , pScheme ) ) ;
SetFont ( pScheme - > GetFont ( " DefaultVerySmall " , IsProportional ( ) ) ) ;
ClearImages ( ) ;
}
void Paint ( )
{
BaseClass : : Paint ( ) ;
int x , y , wide , tall ;
GetBounds ( x , y , wide , tall ) ;
y = ( tall - 2 ) ; // draw the line under the panel
surface ( ) - > DrawSetColor ( m_SectionDividerColor ) ;
surface ( ) - > DrawFilledRect ( 1 , y , GetWide ( ) - 2 , y + 1 ) ;
}
void SetColor ( Color col )
{
m_SectionDividerColor = col ;
SetFgColor ( col ) ;
}
void PerformLayout ( )
{
BaseClass : : PerformLayout ( ) ;
// set up the text in the header
int colCount = m_pListPanel - > GetColumnCountBySection ( m_iSectionID ) ;
if ( colCount ! = GetImageCount ( ) )
{
// rebuild the image list
for ( int i = 0 ; i < colCount ; i + + )
{
int columnFlags = m_pListPanel - > GetColumnFlagsBySection ( m_iSectionID , i ) ;
IImage * image = NULL ;
if ( columnFlags & SectionedListPanel : : HEADER_IMAGE )
{
//!! need some kind of image reference
image = NULL ;
}
else
{
TextImage * textImage = new TextImage ( " " ) ;
textImage - > SetFont ( GetFont ( ) ) ;
HFont fallback = m_pListPanel - > GetColumnFallbackFontBySection ( m_iSectionID , i ) ;
if ( INVALID_FONT ! = fallback )
{
textImage - > SetUseFallbackFont ( true , fallback ) ;
}
textImage - > SetColor ( GetFgColor ( ) ) ;
image = textImage ;
}
SetImageAtIndex ( i , image , 0 ) ;
}
}
for ( int repeat = 0 ; repeat < = 1 ; repeat + + )
{
int xpos = 0 ;
for ( int i = 0 ; i < colCount ; i + + )
{
int columnFlags = m_pListPanel - > GetColumnFlagsBySection ( m_iSectionID , i ) ;
int columnWidth = m_pListPanel - > GetColumnWidthBySection ( m_iSectionID , i ) ;
int maxWidth = columnWidth ;
IImage * image = GetImageAtIndex ( i ) ;
if ( ! image )
{
xpos + = columnWidth ;
continue ;
}
// set the image position within the label
int contentWide , wide , tall ;
image - > GetContentSize ( wide , tall ) ;
contentWide = wide ;
// see if we can draw over the next few column headers (if we're left-aligned)
if ( ! ( columnFlags & SectionedListPanel : : COLUMN_RIGHT ) )
{
for ( int j = i + 1 ; j < colCount ; j + + )
{
// see if this column header has anything for a header
int iwide = 0 , itall = 0 ;
if ( GetImageAtIndex ( j ) )
{
GetImageAtIndex ( j ) - > GetContentSize ( iwide , itall ) ;
}
if ( iwide = = 0 )
{
// it's a blank header, ok to draw over it
maxWidth + = m_pListPanel - > GetColumnWidthBySection ( m_iSectionID , j ) ;
}
}
}
if ( maxWidth > = 0 )
{
wide = maxWidth ;
}
if ( columnFlags & SectionedListPanel : : COLUMN_RIGHT )
{
SetImageBounds ( i , xpos + wide - contentWide , contentWide - COLUMN_DATA_GAP ) ;
}
else
{
SetImageBounds ( i , xpos , wide - COLUMN_DATA_GAP ) ;
}
xpos + = columnWidth ;
if ( ! ( columnFlags & SectionedListPanel : : HEADER_IMAGE ) )
{
Assert ( dynamic_cast < TextImage * > ( image ) ! = NULL ) ;
TextImage * textImage = ( TextImage * ) image ;
textImage - > SetText ( m_pListPanel - > GetColumnTextBySection ( m_iSectionID , i ) ) ;
textImage - > ResizeImageToContentMaxWidth ( maxWidth ) ;
}
}
}
}
private :
int m_iSectionID ;
Color m_SectionDividerColor ;
SectionedListPanel * m_pListPanel ;
} ;
//-----------------------------------------------------------------------------
// Purpose: Individual items in the list
//-----------------------------------------------------------------------------
class CItemButton : public Label
{
DECLARE_CLASS_SIMPLE ( CItemButton , Label ) ;
public :
CItemButton ( SectionedListPanel * parent , int itemID ) : Label ( parent , NULL , " < item > " )
{
m_pListPanel = parent ;
m_iID = itemID ;
m_pData = NULL ;
Clear ( ) ;
}
~ CItemButton ( )
{
// free all the keyvalues
if ( m_pData )
{
m_pData - > deleteThis ( ) ;
}
// clear any section data
SetSectionID ( - 1 ) ;
}
void Clear ( )
{
m_bSelected = false ;
m_bOverrideColors = false ;
m_iSectionID = - 1 ;
SetPaintBackgroundEnabled ( false ) ;
SetTextImageIndex ( - 1 ) ;
ClearImages ( ) ;
}
int GetID ( )
{
return m_iID ;
}
void SetID ( int itemID )
{
m_iID = itemID ;
}
int GetSectionID ( )
{
return m_iSectionID ;
}
void SetSectionID ( int sectionID )
{
if ( sectionID ! = m_iSectionID )
{
// free any existing textimage list
ClearImages ( ) ;
// delete any images we've created
for ( int i = 0 ; i < m_TextImages . Count ( ) ; i + + )
{
delete m_TextImages [ i ] ;
}
m_TextImages . RemoveAll ( ) ;
// mark the list as needing rebuilding
InvalidateLayout ( ) ;
}
m_iSectionID = sectionID ;
}
void SetData ( const KeyValues * data )
{
if ( m_pData )
{
m_pData - > deleteThis ( ) ;
}
m_pData = data - > MakeCopy ( ) ;
InvalidateLayout ( ) ;
}
KeyValues * GetData ( )
{
return m_pData ;
}
virtual void PerformLayout ( )
{
// get our button text
int colCount = m_pListPanel - > GetColumnCountBySection ( m_iSectionID ) ;
if ( ! m_pData | | colCount < 1 )
{
SetText ( " < unset > " ) ;
}
else
{
if ( colCount ! = GetImageCount ( ) )
{
// rebuild the image list
for ( int i = 0 ; i < colCount ; i + + )
{
int columnFlags = m_pListPanel - > GetColumnFlagsBySection ( m_iSectionID , i ) ;
if ( ! ( columnFlags & SectionedListPanel : : COLUMN_IMAGE ) )
{
TextImage * image = new TextImage ( " " ) ;
m_TextImages . AddToTail ( image ) ;
image - > SetFont ( GetFont ( ) ) ;
HFont fallback = m_pListPanel - > GetColumnFallbackFontBySection ( m_iSectionID , i ) ;
if ( INVALID_FONT ! = fallback )
{
image - > SetUseFallbackFont ( true , fallback ) ;
}
SetImageAtIndex ( i , image , 0 ) ;
}
}
{ for ( int i = GetImageCount ( ) ; i < colCount ; i + + ) // make sure we have enough image slots
{
AddImage ( NULL , 0 ) ;
} }
}
// set the text for each column
int xpos = 0 ;
for ( int i = 0 ; i < colCount ; i + + )
{
const char * keyname = m_pListPanel - > GetColumnNameBySection ( m_iSectionID , i ) ;
int columnFlags = m_pListPanel - > GetColumnFlagsBySection ( m_iSectionID , i ) ;
int maxWidth = m_pListPanel - > GetColumnWidthBySection ( m_iSectionID , i ) ;
IImage * image = NULL ;
if ( columnFlags & SectionedListPanel : : COLUMN_IMAGE )
{
// lookup which image is being referred to
if ( m_pListPanel - > m_pImageList )
{
int imageIndex = m_pData - > GetInt ( keyname , 0 ) ;
if ( m_pListPanel - > m_pImageList - > IsValidIndex ( imageIndex ) )
{
// 0 is always the blank image
if ( imageIndex > 0 )
{
image = m_pListPanel - > m_pImageList - > GetImage ( imageIndex ) ;
SetImageAtIndex ( i , image , 0 ) ;
}
}
else
{
// this is mildly valid (CGamesList hits it because of the way it uses the image indices)
// Assert(!("Image index out of range for ImageList in SectionedListPanel"));
}
}
else
{
Assert ( ! ( " Images columns used in SectionedListPanel with no ImageList set " ) ) ;
}
}
else
{
TextImage * textImage = dynamic_cast < TextImage * > ( GetImageAtIndex ( i ) ) ;
if ( textImage )
{
textImage - > SetText ( m_pData - > GetString ( keyname , " " ) ) ;
textImage - > ResizeImageToContentMaxWidth ( maxWidth ) ;
// set the text color based on the selection state - if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
VPANEL focus = input ( ) - > GetFocus ( ) ;
if ( ! m_bOverrideColors )
{
if ( IsSelected ( ) & & ! m_pListPanel - > IsInEditMode ( ) )
{
if ( HasFocus ( ) | | ( focus & & ipanel ( ) - > HasParent ( focus , GetVParent ( ) ) ) )
{
textImage - > SetColor ( m_ArmedFgColor2 ) ;
}
else
{
textImage - > SetColor ( m_OutOfFocusSelectedTextColor ) ;
}
}
else if ( columnFlags & SectionedListPanel : : COLUMN_BRIGHT )
{
textImage - > SetColor ( m_ArmedFgColor1 ) ;
}
else
{
textImage - > SetColor ( m_FgColor2 ) ;
}
}
else
{
// custom colors
if ( IsSelected ( ) & & ( HasFocus ( ) | | ( focus & & ipanel ( ) - > HasParent ( focus , GetVParent ( ) ) ) ) )
{
textImage - > SetColor ( m_ArmedFgColor2 ) ;
}
else
{
textImage - > SetColor ( GetFgColor ( ) ) ;
}
}
}
image = textImage ;
}
// set the image position within the label
int imageWide = 0 , tall = 0 ;
int wide ;
if ( image )
{
image - > GetContentSize ( imageWide , tall ) ;
}
if ( maxWidth > = 0 )
{
wide = maxWidth ;
}
else
{
wide = imageWide ;
}
if ( i = = 0 & & ! ( columnFlags & SectionedListPanel : : COLUMN_IMAGE ) )
{
// first column has an extra indent
SetImageBounds ( i , xpos + COLUMN_DATA_INDENT , wide - ( COLUMN_DATA_INDENT + COLUMN_DATA_GAP ) ) ;
}
else
{
if ( columnFlags & SectionedListPanel : : COLUMN_CENTER )
{
int offSet = ( wide / 2 ) - ( imageWide / 2 ) ;
SetImageBounds ( i , xpos + offSet , wide - offSet - COLUMN_DATA_GAP ) ;
}
else if ( columnFlags & SectionedListPanel : : COLUMN_RIGHT )
{
SetImageBounds ( i , xpos + wide - imageWide , wide - COLUMN_DATA_GAP ) ;
}
else
{
SetImageBounds ( i , xpos , wide - COLUMN_DATA_GAP ) ;
}
}
xpos + = wide ;
}
}
BaseClass : : PerformLayout ( ) ;
}
virtual void ApplySchemeSettings ( IScheme * pScheme )
{
BaseClass : : ApplySchemeSettings ( pScheme ) ;
m_ArmedFgColor1 = GetSchemeColor ( " SectionedListPanel.BrightTextColor " , pScheme ) ;
m_ArmedFgColor2 = GetSchemeColor ( " SectionedListPanel.SelectedTextColor " , pScheme ) ;
m_OutOfFocusSelectedTextColor = GetSchemeColor ( " SectionedListPanel.OutOfFocusSelectedTextColor " , pScheme ) ;
m_ArmedBgColor = GetSchemeColor ( " SectionedListPanel.SelectedBgColor " , pScheme ) ;
m_FgColor2 = GetSchemeColor ( " SectionedListPanel.TextColor " , pScheme ) ;
m_BgColor = GetSchemeColor ( " SectionedListPanel.BgColor " , GetBgColor ( ) , pScheme ) ;
m_SelectionBG2Color = GetSchemeColor ( " SectionedListPanel.OutOfFocusSelectedBgColor " , pScheme ) ;
ClearImages ( ) ;
}
virtual void PaintBackground ( )
{
int wide , tall ;
GetSize ( wide , tall ) ;
if ( IsSelected ( ) & & ! m_pListPanel - > IsInEditMode ( ) )
{
VPANEL focus = input ( ) - > GetFocus ( ) ;
// if one of the children of the SectionedListPanel has focus, then 'we have focus' if we're selected
if ( HasFocus ( ) | | ( focus & & ipanel ( ) - > HasParent ( focus , GetVParent ( ) ) ) )
{
surface ( ) - > DrawSetColor ( m_ArmedBgColor ) ;
}
else
{
surface ( ) - > DrawSetColor ( m_SelectionBG2Color ) ;
}
}
else
{
surface ( ) - > DrawSetColor ( GetBgColor ( ) ) ;
}
surface ( ) - > DrawFilledRect ( 0 , 0 , wide , tall ) ;
}
virtual void OnMousePressed ( MouseCode code )
{
if ( code = = MOUSE_LEFT )
{
m_pListPanel - > PostActionSignal ( new KeyValues ( " ItemLeftClick " , " itemID " , m_iID ) ) ;
}
if ( code = = MOUSE_RIGHT )
{
KeyValues * msg = new KeyValues ( " ItemContextMenu " , " itemID " , m_iID ) ;
msg - > SetPtr ( " SubPanel " , this ) ;
m_pListPanel - > PostActionSignal ( msg ) ;
}
m_pListPanel - > SetSelectedItem ( this ) ;
}
void SetSelected ( bool state )
{
if ( m_bSelected ! = state )
{
if ( state )
{
RequestFocus ( ) ;
}
m_bSelected = state ;
SetPaintBackgroundEnabled ( state ) ;
InvalidateLayout ( ) ;
Repaint ( ) ;
}
}
bool IsSelected ( )
{
return m_bSelected ;
}
virtual void OnSetFocus ( )
{
InvalidateLayout ( ) ; // force the layout to be redone so we can change text color according to focus
BaseClass : : OnSetFocus ( ) ;
}
virtual void OnKillFocus ( )
{
InvalidateLayout ( ) ; // force the layout to be redone so we can change text color according to focus
BaseClass : : OnSetFocus ( ) ;
}
virtual void OnMouseDoublePressed ( MouseCode code )
{
if ( code = = MOUSE_LEFT )
{
m_pListPanel - > PostActionSignal ( new KeyValues ( " ItemDoubleLeftClick " , " itemID " , m_iID ) ) ;
// post up an enter key being hit
m_pListPanel - > OnKeyCodeTyped ( KEY_ENTER ) ;
}
else
{
OnMousePressed ( code ) ;
}
m_pListPanel - > SetSelectedItem ( this ) ;
}
void GetCellBounds ( int column , int & xpos , int & columnWide )
{
xpos = 0 , columnWide = 0 ;
int colCount = m_pListPanel - > GetColumnCountBySection ( m_iSectionID ) ;
for ( int i = 0 ; i < colCount ; i + + )
{
int maxWidth = m_pListPanel - > GetColumnWidthBySection ( m_iSectionID , i ) ;
IImage * image = GetImageAtIndex ( i ) ;
if ( ! image )
continue ;
// set the image position within the label
int wide , tall ;
image - > GetContentSize ( wide , tall ) ;
if ( maxWidth > = 0 )
{
wide = maxWidth ;
}
if ( i = = column )
{
// found the cell size, bail
columnWide = wide ;
return ;
}
xpos + = wide ;
}
}
virtual void SetOverrideColors ( bool state )
{
m_bOverrideColors = state ;
}
private :
SectionedListPanel * m_pListPanel ;
int m_iID ;
int m_iSectionID ;
KeyValues * m_pData ;
Color m_FgColor2 ;
Color m_BgColor ;
Color m_ArmedFgColor1 ;
Color m_ArmedFgColor2 ;
Color m_OutOfFocusSelectedTextColor ;
Color m_ArmedBgColor ;
Color m_SelectionBG2Color ;
CUtlVector < vgui : : TextImage * > m_TextImages ;
bool m_bSelected ;
bool m_bOverrideColors ;
} ;
} ; // namespace vgui
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
SectionedListPanel : : SectionedListPanel ( vgui : : Panel * parent , const char * name ) : BaseClass ( parent , name )
{
m_pScrollBar = new ScrollBar ( this , " SectionedScrollBar " , true ) ;
m_pScrollBar - > SetVisible ( false ) ;
m_pScrollBar - > AddActionSignalTarget ( this ) ;
m_iEditModeItemID = 0 ;
m_iEditModeColumn = 0 ;
m_bSortNeeded = false ;
m_bVerticalScrollbarEnabled = true ;
m_iLineSpacing = 20 ;
m_pImageList = NULL ;
m_bDeleteImageListWhenDone = false ;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
SectionedListPanel : : ~ SectionedListPanel ( )
{
}
//-----------------------------------------------------------------------------
// Purpose: Sorts the list
//-----------------------------------------------------------------------------
void SectionedListPanel : : ReSortList ( )
{
m_SortedItems . RemoveAll ( ) ;
int sectionStart = 0 ;
// layout the buttons
for ( int sectionIndex = 0 ; sectionIndex < m_Sections . Size ( ) ; sectionIndex + + )
{
section_t & section = m_Sections [ sectionIndex ] ;
sectionStart = m_SortedItems . Count ( ) ;
// find all the items in this section
for ( int i = m_Items . Head ( ) ; i ! = m_Items . InvalidIndex ( ) ; i = m_Items . Next ( i ) )
{
if ( m_Items [ i ] - > GetSectionID ( ) = = m_Sections [ sectionIndex ] . m_iID )
{
// insert the items sorted
if ( section . m_pSortFunc )
{
int insertionPoint = sectionStart ;
for ( ; insertionPoint < m_SortedItems . Count ( ) ; insertionPoint + + )
{
if ( section . m_pSortFunc ( this , i , m_SortedItems [ insertionPoint ] - > GetID ( ) ) )
break ;
}
if ( insertionPoint = = m_SortedItems . Count ( ) )
{
m_SortedItems . AddToTail ( m_Items [ i ] ) ;
}
else
{
m_SortedItems . InsertBefore ( insertionPoint , m_Items [ i ] ) ;
}
}
else
{
// just add to the end
m_SortedItems . AddToTail ( m_Items [ i ] ) ;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: iterates through and sets up the position of all the sections and items
//-----------------------------------------------------------------------------
void SectionedListPanel : : PerformLayout ( )
{
// lazy resort the list
if ( m_bSortNeeded )
{
ReSortList ( ) ;
m_bSortNeeded = false ;
}
BaseClass : : PerformLayout ( ) ;
LayoutPanels ( m_iContentHeight ) ;
int cx , cy , cwide , ctall ;
GetBounds ( cx , cy , cwide , ctall ) ;
if ( m_iContentHeight > ctall & & m_bVerticalScrollbarEnabled )
{
m_pScrollBar - > SetVisible ( true ) ;
m_pScrollBar - > MoveToFront ( ) ;
m_pScrollBar - > SetPos ( cwide - m_pScrollBar - > GetWide ( ) - 2 , 0 ) ;
m_pScrollBar - > SetSize ( m_pScrollBar - > GetWide ( ) , ctall - 2 ) ;
m_pScrollBar - > SetRangeWindow ( ctall ) ;
m_pScrollBar - > SetRange ( 0 , m_iContentHeight ) ;
m_pScrollBar - > InvalidateLayout ( ) ;
m_pScrollBar - > Repaint ( ) ;
// since we're just about to make the scrollbar visible, we need to re-layout
// the buttons since they depend on the scrollbar size
LayoutPanels ( m_iContentHeight ) ;
}
else
{
m_pScrollBar - > SetValue ( 0 ) ;
m_pScrollBar - > SetVisible ( false ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: lays out the sections and rows in the panel
//-----------------------------------------------------------------------------
void SectionedListPanel : : LayoutPanels ( int & contentTall )
{
int tall = GetSectionTall ( ) ;
int x = 5 , wide = GetWide ( ) - 10 ;
int y = 5 ;
if ( m_pScrollBar - > IsVisible ( ) )
{
y - = m_pScrollBar - > GetValue ( ) ;
wide - = m_pScrollBar - > GetWide ( ) ;
}
int iStart = - 1 ;
int iEnd = - 1 ;
// layout the buttons
for ( int sectionIndex = 0 ; sectionIndex < m_Sections . Size ( ) ; sectionIndex + + )
{
section_t & section = m_Sections [ sectionIndex ] ;
iStart = - 1 ;
iEnd = - 1 ;
for ( int i = 0 ; i < m_SortedItems . Count ( ) ; i + + )
{
if ( m_SortedItems [ i ] - > GetSectionID ( ) = = m_Sections [ sectionIndex ] . m_iID )
{
if ( iStart = = - 1 )
iStart = i ;
iEnd = i ;
}
}
// don't draw this section at all if their are no item in it
if ( iStart = = - 1 & & ! section . m_bAlwaysVisible )
{
section . m_pHeader - > SetVisible ( false ) ;
continue ;
}
// draw the header
section . m_pHeader - > SetBounds ( x , y , wide , tall ) ;
section . m_pHeader - > SetVisible ( true ) ;
y + = tall ;
if ( iStart = = - 1 & & section . m_bAlwaysVisible )
{
}
else
{
// arrange all the items in this section underneath
for ( int i = iStart ; i < = iEnd ; i + + )
{
CItemButton * item = m_SortedItems [ i ] ; //items[i];
item - > SetBounds ( x , y , wide , m_iLineSpacing ) ;
// setup edit mode
if ( m_hEditModePanel . Get ( ) & & m_iEditModeItemID = = item - > GetID ( ) )
{
int cx , cwide ;
item - > GetCellBounds ( 1 , cx , cwide ) ;
m_hEditModePanel - > SetBounds ( cx , y , cwide , tall ) ;
}
y + = m_iLineSpacing ;
}
}
// add in a little boundry at the bottom
y + = SECTION_GAP ;
}
// calculate height
contentTall = y ;
if ( m_pScrollBar - > IsVisible ( ) )
{
contentTall + = m_pScrollBar - > GetValue ( ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Ensures that the specified item is visible in the display
//-----------------------------------------------------------------------------
void SectionedListPanel : : ScrollToItem ( int iItem )
{
int tall = GetSectionTall ( ) ;
int itemX , itemY ;
int nCurrentValue = m_pScrollBar - > GetValue ( ) ;
// find out where the item is
m_Items [ iItem ] - > GetPos ( itemX , itemY ) ;
// add in the current scrollbar position
itemY + = nCurrentValue ;
// compare that in the list
int cx , cy , cwide , ctall ;
GetBounds ( cx , cy , cwide , ctall ) ;
if ( m_iContentHeight > ctall )
{
if ( itemY < nCurrentValue )
{
// scroll up
m_pScrollBar - > SetValue ( itemY ) ;
}
else if ( itemY > nCurrentValue + ctall - tall )
{
// scroll down
m_pScrollBar - > SetValue ( itemY - ctall + tall ) ;
}
else
{
// keep the current value
}
}
else
{
// area isn't big enough, just remove the scrollbar
m_pScrollBar - > SetValue ( 0 ) ;
}
// reset scrollbar
Repaint ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: sets background color & border
//-----------------------------------------------------------------------------
void SectionedListPanel : : ApplySchemeSettings ( IScheme * pScheme )
{
BaseClass : : ApplySchemeSettings ( pScheme ) ;
SetBgColor ( GetSchemeColor ( " SectionedListPanel.BgColor " , GetBgColor ( ) , pScheme ) ) ;
SetBorder ( pScheme - > GetBorder ( " ButtonDepressedBorder " ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void SectionedListPanel : : ApplySettings ( KeyValues * inResourceData )
{
BaseClass : : ApplySettings ( inResourceData ) ;
m_iLineSpacing = inResourceData - > GetInt ( " linespacing " , 0 ) ;
if ( ! m_iLineSpacing )
{
m_iLineSpacing = 20 ;
}
if ( IsProportional ( ) )
{
m_iLineSpacing = scheme ( ) - > GetProportionalScaledValueEx ( GetScheme ( ) , m_iLineSpacing ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: passes on proportional state to children
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetProportional ( bool state )
{
BaseClass : : SetProportional ( state ) ;
// now setup the section headers and items
int i ;
for ( i = 0 ; i < m_Sections . Count ( ) ; i + + )
{
m_Sections [ i ] . m_pHeader - > SetProportional ( state ) ;
}
FOR_EACH_LL ( m_Items , j )
{
m_Items [ j ] - > SetProportional ( state ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: sets whether or not the vertical scrollbar should ever be displayed
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetVerticalScrollbar ( bool state )
{
m_bVerticalScrollbarEnabled = state ;
}
//-----------------------------------------------------------------------------
// Purpose: adds a new section
//-----------------------------------------------------------------------------
void SectionedListPanel : : AddSection ( int sectionID , const char * name , SectionSortFunc_t sortFunc )
{
CSectionHeader * header = SETUP_PANEL ( new CSectionHeader ( this , name , sectionID ) ) ;
AddSectionHelper ( sectionID , header , sortFunc ) ;
}
//-----------------------------------------------------------------------------
// Purpose: adds a new section
//-----------------------------------------------------------------------------
void SectionedListPanel : : AddSection ( int sectionID , const wchar_t * name , SectionSortFunc_t sortFunc )
{
CSectionHeader * header = SETUP_PANEL ( new CSectionHeader ( this , name , sectionID ) ) ;
AddSectionHelper ( sectionID , header , sortFunc ) ;
}
//-----------------------------------------------------------------------------
// Purpose: helper function for AddSection
//-----------------------------------------------------------------------------
void SectionedListPanel : : AddSectionHelper ( int sectionID , CSectionHeader * header , SectionSortFunc_t sortFunc )
{
int index = m_Sections . AddToTail ( ) ;
m_Sections [ index ] . m_iID = sectionID ;
m_Sections [ index ] . m_pHeader = header ;
m_Sections [ index ] . m_pSortFunc = sortFunc ;
m_Sections [ index ] . m_bAlwaysVisible = false ;
}
//-----------------------------------------------------------------------------
// Purpose: removes all the sections from the current panel
//-----------------------------------------------------------------------------
void SectionedListPanel : : RemoveAllSections ( )
{
for ( int i = 0 ; i < m_Sections . Count ( ) ; i + + )
{
if ( ! m_Sections . IsValidIndex ( i ) )
continue ;
m_Sections [ i ] . m_pHeader - > SetVisible ( false ) ;
m_Sections [ i ] . m_pHeader - > MarkForDeletion ( ) ;
}
m_Sections . RemoveAll ( ) ;
m_Sections . Purge ( ) ;
m_SortedItems . RemoveAll ( ) ;
InvalidateLayout ( ) ;
ReSortList ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: adds a new column to a section
//-----------------------------------------------------------------------------
bool SectionedListPanel : : AddColumnToSection ( int sectionID , const char * columnName , const char * columnText , int columnFlags , int width , HFont fallbackFont /*= INVALID_FONT*/ )
{
wchar_t wtext [ 64 ] ;
wchar_t * pwtext = g_pVGuiLocalize - > Find ( columnText ) ;
if ( ! pwtext )
{
g_pVGuiLocalize - > ConvertANSIToUnicode ( columnText , wtext , sizeof ( wtext ) ) ;
pwtext = wtext ;
}
return AddColumnToSection ( sectionID , columnName , pwtext , columnFlags , width , fallbackFont ) ;
}
//-----------------------------------------------------------------------------
// Purpose: as above but with wchar_t's
//-----------------------------------------------------------------------------
bool SectionedListPanel : : AddColumnToSection ( int sectionID , const char * columnName , const wchar_t * columnText , int columnFlags , int width , HFont fallbackFont /*= INVALID_FONT*/ )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 )
return false ;
section_t & section = m_Sections [ index ] ;
// add the new column to the sections' list
index = section . m_Columns . AddToTail ( ) ;
column_t & column = section . m_Columns [ index ] ;
Q_strncpy ( column . m_szColumnName , columnName , sizeof ( column . m_szColumnName ) ) ;
wcsncpy ( column . m_szColumnText , columnText , sizeof ( column . m_szColumnText ) / sizeof ( wchar_t ) ) ;
column . m_szColumnText [ sizeof ( column . m_szColumnText ) / sizeof ( wchar_t ) - 1 ] = 0 ;
column . m_iColumnFlags = columnFlags ;
column . m_iWidth = width ;
column . m_hFallbackFont = fallbackFont ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: modifies the text in an existing column
//-----------------------------------------------------------------------------
bool SectionedListPanel : : ModifyColumn ( int sectionID , const char * columnName , const wchar_t * columnText )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 )
return false ;
section_t & section = m_Sections [ index ] ;
// find the specified column
int columnIndex ;
for ( columnIndex = 0 ; columnIndex < section . m_Columns . Count ( ) ; columnIndex + + )
{
if ( ! stricmp ( section . m_Columns [ columnIndex ] . m_szColumnName , columnName ) )
break ;
}
if ( ! section . m_Columns . IsValidIndex ( columnIndex ) )
return false ;
column_t & column = section . m_Columns [ columnIndex ] ;
// modify the text
wcsncpy ( column . m_szColumnText , columnText , sizeof ( column . m_szColumnText ) / sizeof ( wchar_t ) ) ;
column . m_szColumnText [ sizeof ( column . m_szColumnText ) / sizeof ( wchar_t ) - 1 ] = 0 ;
section . m_pHeader - > InvalidateLayout ( ) ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: adds an item to the list; returns itemID
//-----------------------------------------------------------------------------
int SectionedListPanel : : AddItem ( int sectionID , const KeyValues * data )
{
int itemID = GetNewItemButton ( ) ;
ModifyItem ( itemID , sectionID , data ) ;
// not sorted but in list
m_SortedItems . AddToTail ( m_Items [ itemID ] ) ;
m_bSortNeeded = true ;
return itemID ;
}
//-----------------------------------------------------------------------------
// Purpose: modifies an existing item; returns false if the item does not exist
//-----------------------------------------------------------------------------
bool SectionedListPanel : : ModifyItem ( int itemID , int sectionID , const KeyValues * data )
{
if ( ! m_Items . IsValidIndex ( itemID ) )
return false ;
InvalidateLayout ( ) ;
m_Items [ itemID ] - > SetSectionID ( sectionID ) ;
m_Items [ itemID ] - > SetData ( data ) ;
m_Items [ itemID ] - > InvalidateLayout ( ) ;
m_bSortNeeded = true ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetItemFgColor ( int itemID , Color color )
{
Assert ( m_Items . IsValidIndex ( itemID ) ) ;
if ( ! m_Items . IsValidIndex ( itemID ) )
return ;
m_Items [ itemID ] - > SetFgColor ( color ) ;
m_Items [ itemID ] - > SetOverrideColors ( true ) ;
m_Items [ itemID ] - > InvalidateLayout ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: sets the color of a section text & underline
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetSectionFgColor ( int sectionID , Color color )
{
if ( ! m_Sections . IsValidIndex ( sectionID ) )
return ;
m_Sections [ sectionID ] . m_pHeader - > SetColor ( color ) ;
}
//-----------------------------------------------------------------------------
// Purpose: forces a section to always be visible
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetSectionAlwaysVisible ( int sectionID , bool visible )
{
if ( ! m_Sections . IsValidIndex ( sectionID ) )
return ;
m_Sections [ sectionID ] . m_bAlwaysVisible = visible ;
}
//-----------------------------------------------------------------------------
// Purpose: removes an item from the list; returns false if the item does not exist or is already removed
//-----------------------------------------------------------------------------
bool SectionedListPanel : : RemoveItem ( int itemID )
{
if ( ! m_Items . IsValidIndex ( itemID ) )
return false ;
m_SortedItems . FindAndRemove ( m_Items [ itemID ] ) ;
m_bSortNeeded = true ;
m_Items [ itemID ] - > MarkForDeletion ( ) ;
m_Items . Remove ( itemID ) ;
InvalidateLayout ( ) ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: returns the number of columns in a section
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetColumnCountBySection ( int sectionID )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 )
return NULL ;
return m_Sections [ index ] . m_Columns . Size ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: returns the name of a column by section and column index; returns NULL if there are no more columns
// valid range of columnIndex is [0, GetColumnCountBySection)
//-----------------------------------------------------------------------------
const char * SectionedListPanel : : GetColumnNameBySection ( int sectionID , int columnIndex )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 | | columnIndex > = m_Sections [ index ] . m_Columns . Size ( ) )
return NULL ;
return m_Sections [ index ] . m_Columns [ columnIndex ] . m_szColumnName ;
}
//-----------------------------------------------------------------------------
// Purpose: returns the text for a column by section and column index
//-----------------------------------------------------------------------------
const wchar_t * SectionedListPanel : : GetColumnTextBySection ( int sectionID , int columnIndex )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 | | columnIndex > = m_Sections [ index ] . m_Columns . Size ( ) )
return NULL ;
return m_Sections [ index ] . m_Columns [ columnIndex ] . m_szColumnText ;
}
//-----------------------------------------------------------------------------
// Purpose: returns the type of a column by section and column index
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetColumnFlagsBySection ( int sectionID , int columnIndex )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 )
return 0 ;
if ( columnIndex > = m_Sections [ index ] . m_Columns . Size ( ) )
return 0 ;
return m_Sections [ index ] . m_Columns [ columnIndex ] . m_iColumnFlags ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetColumnWidthBySection ( int sectionID , int columnIndex )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 )
return 0 ;
if ( columnIndex > = m_Sections [ index ] . m_Columns . Size ( ) )
return 0 ;
return m_Sections [ index ] . m_Columns [ columnIndex ] . m_iWidth ;
}
//-----------------------------------------------------------------------------
// Purpose: returns -1 if section not found
//-----------------------------------------------------------------------------
int SectionedListPanel : : FindSectionIndexByID ( int sectionID )
{
for ( int i = 0 ; i < m_Sections . Size ( ) ; i + + )
{
if ( m_Sections [ i ] . m_iID = = sectionID )
{
return i ;
}
}
return - 1 ;
}
//-----------------------------------------------------------------------------
// Purpose: Called when the scrollbar is moved
//-----------------------------------------------------------------------------
void SectionedListPanel : : OnSliderMoved ( )
{
InvalidateLayout ( ) ;
Repaint ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Scrolls the list according to the mouse wheel movement
//-----------------------------------------------------------------------------
void SectionedListPanel : : OnMouseWheeled ( int delta )
{
if ( m_hEditModePanel . Get ( ) )
{
// ignore mouse wheel in edit mode, forward right up to parent
CallParentFunction ( new KeyValues ( " MouseWheeled " , " delta " , delta ) ) ;
return ;
}
// scroll the window based on the delta
int val = m_pScrollBar - > GetValue ( ) ;
val - = ( delta * BUTTON_HEIGHT_DEFAULT * 3 ) ;
m_pScrollBar - > SetValue ( val ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Resets the scrollbar position on size change
//-----------------------------------------------------------------------------
void SectionedListPanel : : OnSizeChanged ( int wide , int tall )
{
BaseClass : : OnSizeChanged ( wide , tall ) ;
m_pScrollBar - > SetValue ( 0 ) ;
InvalidateLayout ( ) ;
Repaint ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: deselects any items
//-----------------------------------------------------------------------------
void SectionedListPanel : : OnMousePressed ( MouseCode code )
{
ClearSelection ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: deselects any items
//-----------------------------------------------------------------------------
void SectionedListPanel : : ClearSelection ( void )
{
SetSelectedItem ( ( CItemButton * ) NULL ) ;
}
void SectionedListPanel : : MoveSelectionDown ( void )
{
int itemID = GetSelectedItem ( ) ;
Assert ( itemID ! = - 1 ) ;
if ( ! m_SortedItems . Count ( ) ) // if the list has been emptied
return ;
int i ;
for ( i = 0 ; i < m_SortedItems . Count ( ) ; i + + )
{
if ( m_SortedItems [ i ] - > GetID ( ) = = itemID )
break ;
}
Assert ( i ! = m_SortedItems . Count ( ) ) ;
// we're already on the end
if ( i = = m_SortedItems . Count ( ) - 1 )
return ;
int newItemID = m_SortedItems [ i + 1 ] - > GetID ( ) ;
SetSelectedItem ( m_Items [ newItemID ] ) ;
ScrollToItem ( newItemID ) ;
}
void SectionedListPanel : : MoveSelectionUp ( void )
{
int itemID = GetSelectedItem ( ) ;
Assert ( itemID ! = - 1 ) ;
if ( ! m_SortedItems . Count ( ) ) // if the list has been emptied
return ;
int i ;
for ( i = 0 ; i < m_SortedItems . Count ( ) ; i + + )
{
if ( m_SortedItems [ i ] - > GetID ( ) = = itemID )
break ;
}
Assert ( i ! = m_SortedItems . Count ( ) ) ;
// we're already on the end
if ( i = = 0 )
return ;
int newItemID = m_SortedItems [ i - 1 ] - > GetID ( ) ;
SetSelectedItem ( m_Items [ newItemID ] ) ;
ScrollToItem ( newItemID ) ;
}
//-----------------------------------------------------------------------------
// Purpose: arrow key movement handler
//-----------------------------------------------------------------------------
void SectionedListPanel : : OnKeyCodeTyped ( KeyCode code )
{
if ( m_hEditModePanel . Get ( ) )
{
// ignore arrow keys in edit mode
// forward right up to parent so that tab focus change doesn't occur
CallParentFunction ( new KeyValues ( " KeyCodeTyped " , " code " , code ) ) ;
return ;
}
int buttonTall = GetSectionTall ( ) ;
if ( code = = KEY_DOWN )
{
MoveSelectionDown ( ) ;
return ;
}
else if ( code = = KEY_UP )
{
MoveSelectionUp ( ) ;
return ;
}
else if ( code = = KEY_PAGEDOWN )
{
// calculate info for # of rows
int cx , cy , cwide , ctall ;
GetBounds ( cx , cy , cwide , ctall ) ;
int rowsperpage = ctall / buttonTall ;
int itemID = GetSelectedItem ( ) ;
int lastValidItem = itemID ;
int secID = m_Items [ itemID ] - > GetSectionID ( ) ;
int i = 0 ;
int row = m_SortedItems . Find ( m_Items [ itemID ] ) ;
while ( i < rowsperpage )
{
if ( m_SortedItems . IsValidIndex ( + + row ) )
{
itemID = m_SortedItems [ row ] - > GetID ( ) ;
lastValidItem = itemID ;
i + + ;
// if we switched sections, then count the section header as a row
if ( m_Items [ itemID ] - > GetSectionID ( ) ! = secID )
{
secID = m_Items [ itemID ] - > GetSectionID ( ) ;
i + + ;
}
}
else
{
itemID = lastValidItem ;
break ;
}
}
SetSelectedItem ( m_Items [ itemID ] ) ;
ScrollToItem ( itemID ) ;
}
else if ( code = = KEY_PAGEUP )
{
// calculate info for # of rows
int cx , cy , cwide , ctall ;
GetBounds ( cx , cy , cwide , ctall ) ;
int rowsperpage = ctall / buttonTall ;
int itemID = GetSelectedItem ( ) ;
int lastValidItem = itemID ;
int secID = m_Items [ itemID ] - > GetSectionID ( ) ;
int i = 0 ;
int row = m_SortedItems . Find ( m_Items [ itemID ] ) ;
while ( i < rowsperpage )
{
if ( m_SortedItems . IsValidIndex ( - - row ) )
{
itemID = m_SortedItems [ row ] - > GetID ( ) ;
lastValidItem = itemID ;
i + + ;
// if we switched sections, then count the section header as a row
if ( m_Items [ itemID ] - > GetSectionID ( ) ! = secID )
{
secID = m_Items [ itemID ] - > GetSectionID ( ) ;
i + + ;
}
}
else
{
SetSelectedItem ( m_Items [ lastValidItem ] ) ;
m_pScrollBar - > SetValue ( 0 ) ;
return ;
}
}
SetSelectedItem ( m_Items [ itemID ] ) ;
ScrollToItem ( itemID ) ;
}
else if ( code = = KEY_LEFT | | code = = KEY_RIGHT )
{
}
else
{
BaseClass : : OnKeyCodeTyped ( code ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Clears the list
//-----------------------------------------------------------------------------
void SectionedListPanel : : DeleteAllItems ( )
{
FOR_EACH_LL ( m_Items , i )
{
m_Items [ i ] - > SetVisible ( false ) ;
m_Items [ i ] - > Clear ( ) ;
// don't delete, move to free list
int freeIndex = m_FreeItems . AddToTail ( ) ;
m_FreeItems [ freeIndex ] = m_Items [ i ] ;
}
m_Items . RemoveAll ( ) ;
m_SortedItems . RemoveAll ( ) ;
m_hSelectedItem = NULL ;
InvalidateLayout ( ) ;
m_bSortNeeded = true ;
}
//-----------------------------------------------------------------------------
// Purpose: Changes the current list selection
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetSelectedItem ( CItemButton * item )
{
if ( m_hSelectedItem . Get ( ) = = item )
return ;
// deselect the current item
if ( m_hSelectedItem . Get ( ) )
{
m_hSelectedItem - > SetSelected ( false ) ;
}
// set the new item
m_hSelectedItem = item ;
if ( m_hSelectedItem . Get ( ) )
{
m_hSelectedItem - > SetSelected ( true ) ;
}
Repaint ( ) ;
PostActionSignal ( new KeyValues ( " ItemSelected " , " itemID " , m_hSelectedItem . Get ( ) ? m_hSelectedItem - > GetID ( ) : - 1 ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetSelectedItem ( )
{
if ( m_hSelectedItem . Get ( ) )
{
return m_hSelectedItem - > GetID ( ) ;
}
return - 1 ;
}
//-----------------------------------------------------------------------------
// Purpose: sets which item is currently selected
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetSelectedItem ( int itemID )
{
if ( m_Items . IsValidIndex ( itemID ) )
{
SetSelectedItem ( m_Items [ itemID ] ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: returns the data of a selected item
//-----------------------------------------------------------------------------
KeyValues * SectionedListPanel : : GetItemData ( int itemID )
{
Assert ( m_Items . IsValidIndex ( itemID ) ) ;
if ( ! m_Items . IsValidIndex ( itemID ) )
return NULL ;
return m_Items [ itemID ] - > GetData ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: returns what section an item is in
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetItemSection ( int itemID )
{
if ( ! m_Items . IsValidIndex ( itemID ) )
return - 1 ;
return m_Items [ itemID ] - > GetSectionID ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the itemID is valid for use
//-----------------------------------------------------------------------------
bool SectionedListPanel : : IsItemIDValid ( int itemID )
{
return m_Items . IsValidIndex ( itemID ) ;
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the itemID is valid for use
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetHighestItemID ( )
{
return m_Items . MaxElementIndex ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: item iterators
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetItemCount ( )
{
return m_SortedItems . Count ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: item iterators
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetItemIDFromRow ( int row )
{
if ( ! m_SortedItems . IsValidIndex ( row ) )
return - 1 ;
return m_SortedItems [ row ] - > GetID ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: returns the row that this itemID occupies. -1 if the itemID is invalid
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetRowFromItemID ( int itemID )
{
for ( int i = 0 ; i < m_SortedItems . Count ( ) ; i + + )
{
if ( m_SortedItems [ i ] - > GetID ( ) = = itemID )
{
return i ;
}
}
return - 1 ;
}
//-----------------------------------------------------------------------------
// Purpose: gets the local coordinates of a cell
//-----------------------------------------------------------------------------
bool SectionedListPanel : : GetCellBounds ( int itemID , int column , int & x , int & y , int & wide , int & tall )
{
x = y = wide = tall = 0 ;
if ( ! IsItemIDValid ( itemID ) )
return false ;
// get the item
CItemButton * item = m_Items [ itemID ] ;
if ( ! item - > IsVisible ( ) )
return false ;
//!! ignores column for now
item - > GetBounds ( x , y , wide , tall ) ;
item - > GetCellBounds ( column , x , wide ) ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: forces an item to redraw
//-----------------------------------------------------------------------------
void SectionedListPanel : : InvalidateItem ( int itemID )
{
if ( ! IsItemIDValid ( itemID ) )
return ;
m_Items [ itemID ] - > InvalidateLayout ( ) ;
m_Items [ itemID ] - > Repaint ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: set up a field for editing
//-----------------------------------------------------------------------------
void SectionedListPanel : : EnterEditMode ( int itemID , int column , vgui : : Panel * editPanel )
{
m_hEditModePanel = editPanel ;
m_iEditModeItemID = itemID ;
m_iEditModeColumn = column ;
editPanel - > SetParent ( this ) ;
editPanel - > SetVisible ( true ) ;
editPanel - > RequestFocus ( ) ;
editPanel - > MoveToFront ( ) ;
InvalidateLayout ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: leaves editing mode
//-----------------------------------------------------------------------------
void SectionedListPanel : : LeaveEditMode ( )
{
if ( m_hEditModePanel . Get ( ) )
{
InvalidateItem ( m_iEditModeItemID ) ;
m_hEditModePanel - > SetVisible ( false ) ;
m_hEditModePanel - > SetParent ( ( Panel * ) NULL ) ;
m_hEditModePanel = NULL ;
}
}
//-----------------------------------------------------------------------------
// Purpose: returns true if we are currently in inline editing mode
//-----------------------------------------------------------------------------
bool SectionedListPanel : : IsInEditMode ( )
{
return ( m_hEditModePanel . Get ( ) ! = NULL ) ;
}
//-----------------------------------------------------------------------------
// Purpose: list used to match indexes in image columns to image pointers
//-----------------------------------------------------------------------------
void SectionedListPanel : : SetImageList ( ImageList * imageList , bool deleteImageListWhenDone )
{
m_bDeleteImageListWhenDone = deleteImageListWhenDone ;
m_pImageList = imageList ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void SectionedListPanel : : OnSetFocus ( )
{
if ( m_hSelectedItem . Get ( ) )
{
m_hSelectedItem - > RequestFocus ( ) ;
}
else
{
BaseClass : : OnSetFocus ( ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetSectionTall ( )
{
if ( m_Sections . Count ( ) )
{
HFont font = m_Sections [ 0 ] . m_pHeader - > GetFont ( ) ;
if ( font ! = INVALID_FONT )
{
return surface ( ) - > GetFontTall ( font ) + BUTTON_HEIGHT_SPACER ;
}
}
return BUTTON_HEIGHT_DEFAULT ;
}
//-----------------------------------------------------------------------------
// Purpose: returns the size required to fully draw the contents of the panel
//-----------------------------------------------------------------------------
void SectionedListPanel : : GetContentSize ( int & wide , int & tall )
{
// make sure our layout is done
if ( IsLayoutInvalid ( ) )
{
if ( m_bSortNeeded )
{
ReSortList ( ) ;
m_bSortNeeded = false ;
}
LayoutPanels ( m_iContentHeight ) ;
}
wide = GetWide ( ) ;
tall = m_iContentHeight ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the index of a new item button
//-----------------------------------------------------------------------------
int SectionedListPanel : : GetNewItemButton ( )
{
int itemID = m_Items . AddToTail ( ) ;
if ( m_FreeItems . Count ( ) )
{
// reusing an existing CItemButton
m_Items [ itemID ] = m_FreeItems [ m_FreeItems . Head ( ) ] ;
m_Items [ itemID ] - > SetID ( itemID ) ;
m_Items [ itemID ] - > SetVisible ( true ) ;
m_FreeItems . Remove ( m_FreeItems . Head ( ) ) ;
}
else
{
// create a new CItemButton
m_Items [ itemID ] = SETUP_PANEL ( new CItemButton ( this , itemID ) ) ;
}
return itemID ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns fallback font to use for text image for this column
// Input : sectionID -
// columnIndex -
// Output : virtual HFont
//-----------------------------------------------------------------------------
HFont SectionedListPanel : : GetColumnFallbackFontBySection ( int sectionID , int columnIndex )
{
int index = FindSectionIndexByID ( sectionID ) ;
if ( index < 0 )
return INVALID_FONT ;
if ( columnIndex > = m_Sections [ index ] . m_Columns . Size ( ) )
return INVALID_FONT ;
return m_Sections [ index ] . m_Columns [ columnIndex ] . m_hFallbackFont ;
}