aboutsummaryrefslogtreecommitdiff
path: root/mp/src/vgui2/vgui_controls/SectionedListPanel.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/vgui2/vgui_controls/SectionedListPanel.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/vgui2/vgui_controls/SectionedListPanel.cpp')
-rw-r--r--mp/src/vgui2/vgui_controls/SectionedListPanel.cpp4338
1 files changed, 2169 insertions, 2169 deletions
diff --git a/mp/src/vgui2/vgui_controls/SectionedListPanel.cpp b/mp/src/vgui2/vgui_controls/SectionedListPanel.cpp
index 120de368..65e90239 100644
--- a/mp/src/vgui2/vgui_controls/SectionedListPanel.cpp
+++ b/mp/src/vgui2/vgui_controls/SectionedListPanel.cpp
@@ -1,2169 +1,2169 @@
-//========= 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;
-
-enum
-{
- BUTTON_HEIGHT_DEFAULT = 20,
- BUTTON_HEIGHT_SPACER = 7,
- DEFAULT_LINE_SPACING = 20,
- DEFAULT_SECTION_GAP = 8,
- COLUMN_DATA_INDENT = 6,
- COLUMN_DATA_GAP = 2,
-};
-
-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 );
-}
-
-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();
-}
-
-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();
-
- 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 - 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->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();
- }
-
- ~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);
-
-
- 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, 0, wide, tall);
- }
-
- 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, tall = 0;
- int wide;
- 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;
- }
-
-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;
-};
-
-}; // 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_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 &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);
-
- 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 &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;
- }
-
- // 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;
- }
- }
-
- // 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;
- }
- if (IsProportional())
- {
- m_iSectionGap = scheme()->GetProportionalScaledValueEx(GetScheme(), m_iSectionGap);
- }
-}
-
-//-----------------------------------------------------------------------------
-// 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 &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();
-}
-
-//=============================================================================
-// 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::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: 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;
-}
-
-//=============================================================================
-// 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 ||
- 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 ||
- 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 )
- {
- 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;
-}
+//========= 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;
+
+enum
+{
+ BUTTON_HEIGHT_DEFAULT = 20,
+ BUTTON_HEIGHT_SPACER = 7,
+ DEFAULT_LINE_SPACING = 20,
+ DEFAULT_SECTION_GAP = 8,
+ COLUMN_DATA_INDENT = 6,
+ COLUMN_DATA_GAP = 2,
+};
+
+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 );
+}
+
+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();
+}
+
+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();
+
+ 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 - 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->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();
+ }
+
+ ~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);
+
+
+ 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, 0, wide, tall);
+ }
+
+ 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, tall = 0;
+ int wide;
+ 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;
+ }
+
+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;
+};
+
+}; // 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_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 &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);
+
+ 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 &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;
+ }
+
+ // 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;
+ }
+ }
+
+ // 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;
+ }
+ if (IsProportional())
+ {
+ m_iSectionGap = scheme()->GetProportionalScaledValueEx(GetScheme(), m_iSectionGap);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// 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 &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();
+}
+
+//=============================================================================
+// 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::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: 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;
+}
+
+//=============================================================================
+// 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 ||
+ 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 ||
+ 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 )
+ {
+ 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;
+}