diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/vgui2/vgui_controls/SectionedListPanel.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-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.cpp | 4338 |
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 §ion = m_Sections[sectionIndex];
- sectionStart = m_SortedItems.Count();
-
- // find all the items in this section
- for( int i = m_Items.Head(); i != m_Items.InvalidIndex(); i = m_Items.Next( i ) )
- {
- if (m_Items[i]->GetSectionID() == m_Sections[sectionIndex].m_iID)
- {
- // insert the items sorted
- if (section.m_pSortFunc)
- {
- int insertionPoint = sectionStart;
- for (;insertionPoint < m_SortedItems.Count(); insertionPoint++)
- {
- if (section.m_pSortFunc(this, i, m_SortedItems[insertionPoint]->GetID()))
- break;
- }
-
- if (insertionPoint == m_SortedItems.Count())
- {
- m_SortedItems.AddToTail(m_Items[i]);
- }
- else
- {
- m_SortedItems.InsertBefore(insertionPoint, m_Items[i]);
- }
- }
- else
- {
- // just add to the end
- m_SortedItems.AddToTail(m_Items[i]);
- }
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: iterates through and sets up the position of all the sections and items
-//-----------------------------------------------------------------------------
-void SectionedListPanel::PerformLayout()
-{
- // lazy resort the list
- if (m_bSortNeeded)
- {
- ReSortList();
- m_bSortNeeded = false;
- }
-
- BaseClass::PerformLayout();
-
- LayoutPanels(m_iContentHeight);
-
- int cx, cy, cwide, ctall;
- GetBounds(cx, cy, cwide, ctall);
- if (m_iContentHeight > ctall && m_bVerticalScrollbarEnabled)
- {
- m_pScrollBar->SetVisible(true);
- m_pScrollBar->MoveToFront();
-
- m_pScrollBar->SetPos(cwide - m_pScrollBar->GetWide() - 2, 0);
- m_pScrollBar->SetSize(m_pScrollBar->GetWide(), ctall - 2);
-
- m_pScrollBar->SetRangeWindow(ctall);
-
- m_pScrollBar->SetRange(0, m_iContentHeight);
- m_pScrollBar->InvalidateLayout();
- m_pScrollBar->Repaint();
-
- // since we're just about to make the scrollbar visible, we need to re-layout
- // the buttons since they depend on the scrollbar size
- LayoutPanels(m_iContentHeight);
- }
- else
- {
- m_pScrollBar->SetValue(0);
-
- bool bWasVisible = m_pScrollBar->IsVisible();
- m_pScrollBar->SetVisible(false);
-
- // When we hide the scrollbar, we need to layout the buttons because they'll have more width to work with
- if ( bWasVisible )
- {
- LayoutPanels(m_iContentHeight);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: lays out the sections and rows in the panel
-//-----------------------------------------------------------------------------
-void SectionedListPanel::LayoutPanels(int &contentTall)
-{
- int tall = GetSectionTall();
- int x = 5, wide = GetWide() - 10;
- int y = 5;
-
- if (m_pScrollBar->IsVisible())
- {
- y -= m_pScrollBar->GetValue();
- wide -= m_pScrollBar->GetWide();
- }
-
- int iStart = -1;
- int iEnd = -1;
-
- // layout the buttons
- bool bFirstVisibleSection = true;
- for (int sectionIndex = 0; sectionIndex < m_Sections.Size(); sectionIndex++)
- {
- section_t §ion = m_Sections[sectionIndex];
-
- iStart = -1;
- iEnd = -1;
- for (int i = 0; i < m_SortedItems.Count(); i++)
- {
- if (m_SortedItems[i]->GetSectionID() == m_Sections[sectionIndex].m_iID)
- {
- if (iStart == -1)
- iStart = i;
- iEnd = i;
- }
- }
-
- // don't draw this section at all if 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 §ion = m_Sections[index];
-
- // add the new column to the sections' list
- index = section.m_Columns.AddToTail();
- column_t &column = section.m_Columns[index];
-
- Q_strncpy(column.m_szColumnName, columnName, sizeof(column.m_szColumnName));
- wcsncpy(column.m_szColumnText, columnText, sizeof(column.m_szColumnText) / sizeof(wchar_t));
- column.m_szColumnText[sizeof(column.m_szColumnText) / sizeof(wchar_t) - 1] = 0;
- column.m_iColumnFlags = columnFlags;
- column.m_iWidth = width;
- column.m_hFallbackFont = fallbackFont;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: modifies the text in an existing column
-//-----------------------------------------------------------------------------
-bool SectionedListPanel::ModifyColumn(int sectionID, const char *columnName, const wchar_t *columnText)
-{
- int index = FindSectionIndexByID(sectionID);
- if (index < 0)
- return false;
- section_t §ion = m_Sections[index];
-
- // find the specified column
- int columnIndex;
- for (columnIndex = 0; columnIndex < section.m_Columns.Count(); columnIndex++)
- {
- if (!stricmp(section.m_Columns[columnIndex].m_szColumnName, columnName))
- break;
- }
- if (!section.m_Columns.IsValidIndex(columnIndex))
- return false;
- column_t &column = section.m_Columns[columnIndex];
-
- // modify the text
- wcsncpy(column.m_szColumnText, columnText, sizeof(column.m_szColumnText) / sizeof(wchar_t));
- column.m_szColumnText[sizeof(column.m_szColumnText) / sizeof(wchar_t) - 1] = 0;
- section.m_pHeader->InvalidateLayout();
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: adds an item to the list; returns itemID
-//-----------------------------------------------------------------------------
-int SectionedListPanel::AddItem(int sectionID, const KeyValues *data)
-{
- int itemID = GetNewItemButton();
- ModifyItem(itemID, sectionID, data);
-
- // not sorted but in list
- m_SortedItems.AddToTail(m_Items[itemID]);
- m_bSortNeeded = true;
-
- return itemID;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: modifies an existing item; returns false if the item does not exist
-//-----------------------------------------------------------------------------
-bool SectionedListPanel::ModifyItem(int itemID, int sectionID, const KeyValues *data)
-{
- if ( !m_Items.IsValidIndex(itemID) )
- return false;
-
- InvalidateLayout();
- m_Items[itemID]->SetSectionID(sectionID);
- m_Items[itemID]->SetData(data);
- m_Items[itemID]->InvalidateLayout();
- m_bSortNeeded = true;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void SectionedListPanel::SetItemFgColor( int itemID, Color color )
-{
- Assert( m_Items.IsValidIndex(itemID) );
- if ( !m_Items.IsValidIndex(itemID) )
- return;
-
- m_Items[itemID]->SetFgColor( color );
- m_Items[itemID]->SetOverrideColors( true );
- m_Items[itemID]->InvalidateLayout();
-}
-
-//=============================================================================
-// HPE_BEGIN:
-// [menglish] Setter for the background color similar to the foreground color
-//=============================================================================
-
-void SectionedListPanel::SetItemBgColor( int itemID, Color color )
-{
- Assert( m_Items.IsValidIndex(itemID) );
- if ( !m_Items.IsValidIndex(itemID) )
- return;
-
- m_Items[itemID]->SetBgColor( color );
- m_Items[itemID]->SetPaintBackgroundEnabled( true );
- m_Items[itemID]->SetOverrideColors( true );
- m_Items[itemID]->InvalidateLayout();
-}
-
-void SectionedListPanel::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 §ion = m_Sections[sectionIndex]; + sectionStart = m_SortedItems.Count(); + + // find all the items in this section + for( int i = m_Items.Head(); i != m_Items.InvalidIndex(); i = m_Items.Next( i ) ) + { + if (m_Items[i]->GetSectionID() == m_Sections[sectionIndex].m_iID) + { + // insert the items sorted + if (section.m_pSortFunc) + { + int insertionPoint = sectionStart; + for (;insertionPoint < m_SortedItems.Count(); insertionPoint++) + { + if (section.m_pSortFunc(this, i, m_SortedItems[insertionPoint]->GetID())) + break; + } + + if (insertionPoint == m_SortedItems.Count()) + { + m_SortedItems.AddToTail(m_Items[i]); + } + else + { + m_SortedItems.InsertBefore(insertionPoint, m_Items[i]); + } + } + else + { + // just add to the end + m_SortedItems.AddToTail(m_Items[i]); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: iterates through and sets up the position of all the sections and items +//----------------------------------------------------------------------------- +void SectionedListPanel::PerformLayout() +{ + // lazy resort the list + if (m_bSortNeeded) + { + ReSortList(); + m_bSortNeeded = false; + } + + BaseClass::PerformLayout(); + + LayoutPanels(m_iContentHeight); + + int cx, cy, cwide, ctall; + GetBounds(cx, cy, cwide, ctall); + if (m_iContentHeight > ctall && m_bVerticalScrollbarEnabled) + { + m_pScrollBar->SetVisible(true); + m_pScrollBar->MoveToFront(); + + m_pScrollBar->SetPos(cwide - m_pScrollBar->GetWide() - 2, 0); + m_pScrollBar->SetSize(m_pScrollBar->GetWide(), ctall - 2); + + m_pScrollBar->SetRangeWindow(ctall); + + m_pScrollBar->SetRange(0, m_iContentHeight); + m_pScrollBar->InvalidateLayout(); + m_pScrollBar->Repaint(); + + // since we're just about to make the scrollbar visible, we need to re-layout + // the buttons since they depend on the scrollbar size + LayoutPanels(m_iContentHeight); + } + else + { + m_pScrollBar->SetValue(0); + + bool bWasVisible = m_pScrollBar->IsVisible(); + m_pScrollBar->SetVisible(false); + + // When we hide the scrollbar, we need to layout the buttons because they'll have more width to work with + if ( bWasVisible ) + { + LayoutPanels(m_iContentHeight); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: lays out the sections and rows in the panel +//----------------------------------------------------------------------------- +void SectionedListPanel::LayoutPanels(int &contentTall) +{ + int tall = GetSectionTall(); + int x = 5, wide = GetWide() - 10; + int y = 5; + + if (m_pScrollBar->IsVisible()) + { + y -= m_pScrollBar->GetValue(); + wide -= m_pScrollBar->GetWide(); + } + + int iStart = -1; + int iEnd = -1; + + // layout the buttons + bool bFirstVisibleSection = true; + for (int sectionIndex = 0; sectionIndex < m_Sections.Size(); sectionIndex++) + { + section_t §ion = m_Sections[sectionIndex]; + + iStart = -1; + iEnd = -1; + for (int i = 0; i < m_SortedItems.Count(); i++) + { + if (m_SortedItems[i]->GetSectionID() == m_Sections[sectionIndex].m_iID) + { + if (iStart == -1) + iStart = i; + iEnd = i; + } + } + + // don't draw this section at all if 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 §ion = m_Sections[index]; + + // add the new column to the sections' list + index = section.m_Columns.AddToTail(); + column_t &column = section.m_Columns[index]; + + Q_strncpy(column.m_szColumnName, columnName, sizeof(column.m_szColumnName)); + wcsncpy(column.m_szColumnText, columnText, sizeof(column.m_szColumnText) / sizeof(wchar_t)); + column.m_szColumnText[sizeof(column.m_szColumnText) / sizeof(wchar_t) - 1] = 0; + column.m_iColumnFlags = columnFlags; + column.m_iWidth = width; + column.m_hFallbackFont = fallbackFont; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: modifies the text in an existing column +//----------------------------------------------------------------------------- +bool SectionedListPanel::ModifyColumn(int sectionID, const char *columnName, const wchar_t *columnText) +{ + int index = FindSectionIndexByID(sectionID); + if (index < 0) + return false; + section_t §ion = m_Sections[index]; + + // find the specified column + int columnIndex; + for (columnIndex = 0; columnIndex < section.m_Columns.Count(); columnIndex++) + { + if (!stricmp(section.m_Columns[columnIndex].m_szColumnName, columnName)) + break; + } + if (!section.m_Columns.IsValidIndex(columnIndex)) + return false; + column_t &column = section.m_Columns[columnIndex]; + + // modify the text + wcsncpy(column.m_szColumnText, columnText, sizeof(column.m_szColumnText) / sizeof(wchar_t)); + column.m_szColumnText[sizeof(column.m_szColumnText) / sizeof(wchar_t) - 1] = 0; + section.m_pHeader->InvalidateLayout(); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: adds an item to the list; returns itemID +//----------------------------------------------------------------------------- +int SectionedListPanel::AddItem(int sectionID, const KeyValues *data) +{ + int itemID = GetNewItemButton(); + ModifyItem(itemID, sectionID, data); + + // not sorted but in list + m_SortedItems.AddToTail(m_Items[itemID]); + m_bSortNeeded = true; + + return itemID; +} + +//----------------------------------------------------------------------------- +// Purpose: modifies an existing item; returns false if the item does not exist +//----------------------------------------------------------------------------- +bool SectionedListPanel::ModifyItem(int itemID, int sectionID, const KeyValues *data) +{ + if ( !m_Items.IsValidIndex(itemID) ) + return false; + + InvalidateLayout(); + m_Items[itemID]->SetSectionID(sectionID); + m_Items[itemID]->SetData(data); + m_Items[itemID]->InvalidateLayout(); + m_bSortNeeded = true; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void SectionedListPanel::SetItemFgColor( int itemID, Color color ) +{ + Assert( m_Items.IsValidIndex(itemID) ); + if ( !m_Items.IsValidIndex(itemID) ) + return; + + m_Items[itemID]->SetFgColor( color ); + m_Items[itemID]->SetOverrideColors( true ); + m_Items[itemID]->InvalidateLayout(); +} + +//============================================================================= +// HPE_BEGIN: +// [menglish] Setter for the background color similar to the foreground color +//============================================================================= + +void SectionedListPanel::SetItemBgColor( int itemID, Color color ) +{ + Assert( m_Items.IsValidIndex(itemID) ); + if ( !m_Items.IsValidIndex(itemID) ) + return; + + m_Items[itemID]->SetBgColor( color ); + m_Items[itemID]->SetPaintBackgroundEnabled( true ); + m_Items[itemID]->SetOverrideColors( true ); + m_Items[itemID]->InvalidateLayout(); +} + +void SectionedListPanel::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; +} |