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.
2272 lines
64 KiB
2272 lines
64 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// 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;
|
||
|
|
||
|
namespace vgui
|
||
|
{
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: header label that separates and names each section
|
||
|
//-----------------------------------------------------------------------------
|
||
|
SectionedListPanelHeader::SectionedListPanelHeader(SectionedListPanel *parent, const char *name, int sectionID) : Label(parent, name, "")
|
||
|
{
|
||
|
m_pListPanel = parent;
|
||
|
m_iSectionID = sectionID;
|
||
|
SetTextImageIndex(-1);
|
||
|
ClearImages();
|
||
|
SetPaintBackgroundEnabled( false );
|
||
|
m_bDrawDividerBar = true;
|
||
|
}
|
||
|
|
||
|
SectionedListPanelHeader::SectionedListPanelHeader(SectionedListPanel *parent, const wchar_t *name, int sectionID) : Label(parent, "SectionHeader", "")
|
||
|
{
|
||
|
SetText(name);
|
||
|
SetVisible(false);
|
||
|
m_pListPanel = parent;
|
||
|
m_iSectionID = sectionID;
|
||
|
SetTextImageIndex(-1);
|
||
|
ClearImages();
|
||
|
m_bDrawDividerBar = true;
|
||
|
}
|
||
|
|
||
|
void SectionedListPanelHeader::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();
|
||
|
|
||
|
HFont hFont = m_pListPanel->GetHeaderFont();
|
||
|
if ( hFont != INVALID_FONT )
|
||
|
{
|
||
|
SetFont( hFont );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetFont(pScheme->GetFont("DefaultVerySmall", IsProportional()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SectionedListPanelHeader::Paint()
|
||
|
{
|
||
|
BaseClass::Paint();
|
||
|
|
||
|
if ( m_bDrawDividerBar )
|
||
|
{
|
||
|
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 SectionedListPanelHeader::SetColor(Color col)
|
||
|
{
|
||
|
m_SectionDividerColor = col;
|
||
|
SetFgColor(col);
|
||
|
}
|
||
|
void SectionedListPanelHeader::SetDividerColor(Color col )
|
||
|
{
|
||
|
m_SectionDividerColor = col;
|
||
|
}
|
||
|
|
||
|
void SectionedListPanelHeader::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, wide - SectionedListPanel::COLUMN_DATA_GAP);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetImageBounds(i, xpos, wide - SectionedListPanel::COLUMN_DATA_GAP);
|
||
|
}
|
||
|
xpos += columnWidth;
|
||
|
|
||
|
if (!(columnFlags & SectionedListPanel::HEADER_IMAGE))
|
||
|
{
|
||
|
Assert(dynamic_cast<TextImage *>(image) != NULL);
|
||
|
TextImage *textImage = (TextImage *)image;
|
||
|
textImage->SetFont(GetFont());
|
||
|
textImage->SetText(m_pListPanel->GetColumnTextBySection(m_iSectionID, i));
|
||
|
textImage->ResizeImageToContentMaxWidth( maxWidth );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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();
|
||
|
m_nHorizFillInset = 0;
|
||
|
}
|
||
|
|
||
|
~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)
|
||
|
{
|
||
|
const wchar* pwszOverride = m_pData->GetWString( keyname, NULL );
|
||
|
if ( pwszOverride && pwszOverride[0] != '#' )
|
||
|
{
|
||
|
textImage->SetText( pwszOverride );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
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
|
||
|
{
|
||
|
Color *clrOverride = m_pListPanel->GetColorOverrideForCell(m_iSectionID, m_iID, i);
|
||
|
textImage->SetColor( (clrOverride != NULL) ? *clrOverride : 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 + SectionedListPanel::COLUMN_DATA_INDENT, wide - (SectionedListPanel::COLUMN_DATA_INDENT + SectionedListPanel::COLUMN_DATA_GAP));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (columnFlags & SectionedListPanel::COLUMN_CENTER)
|
||
|
{
|
||
|
int offSet = (wide / 2) - (imageWide / 2);
|
||
|
SetImageBounds(i, xpos + offSet, wide - offSet - SectionedListPanel::COLUMN_DATA_GAP);
|
||
|
}
|
||
|
else if (columnFlags & SectionedListPanel::COLUMN_RIGHT)
|
||
|
{
|
||
|
SetImageBounds(i, xpos + wide - imageWide, wide - SectionedListPanel::COLUMN_DATA_GAP);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetImageBounds(i, xpos, wide - SectionedListPanel::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);
|
||
|
|
||
|
|
||
|
HFont hFont = m_pListPanel->GetRowFont();
|
||
|
if ( hFont != INVALID_FONT )
|
||
|
{
|
||
|
SetFont( hFont );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const char *fontName = pScheme->GetResourceString( "SectionedListPanel.Font" );
|
||
|
HFont font = pScheme->GetFont(fontName, IsProportional());
|
||
|
if ( font != INVALID_FONT )
|
||
|
{
|
||
|
SetFont( font );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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, m_nHorizFillInset, wide, tall - m_nHorizFillInset);
|
||
|
}
|
||
|
|
||
|
virtual void Paint()
|
||
|
{
|
||
|
BaseClass::Paint();
|
||
|
|
||
|
if ( !m_bShowColumns )
|
||
|
return;
|
||
|
|
||
|
// Debugging code to show column widths
|
||
|
int wide, tall;
|
||
|
GetSize(wide, tall);
|
||
|
surface()->DrawSetColor( 255,255,255,255 );
|
||
|
surface()->DrawOutlinedRect(0, 0, wide, tall);
|
||
|
|
||
|
int colCount = m_pListPanel->GetColumnCountBySection(m_iSectionID);
|
||
|
if (m_pData && colCount >= 0)
|
||
|
{
|
||
|
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))
|
||
|
{
|
||
|
if (imageIndex > 0)
|
||
|
{
|
||
|
image = m_pListPanel->m_pImageList->GetImage(imageIndex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
image = GetImageAtIndex(i);
|
||
|
}
|
||
|
|
||
|
int imageWide = 0;
|
||
|
if (image)
|
||
|
{
|
||
|
image->GetContentSize(imageWide, tall);
|
||
|
}
|
||
|
if (maxWidth >= 0)
|
||
|
{
|
||
|
wide = maxWidth;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wide = imageWide;
|
||
|
}
|
||
|
|
||
|
xpos += wide;//max(maxWidth,wide);
|
||
|
surface()->DrawOutlinedRect( xpos, 0, xpos, GetTall() );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual void OnMousePressed(MouseCode code)
|
||
|
{
|
||
|
if ( m_pListPanel && m_pListPanel->IsClickable() && IsEnabled() )
|
||
|
{
|
||
|
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)
|
||
|
{
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
// [tj] Only do this if clicking is enabled.
|
||
|
//=============================================================================
|
||
|
if (m_pListPanel && m_pListPanel->IsClickable())
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
// [menglish] gets the local coordinates of a cell using the max width for every column
|
||
|
//=============================================================================
|
||
|
|
||
|
void GetMaxCellBounds(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);
|
||
|
|
||
|
if (i == column)
|
||
|
{
|
||
|
// found the cell size, bail
|
||
|
columnWide = maxWidth;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
xpos += maxWidth;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================
|
||
|
|
||
|
virtual void SetOverrideColors( bool state )
|
||
|
{
|
||
|
m_bOverrideColors = state;
|
||
|
}
|
||
|
|
||
|
void SetShowColumns( bool bShow )
|
||
|
{
|
||
|
m_bShowColumns = bShow;
|
||
|
}
|
||
|
|
||
|
void SetItemBgHorizFillInset( int nHorizFillInset ){ m_nHorizFillInset = nHorizFillInset; }
|
||
|
|
||
|
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;
|
||
|
bool m_bShowColumns;
|
||
|
int m_nHorizFillInset;
|
||
|
};
|
||
|
|
||
|
}; // namespace vgui
|
||
|
|
||
|
DECLARE_BUILD_FACTORY( SectionedListPanel );
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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 = DEFAULT_LINE_SPACING;
|
||
|
m_iLineGap = 0;
|
||
|
m_iSectionGap = DEFAULT_SECTION_GAP;
|
||
|
|
||
|
m_pImageList = NULL;
|
||
|
m_bDeleteImageListWhenDone = false;
|
||
|
|
||
|
m_hHeaderFont = INVALID_FONT;
|
||
|
m_hRowFont = INVALID_FONT;
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
//=============================================================================
|
||
|
// [tj] Default clickability to true so existing controls aren't affected.
|
||
|
m_clickable = true;
|
||
|
// [tj] draw section headers by default so existing controls aren't affected.
|
||
|
m_bDrawSectionHeaders = true;
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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 §ion = 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);
|
||
|
|
||
|
bool bWasVisible = m_pScrollBar->IsVisible();
|
||
|
m_pScrollBar->SetVisible(false);
|
||
|
|
||
|
// When we hide the scrollbar, we need to layout the buttons because they'll have more width to work with
|
||
|
if ( bWasVisible )
|
||
|
{
|
||
|
LayoutPanels(m_iContentHeight);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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
|
||
|
bool bFirstVisibleSection = true;
|
||
|
for (int sectionIndex = 0; sectionIndex < m_Sections.Size(); sectionIndex++)
|
||
|
{
|
||
|
section_t §ion = 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 there are no items in it
|
||
|
if (iStart == -1 && !section.m_bAlwaysVisible)
|
||
|
{
|
||
|
section.m_pHeader->SetVisible(false);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Skip down a bit if this is not the first section to be drawn
|
||
|
if ( bFirstVisibleSection )
|
||
|
bFirstVisibleSection = false;
|
||
|
else
|
||
|
y += m_iSectionGap;
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
// [tj] Only draw the header if it is enabled
|
||
|
//=============================================================================
|
||
|
int nMinNextSectionY = y + section.m_iMinimumHeight;
|
||
|
if (m_bDrawSectionHeaders)
|
||
|
{
|
||
|
// draw the header
|
||
|
section.m_pHeader->SetBounds(x, y, wide, tall);
|
||
|
section.m_pHeader->SetVisible(true);
|
||
|
y += tall;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
section.m_pHeader->SetVisible(false);
|
||
|
}
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================
|
||
|
|
||
|
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 + m_iLineGap;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add space, if needed to fulfill minimum requested content height
|
||
|
if ( y < nMinNextSectionY )
|
||
|
y = nMinNextSectionY;
|
||
|
}
|
||
|
|
||
|
// 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"));
|
||
|
|
||
|
FOR_EACH_LL( m_Items, j )
|
||
|
{
|
||
|
m_Items[j]->SetShowColumns( m_bShowColumns );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::SetHeaderFont( HFont hFont )
|
||
|
{
|
||
|
m_hHeaderFont = hFont;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HFont SectionedListPanel::GetHeaderFont( void ) const
|
||
|
{
|
||
|
return m_hHeaderFont;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::SetRowFont( HFont hFont )
|
||
|
{
|
||
|
m_hRowFont = hFont;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HFont SectionedListPanel::GetRowFont( void ) const
|
||
|
{
|
||
|
return m_hRowFont;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::ApplySettings(KeyValues *inResourceData)
|
||
|
{
|
||
|
BaseClass::ApplySettings(inResourceData);
|
||
|
m_iLineSpacing = inResourceData->GetInt("linespacing", 0);
|
||
|
if (!m_iLineSpacing)
|
||
|
{
|
||
|
m_iLineSpacing = DEFAULT_LINE_SPACING;
|
||
|
}
|
||
|
if (IsProportional())
|
||
|
{
|
||
|
m_iLineSpacing = scheme()->GetProportionalScaledValueEx(GetScheme(), m_iLineSpacing);
|
||
|
}
|
||
|
|
||
|
m_iSectionGap = inResourceData->GetInt("sectiongap", 0);
|
||
|
if (!m_iSectionGap)
|
||
|
{
|
||
|
m_iSectionGap = DEFAULT_SECTION_GAP;
|
||
|
}
|
||
|
m_iLineGap = inResourceData->GetInt( "linegap", 0 );
|
||
|
if (IsProportional())
|
||
|
{
|
||
|
m_iSectionGap = scheme()->GetProportionalScaledValueEx(GetScheme(), m_iSectionGap);
|
||
|
m_iLineGap = scheme()->GetProportionalScaledValueEx( GetScheme(), m_iLineGap );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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)
|
||
|
{
|
||
|
SectionedListPanelHeader *header = new SectionedListPanelHeader(this, name, sectionID);
|
||
|
AddSection(sectionID, header, sortFunc);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: adds a new section
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::AddSection(int sectionID, const wchar_t *name, SectionSortFunc_t sortFunc)
|
||
|
{
|
||
|
SectionedListPanelHeader *header = new SectionedListPanelHeader(this, name, sectionID);
|
||
|
AddSection(sectionID, header, sortFunc);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Adds a new section, given object
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::AddSection(int sectionID, SectionedListPanelHeader *header, SectionSortFunc_t sortFunc)
|
||
|
{
|
||
|
header = SETUP_PANEL( header );
|
||
|
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;
|
||
|
m_Sections[index].m_iMinimumHeight = 0;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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 §ion = 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 §ion = 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();
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
// [menglish] Setter for the background color similar to the foreground color
|
||
|
//=============================================================================
|
||
|
|
||
|
void SectionedListPanel::SetItemBgColor( int itemID, Color color )
|
||
|
{
|
||
|
Assert( m_Items.IsValidIndex(itemID) );
|
||
|
if ( !m_Items.IsValidIndex(itemID) )
|
||
|
return;
|
||
|
|
||
|
m_Items[itemID]->SetBgColor( color );
|
||
|
m_Items[itemID]->SetPaintBackgroundEnabled( true );
|
||
|
m_Items[itemID]->SetOverrideColors( true );
|
||
|
m_Items[itemID]->InvalidateLayout();
|
||
|
}
|
||
|
|
||
|
void SectionedListPanel::SetItemBgHorizFillInset( int itemID, int nInset )
|
||
|
{
|
||
|
Assert( m_Items.IsValidIndex( itemID ) );
|
||
|
if ( !m_Items.IsValidIndex( itemID ) )
|
||
|
return;
|
||
|
|
||
|
m_Items[itemID]->SetItemBgHorizFillInset( nInset );
|
||
|
}
|
||
|
|
||
|
void SectionedListPanel::SetItemFont( int itemID, HFont font )
|
||
|
{
|
||
|
Assert( m_Items.IsValidIndex(itemID) );
|
||
|
if ( !m_Items.IsValidIndex(itemID) )
|
||
|
return;
|
||
|
|
||
|
m_Items[itemID]->SetFont( font );
|
||
|
}
|
||
|
|
||
|
void SectionedListPanel::SetItemEnabled( int itemID, bool bEnabled )
|
||
|
{
|
||
|
Assert( m_Items.IsValidIndex(itemID) );
|
||
|
if ( !m_Items.IsValidIndex(itemID) )
|
||
|
return;
|
||
|
|
||
|
m_Items[itemID]->SetEnabled( bEnabled );
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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: added so you can change the divider color AFTER the main color.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::SetSectionDividerColor( int sectionID, Color color)
|
||
|
{
|
||
|
if (!m_Sections.IsValidIndex(sectionID))
|
||
|
return;
|
||
|
|
||
|
m_Sections[sectionID].m_pHeader->SetDividerColor(color);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::SetSectionDrawDividerBar( int sectionID, bool bDraw )
|
||
|
{
|
||
|
if ( !m_Sections.IsValidIndex( sectionID ) )
|
||
|
return;
|
||
|
|
||
|
m_Sections[sectionID].m_pHeader->DrawDividerBar( bDraw );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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;
|
||
|
}
|
||
|
void SectionedListPanel::SetFontSection(int sectionID, HFont font)
|
||
|
{
|
||
|
if (!m_Sections.IsValidIndex(sectionID))
|
||
|
return;
|
||
|
|
||
|
m_Sections[sectionID].m_pHeader->SetFont(font);
|
||
|
}
|
||
|
void SectionedListPanel::SetSectionMinimumHeight(int sectionID, int iMinimumHeight)
|
||
|
{
|
||
|
if (!m_Sections.IsValidIndex(sectionID))
|
||
|
return;
|
||
|
|
||
|
m_Sections[sectionID].m_iMinimumHeight = iMinimumHeight;
|
||
|
InvalidateLayout();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::SetColumnWidthBySection(int sectionID, const char *columnName, int iWidth)
|
||
|
{
|
||
|
int index = FindSectionIndexByID(sectionID);
|
||
|
if (index < 0)
|
||
|
return;
|
||
|
section_t §ion = 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;
|
||
|
|
||
|
column_t &column = section.m_Columns[columnIndex];
|
||
|
column.m_iWidth = iWidth;
|
||
|
|
||
|
// make sure the header for this section reloads with the new width
|
||
|
section.m_pHeader->InvalidateLayout();
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
// [menglish] Gets the column index by the string identifier
|
||
|
//=============================================================================
|
||
|
|
||
|
int SectionedListPanel::GetColumnIndexByName(int sectionID, char* name)
|
||
|
{
|
||
|
int index = FindSectionIndexByID(sectionID);
|
||
|
if (index < 0)
|
||
|
return 0;
|
||
|
|
||
|
for ( int columnIndex = 0; columnIndex < m_Sections[index].m_Columns.Count(); ++ columnIndex)
|
||
|
{
|
||
|
if( !V_strcmp( m_Sections[index].m_Columns[columnIndex].m_szColumnName, name ) )
|
||
|
return columnIndex;
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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)
|
||
|
{
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
// [tj] Only do this if clicking is enabled.
|
||
|
//=============================================================================
|
||
|
if (m_clickable){
|
||
|
ClearSelection();
|
||
|
}
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================}
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: deselects any items
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::ClearSelection( void )
|
||
|
{
|
||
|
SetSelectedItem((CItemButton *)NULL);
|
||
|
}
|
||
|
|
||
|
void SectionedListPanel::MoveSelectionDown( void )
|
||
|
{
|
||
|
int itemID = GetSelectedItem();
|
||
|
if (itemID == -1)
|
||
|
return;
|
||
|
|
||
|
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();
|
||
|
if (itemID == -1)
|
||
|
return;
|
||
|
|
||
|
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 || i >= m_SortedItems.Count() )
|
||
|
return;
|
||
|
|
||
|
int newItemID = m_SortedItems[i - 1]->GetID();
|
||
|
SetSelectedItem(m_Items[newItemID]);
|
||
|
ScrollToItem(newItemID);
|
||
|
}
|
||
|
|
||
|
void SectionedListPanel::NavigateTo( void )
|
||
|
{
|
||
|
BaseClass::NavigateTo();
|
||
|
|
||
|
if ( m_SortedItems.Count() )
|
||
|
{
|
||
|
int nItemID = m_SortedItems[ 0 ]->GetID();
|
||
|
SetSelectedItem( m_Items[ nItemID ] );
|
||
|
ScrollToItem( nItemID );
|
||
|
}
|
||
|
|
||
|
RequestFocus();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: arrow key movement handler
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::OnKeyCodePressed( 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("KeyCodePressed", "code", code));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int buttonTall = GetSectionTall();
|
||
|
|
||
|
ButtonCode_t nButtonCode = GetBaseButtonCode( code );
|
||
|
|
||
|
if ( nButtonCode == KEY_XBUTTON_DOWN ||
|
||
|
nButtonCode == KEY_XSTICK1_DOWN ||
|
||
|
nButtonCode == KEY_XSTICK2_DOWN ||
|
||
|
nButtonCode == STEAMCONTROLLER_DPAD_DOWN ||
|
||
|
code == KEY_DOWN )
|
||
|
{
|
||
|
int itemID = GetSelectedItem();
|
||
|
MoveSelectionDown();
|
||
|
if ( itemID != GetSelectedItem() )
|
||
|
{
|
||
|
// Only eat the input if it did something
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else if ( nButtonCode == KEY_XBUTTON_UP ||
|
||
|
nButtonCode == KEY_XSTICK1_UP ||
|
||
|
nButtonCode == KEY_XSTICK2_UP ||
|
||
|
nButtonCode == STEAMCONTROLLER_DPAD_UP ||
|
||
|
code == KEY_UP)
|
||
|
{
|
||
|
int itemID = GetSelectedItem();
|
||
|
MoveSelectionUp();
|
||
|
if ( itemID != GetSelectedItem() )
|
||
|
{
|
||
|
// Only eat the input if it did something
|
||
|
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);
|
||
|
return;
|
||
|
}
|
||
|
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);
|
||
|
return;
|
||
|
}
|
||
|
else if ( code == KEY_ENTER || nButtonCode == KEY_XBUTTON_A || nButtonCode == STEAMCONTROLLER_A )
|
||
|
{
|
||
|
Panel *pSelectedItem = m_hSelectedItem;
|
||
|
if ( pSelectedItem )
|
||
|
{
|
||
|
pSelectedItem->OnMousePressed( MOUSE_LEFT );
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
BaseClass::OnKeyCodePressed( 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: gets the local coordinates of a section header
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool SectionedListPanel::GetSectionHeaderBounds(int sectionID, int &x, int &y, int &wide, int &tall)
|
||
|
{
|
||
|
x = y = wide = tall = 0;
|
||
|
int index = FindSectionIndexByID(sectionID);
|
||
|
if (index < 0 || !m_Sections[index].m_pHeader )
|
||
|
return false;
|
||
|
|
||
|
m_Sections[index].m_pHeader->GetBounds( x, y, wide, tall );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_BEGIN:
|
||
|
// [menglish] Gets the local coordinates of a cell using the max width for every column
|
||
|
// Gets the local coordinates of a cell
|
||
|
//=============================================================================
|
||
|
|
||
|
bool SectionedListPanel::GetMaxCellBounds(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->GetMaxCellBounds(column, x, wide);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: gets the local coordinates of a cell
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool SectionedListPanel::GetItemBounds(int itemID, 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);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//=============================================================================
|
||
|
// HPE_END
|
||
|
//=============================================================================
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// 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));
|
||
|
m_Items[itemID]->SetShowColumns( m_bShowColumns );
|
||
|
}
|
||
|
|
||
|
// Gross. Le's hope this isn't the only property that doesn't get defaulted
|
||
|
// properly when an item is recycled.....
|
||
|
m_Items[itemID]->SetEnabled( true );
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
Color *SectionedListPanel::GetColorOverrideForCell( int sectionID, int itemID, int columnID )
|
||
|
{
|
||
|
FOR_EACH_VEC( m_ColorOverrides, i )
|
||
|
{
|
||
|
if ( ( m_ColorOverrides[i].m_SectionID == sectionID ) &&
|
||
|
( m_ColorOverrides[i].m_ItemID == itemID ) &&
|
||
|
( m_ColorOverrides[i].m_ColumnID == columnID ) )
|
||
|
{
|
||
|
return &(m_ColorOverrides[i].m_clrOverride);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SectionedListPanel::SetColorOverrideForCell( int sectionID, int itemID, int columnID, Color clrOverride )
|
||
|
{
|
||
|
// is this value already in the override list?
|
||
|
FOR_EACH_VEC( m_ColorOverrides, i )
|
||
|
{
|
||
|
if ( ( m_ColorOverrides[i].m_SectionID == sectionID ) &&
|
||
|
( m_ColorOverrides[i].m_ItemID == itemID ) &&
|
||
|
( m_ColorOverrides[i].m_ColumnID == columnID ) )
|
||
|
{
|
||
|
m_ColorOverrides[i].m_clrOverride = clrOverride;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int iIndex = m_ColorOverrides.AddToTail();
|
||
|
m_ColorOverrides[iIndex].m_SectionID = sectionID;
|
||
|
m_ColorOverrides[iIndex].m_ItemID = itemID;
|
||
|
m_ColorOverrides[iIndex].m_ColumnID = columnID;
|
||
|
m_ColorOverrides[iIndex].m_clrOverride = clrOverride;
|
||
|
}
|