You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1082 lines
26 KiB
1082 lines
26 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include <assert.h> |
|
#include <ctype.h> |
|
|
|
#include <vgui/MouseCode.h> |
|
#include <vgui/KeyCode.h> |
|
#include <KeyValues.h> |
|
#include <vgui/ISurface.h> |
|
#include <vgui/IVGui.h> |
|
#include <vgui/IInput.h> |
|
#include <vgui/IPanel.h> |
|
#include <vgui/ILocalize.h> |
|
|
|
#include <vgui_controls/Controls.h> |
|
#include <vgui_controls/ScrollBar.h> |
|
#include <vgui_controls/ImageList.h> |
|
#include <vgui_controls/ImagePanel.h> |
|
#include <vgui_controls/Label.h> |
|
#include <vgui_controls/TextImage.h> |
|
#include <vgui_controls/ListViewPanel.h> |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
using namespace vgui; |
|
|
|
enum |
|
{ |
|
WINDOW_BORDER_WIDTH=2 // the width of the window's border |
|
}; |
|
|
|
namespace vgui |
|
{ |
|
class ListViewItem : public Label |
|
{ |
|
DECLARE_CLASS_SIMPLE( ListViewItem, Label ); |
|
|
|
public: |
|
ListViewItem(Panel *parent) : Label(parent, NULL, "") |
|
{ |
|
m_pListViewPanel = (ListViewPanel*) parent; |
|
m_pData = NULL; |
|
m_bSelected = false; |
|
SetPaintBackgroundEnabled(true); |
|
} |
|
|
|
~ListViewItem() |
|
{ |
|
if (m_pData) |
|
{ |
|
m_pData->deleteThis(); |
|
m_pData = NULL; |
|
} |
|
} |
|
|
|
void SetData(const KeyValues *data) |
|
{ |
|
if (m_pData) |
|
{ |
|
m_pData->deleteThis(); |
|
} |
|
m_pData = data->MakeCopy(); |
|
} |
|
|
|
virtual void OnMousePressed( MouseCode code) |
|
{ |
|
m_pListViewPanel->OnItemMousePressed(this, code); |
|
} |
|
|
|
virtual void OnMouseDoublePressed( MouseCode code) |
|
{ |
|
// double press should only select the item |
|
m_pListViewPanel->OnItemMouseDoublePressed(this, code); |
|
} |
|
|
|
KeyValues *GetData() |
|
{ |
|
return m_pData; |
|
} |
|
|
|
void SetSelected(bool bSelected) |
|
{ |
|
if (bSelected == m_bSelected) |
|
return; |
|
|
|
m_bSelected = bSelected; |
|
if (bSelected) |
|
{ |
|
RequestFocus(); |
|
} |
|
|
|
UpdateImage(); |
|
InvalidateLayout(); |
|
Repaint(); |
|
} |
|
|
|
virtual void PerformLayout() |
|
{ |
|
TextImage *textImage = GetTextImage(); |
|
if (m_bSelected) |
|
{ |
|
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()))) |
|
{ |
|
textImage->SetColor(m_ArmedFgColor2); |
|
} |
|
else |
|
{ |
|
textImage->SetColor(m_FgColor2); |
|
} |
|
} |
|
else |
|
{ |
|
textImage->SetColor(GetFgColor()); |
|
} |
|
BaseClass::PerformLayout(); |
|
Repaint(); |
|
} |
|
|
|
virtual void PaintBackground() |
|
{ |
|
int wide, tall; |
|
GetSize(wide, tall); |
|
|
|
if ( m_bSelected ) |
|
{ |
|
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 ApplySchemeSettings(IScheme *pScheme) |
|
{ |
|
BaseClass::ApplySchemeSettings(pScheme); |
|
|
|
m_ArmedFgColor2 = GetSchemeColor("ListPanel.SelectedTextColor", pScheme); |
|
m_ArmedBgColor = GetSchemeColor("ListPanel.SelectedBgColor", pScheme); |
|
|
|
m_FgColor1 = GetSchemeColor("ListPanel.TextColor", pScheme); |
|
m_FgColor2 = GetSchemeColor("ListPanel.SelectedTextColor", pScheme); |
|
|
|
m_BgColor = GetSchemeColor("ListPanel.BgColor", GetBgColor(), pScheme); |
|
m_BgColor = GetSchemeColor("ListPanel.TextBgColor", m_BgColor, pScheme); |
|
m_SelectionBG2Color = GetSchemeColor("ListPanel.SelectedOutOfFocusBgColor", pScheme); |
|
SetBgColor(m_BgColor); |
|
SetFgColor(m_FgColor1); |
|
|
|
UpdateImage(); |
|
} |
|
|
|
void UpdateImage() |
|
{ |
|
if ( m_pListViewPanel->m_pImageList ) |
|
{ |
|
int imageIndex = 0; |
|
if ( m_bSelected ) |
|
{ |
|
imageIndex = m_pData->GetInt("imageSelected", 0); |
|
} |
|
if ( imageIndex == 0 ) |
|
{ |
|
imageIndex = m_pData->GetInt("image", 0); |
|
} |
|
if ( m_pListViewPanel->m_pImageList->IsValidIndex(imageIndex) ) |
|
{ |
|
SetImageAtIndex(0, m_pListViewPanel->m_pImageList->GetImage(imageIndex), 0); |
|
} |
|
else |
|
{ |
|
// use the default |
|
SetImageAtIndex(0, m_pListViewPanel->m_pImageList->GetImage(1), 0); |
|
} |
|
SizeToContents(); |
|
InvalidateLayout(); |
|
} |
|
} |
|
|
|
private: |
|
|
|
Color m_FgColor1; |
|
Color m_FgColor2; |
|
Color m_BgColor; |
|
Color m_ArmedFgColor2; |
|
Color m_ArmedBgColor; |
|
Color m_SelectionBG2Color; |
|
|
|
//IBorder *_keyFocusBorder; // maybe in the future when I'm the 'active' but not selected item, I'll have a border |
|
|
|
KeyValues *m_pData; |
|
ListViewPanel *m_pListViewPanel; |
|
bool m_bSelected; |
|
}; |
|
} |
|
|
|
static bool DefaultSortFunc(KeyValues *kv1, KeyValues *kv2) |
|
{ |
|
const char *string1 = kv1->GetString("text"); |
|
const char *string2 = kv2->GetString("text"); |
|
return Q_stricmp(string1, string2) < 0; |
|
} |
|
|
|
DECLARE_BUILD_FACTORY( ListViewPanel ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
ListViewPanel::ListViewPanel(Panel *parent, const char *panelName) : Panel(parent, panelName) |
|
{ |
|
m_iRowHeight = 20; |
|
m_bNeedsSort = false; |
|
m_hFont = NULL; |
|
m_pImageList = NULL; |
|
m_bDeleteImageListWhenDone = false; |
|
m_pSortFunc = DefaultSortFunc; |
|
m_ShiftStartItemID = -1; |
|
|
|
m_hbar = new ScrollBar(this, "HorizScrollBar", false); |
|
m_hbar->AddActionSignalTarget(this); |
|
m_hbar->SetVisible(false); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
ListViewPanel::~ListViewPanel() |
|
{ |
|
DeleteAllItems(); |
|
|
|
delete m_hbar; |
|
|
|
if ( m_bDeleteImageListWhenDone ) |
|
{ |
|
delete m_pImageList; |
|
m_pImageList = NULL; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::AddItem(const KeyValues *data, bool bScrollToItem, bool bSortOnAdd) |
|
{ |
|
ListViewItem *pNewItem = new ListViewItem(this); |
|
pNewItem->SetData(data); |
|
if (m_hFont) |
|
{ |
|
pNewItem->SetFont(m_hFont); |
|
} |
|
int itemID = m_DataItems.AddToTail(pNewItem); |
|
ApplyItemChanges(itemID); |
|
m_SortedItems.AddToTail(itemID); |
|
|
|
if ( bSortOnAdd ) |
|
{ |
|
m_bNeedsSort = true; |
|
} |
|
|
|
InvalidateLayout(); |
|
|
|
if ( bScrollToItem ) |
|
{ |
|
ScrollToItem(itemID); |
|
} |
|
|
|
return itemID; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::ScrollToItem(int itemID) |
|
{ |
|
if (!m_hbar->IsVisible()) |
|
{ |
|
return; |
|
} |
|
int val = m_hbar->GetValue(); |
|
|
|
int wide, tall; |
|
GetSize( wide, tall ); |
|
|
|
int maxWidth = GetItemsMaxWidth(); |
|
int maxColVisible = wide / maxWidth; |
|
int itemsPerCol = GetItemsPerColumn(); |
|
|
|
int itemIndex = m_SortedItems.Find(itemID); |
|
int desiredCol = itemIndex / itemsPerCol; |
|
if (desiredCol < val || desiredCol >= (val + maxColVisible) ) |
|
{ |
|
m_hbar->SetValue(desiredCol); |
|
} |
|
|
|
InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::GetItemCount() |
|
{ |
|
return m_DataItems.Count(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
KeyValues *ListViewPanel::GetItem(int itemID) |
|
{ |
|
if ( !m_DataItems.IsValidIndex(itemID) ) |
|
return NULL; |
|
|
|
return m_DataItems[itemID]->GetData(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get ItemID from position in panel - valid from [0, GetItemCount) |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::GetItemIDFromPos(int iPos) |
|
{ |
|
if ( m_SortedItems.IsValidIndex(iPos) ) |
|
{ |
|
return m_SortedItems[iPos]; |
|
} |
|
else |
|
{ |
|
return m_DataItems.InvalidIndex(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::ApplyItemChanges(int itemID) |
|
{ |
|
if ( !m_DataItems.IsValidIndex(itemID) ) |
|
return; |
|
|
|
KeyValues *kv = m_DataItems[itemID]->GetData(); |
|
ListViewItem *pLabel = m_DataItems[itemID]; |
|
|
|
pLabel->SetText(kv->GetString("text")); |
|
pLabel->SetTextImageIndex(1); |
|
pLabel->SetImagePreOffset(1, 5); |
|
|
|
TextImage *pTextImage = pLabel->GetTextImage(); |
|
pTextImage->ResizeImageToContent(); |
|
|
|
pLabel->UpdateImage(); |
|
pLabel->SizeToContents(); |
|
pLabel->InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::RemoveItem(int itemID) |
|
{ |
|
if ( !m_DataItems.IsValidIndex(itemID) ) |
|
return; |
|
|
|
m_DataItems[itemID]->MarkForDeletion(); |
|
|
|
// mark the keyValues for deletion |
|
m_DataItems.Remove(itemID); |
|
m_SortedItems.FindAndRemove(itemID); |
|
m_SelectedItems.FindAndRemove(itemID); |
|
|
|
InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::DeleteAllItems() |
|
{ |
|
FOR_EACH_LL( m_DataItems, index ) |
|
{ |
|
m_DataItems[index]->MarkForDeletion(); |
|
} |
|
m_DataItems.RemoveAll(); |
|
m_SortedItems.RemoveAll(); |
|
m_SelectedItems.RemoveAll(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::InvalidItemID() |
|
{ |
|
return m_DataItems.InvalidIndex(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool ListViewPanel::IsValidItemID(int itemID) |
|
{ |
|
return m_DataItems.IsValidIndex(itemID); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::SetSortFunc(ListViewSortFunc_t func) |
|
{ |
|
if ( func ) |
|
{ |
|
m_pSortFunc = func; |
|
SortList(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::SortList() |
|
{ |
|
m_SortedItems.RemoveAll(); |
|
|
|
// find all the items in this section |
|
for( int i = m_DataItems.Head(); i != m_DataItems.InvalidIndex(); i = m_DataItems.Next( i ) ) |
|
{ |
|
// insert the items sorted |
|
if (m_pSortFunc) |
|
{ |
|
int insertionPoint; |
|
for (insertionPoint = 0; insertionPoint < m_SortedItems.Count(); insertionPoint++) |
|
{ |
|
if ( m_pSortFunc(m_DataItems[i]->GetData(), m_DataItems[m_SortedItems[insertionPoint]]->GetData() ) ) |
|
break; |
|
} |
|
|
|
if (insertionPoint == m_SortedItems.Count()) |
|
{ |
|
m_SortedItems.AddToTail(i); |
|
} |
|
else |
|
{ |
|
m_SortedItems.InsertBefore(insertionPoint, i); |
|
} |
|
} |
|
else |
|
{ |
|
// just add to the end |
|
m_SortedItems.AddToTail(i); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::SetImageList(ImageList *imageList, bool deleteImageListWhenDone) |
|
{ |
|
// get rid of existing list image if there's one and we're supposed to get rid of it |
|
if ( m_pImageList && m_bDeleteImageListWhenDone ) |
|
{ |
|
delete m_pImageList; |
|
m_pImageList = NULL; |
|
} |
|
|
|
m_bDeleteImageListWhenDone = deleteImageListWhenDone; |
|
m_pImageList = imageList; |
|
|
|
FOR_EACH_LL( m_DataItems, i ) |
|
{ |
|
m_DataItems[i]->UpdateImage(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::SetFont(HFont font) |
|
{ |
|
Assert( font ); |
|
if ( !font ) |
|
return; |
|
|
|
m_hFont = font; |
|
m_iRowHeight = surface()->GetFontTall(font) + 1; |
|
|
|
FOR_EACH_LL( m_DataItems, i ) |
|
{ |
|
m_DataItems[i]->SetFont(m_hFont); |
|
TextImage *pTextImage = m_DataItems[i]->GetTextImage(); |
|
pTextImage->ResizeImageToContent(); |
|
m_DataItems[i]->SizeToContents(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::GetSelectedItemsCount() |
|
{ |
|
return m_SelectedItems.Count(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::GetSelectedItem(int selectionIndex) |
|
{ |
|
if ( m_SelectedItems.IsValidIndex(selectionIndex) ) |
|
return m_SelectedItems[selectionIndex]; |
|
|
|
return -1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::ClearSelectedItems() |
|
{ |
|
int i; |
|
for (i = 0 ; i < m_SelectedItems.Count(); i++) |
|
{ |
|
if ( m_DataItems.IsValidIndex(m_SelectedItems[i]) ) |
|
{ |
|
m_DataItems[m_SelectedItems[i]]->SetSelected(false); |
|
} |
|
} |
|
m_SelectedItems.RemoveAll(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::AddSelectedItem(int itemID) |
|
{ |
|
if ( m_SelectedItems.Find(itemID) == -1 ) |
|
{ |
|
m_SelectedItems.AddToTail(itemID); |
|
m_DataItems[itemID]->SetSelected(true); |
|
m_LastSelectedItemID = itemID; |
|
m_ShiftStartItemID = itemID; |
|
PostActionSignal(new KeyValues("ListViewItemSelected")); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::SetSingleSelectedItem(int itemID) |
|
{ |
|
ClearSelectedItems(); |
|
AddSelectedItem(itemID); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnMouseWheeled(int delta) |
|
{ |
|
int val = m_hbar->GetValue(); |
|
val -= delta; |
|
m_hbar->SetValue(val); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnSizeChanged(int wide, int tall) |
|
{ |
|
BaseClass::OnSizeChanged(wide, tall); |
|
InvalidateLayout(); |
|
Repaint(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::GetItemsMaxWidth() |
|
{ |
|
int maxWidth = 0; |
|
FOR_EACH_LL( m_DataItems, i ) |
|
{ |
|
int labelWide, labelTall; |
|
m_DataItems[i]->GetSize(labelWide, labelTall); |
|
if (labelWide > maxWidth) |
|
{ |
|
maxWidth = labelWide + 25; |
|
} |
|
} |
|
return maxWidth; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::PerformLayout() |
|
{ |
|
if (m_bNeedsSort) |
|
{ |
|
SortList(); |
|
} |
|
|
|
if ( m_DataItems.Count() == 0 ) |
|
return; |
|
|
|
int wide, tall; |
|
GetSize(wide, tall); |
|
|
|
int maxWidth = GetItemsMaxWidth(); |
|
if (maxWidth < 24) |
|
{ |
|
maxWidth = 24; |
|
} |
|
int maxColVisible = wide / maxWidth; |
|
|
|
m_hbar->SetVisible(false); |
|
int itemsPerCol = GetItemsPerColumn(); |
|
if (itemsPerCol < 1) |
|
{ |
|
itemsPerCol = 1; |
|
} |
|
int cols = ( GetItemCount() + (itemsPerCol - 1) ) / itemsPerCol; |
|
|
|
int startItem = 0; |
|
if ( cols > maxColVisible) |
|
{ |
|
m_hbar->SetVisible(true); |
|
|
|
// recalulate # per column now that we've made the hbar visible |
|
itemsPerCol = GetItemsPerColumn(); |
|
cols = ( GetItemCount() + (itemsPerCol - 1) ) / (itemsPerCol > 0 ? itemsPerCol : 1 ); |
|
|
|
m_hbar->SetEnabled(false); |
|
m_hbar->SetRangeWindow( maxColVisible ); |
|
m_hbar->SetRange( 0, cols); |
|
m_hbar->SetButtonPressedScrollValue( 1 ); |
|
|
|
m_hbar->SetPos(0, tall - (m_hbar->GetTall()+WINDOW_BORDER_WIDTH)); |
|
m_hbar->SetSize(wide - (WINDOW_BORDER_WIDTH*2), m_hbar->GetTall()); |
|
m_hbar->InvalidateLayout(); |
|
|
|
int val = m_hbar->GetValue(); |
|
startItem += val*itemsPerCol; |
|
} |
|
else |
|
{ |
|
m_hbar->SetVisible(false); |
|
} |
|
int lastItemVisible = startItem + (( maxColVisible + 1 )* itemsPerCol) - 1; |
|
|
|
int itemsThisCol = 0; |
|
int x = 0; |
|
int y = 0; |
|
int i; |
|
for ( i = 0 ; i < m_SortedItems.Count() ; i++ ) |
|
{ |
|
if ( i >= startItem && i <= lastItemVisible ) |
|
{ |
|
m_DataItems[ m_SortedItems[i] ]->SetVisible(true); |
|
m_DataItems[ m_SortedItems[i] ]->SetPos(x, y); |
|
itemsThisCol++; |
|
if ( itemsThisCol == itemsPerCol ) |
|
{ |
|
y = 0; |
|
x += maxWidth; |
|
itemsThisCol = 0; |
|
} |
|
else |
|
{ |
|
y += m_iRowHeight; |
|
} |
|
} |
|
else |
|
{ |
|
m_DataItems[ m_SortedItems[i] ]->SetVisible(false); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::Paint() |
|
{ |
|
BaseClass::Paint(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::ApplySchemeSettings(IScheme *pScheme) |
|
{ |
|
BaseClass::ApplySchemeSettings(pScheme); |
|
|
|
SetBgColor(GetSchemeColor("ListPanel.BgColor", pScheme)); |
|
SetBorder(pScheme->GetBorder("ButtonDepressedBorder")); |
|
|
|
m_LabelFgColor = GetSchemeColor("ListPanel.TextColor", pScheme); |
|
m_SelectionFgColor = GetSchemeColor("ListPanel.SelectedTextColor", m_LabelFgColor, pScheme); |
|
|
|
m_hFont = pScheme->GetFont("Default", IsProportional()); |
|
SetFont(m_hFont); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnMousePressed( MouseCode code) |
|
{ |
|
if (code == MOUSE_LEFT || code == MOUSE_RIGHT) |
|
{ |
|
ClearSelectedItems(); |
|
RequestFocus(); |
|
} |
|
// check for context menu open |
|
if (code == MOUSE_RIGHT) |
|
{ |
|
// post it, but with the invalid row |
|
PostActionSignal(new KeyValues("OpenContextMenu", "itemID", -1)); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnShiftSelect(int itemID) |
|
{ |
|
// if we dont' have a valid selected ItemID - then we just choose the first item |
|
if ( !m_DataItems.IsValidIndex(m_ShiftStartItemID) ) |
|
{ |
|
m_ShiftStartItemID = m_DataItems.Head(); |
|
} |
|
|
|
// find out if the just pressed item is "earlier" or is the 'last selected item' |
|
int lowerPos = -1, upperPos = -1; |
|
int i; |
|
for ( i = 0 ; i < m_SortedItems.Count() ; i++ ) |
|
{ |
|
if ( m_SortedItems[i] == itemID ) |
|
{ |
|
lowerPos = i; |
|
upperPos = m_SortedItems.Find(m_ShiftStartItemID); |
|
break; |
|
} |
|
else if ( m_SortedItems[i] == m_ShiftStartItemID ) |
|
{ |
|
lowerPos = m_SortedItems.Find(m_ShiftStartItemID); |
|
upperPos = i; |
|
break; |
|
} |
|
} |
|
assert(lowerPos <= upperPos); |
|
if ( !input()->IsKeyDown(KEY_LCONTROL) && !input()->IsKeyDown(KEY_RCONTROL) ) |
|
{ |
|
ClearSelectedItems(); |
|
} |
|
|
|
for ( i = lowerPos ; i <= upperPos ; i ++) |
|
{ |
|
// do not use AddSelectedItem because we don't want to switch the shiftStartItemID |
|
m_DataItems[ m_SortedItems[i] ]->SetSelected(true); |
|
m_SelectedItems.AddToTail(m_SortedItems[i]); |
|
m_LastSelectedItemID = itemID; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnItemMousePressed(ListViewItem* pItem, MouseCode code) |
|
{ |
|
int itemID = m_DataItems.Find(pItem); |
|
if (!m_DataItems.IsValidIndex(itemID)) |
|
return; |
|
|
|
// check for context menu open |
|
if (code == MOUSE_RIGHT) |
|
{ |
|
// if this is a new item - unselect everything else |
|
if ( m_SelectedItems.Find(itemID) == -1) |
|
{ |
|
ClearSelectedItems(); |
|
AddSelectedItem(itemID); |
|
} |
|
|
|
PostActionSignal(new KeyValues("OpenContextMenu", "itemID", itemID)); |
|
} |
|
else |
|
{ |
|
if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) ) |
|
{ |
|
OnShiftSelect(itemID); |
|
} |
|
else if ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) ) |
|
{ |
|
if ( m_SelectedItems.Find(itemID) != -1) |
|
{ |
|
m_SelectedItems.FindAndRemove(itemID); |
|
pItem->SetSelected(false); |
|
|
|
// manually select these since we 'last' clicked on these items |
|
m_ShiftStartItemID = itemID; |
|
m_LastSelectedItemID = itemID; |
|
m_DataItems[itemID]->RequestFocus(); |
|
} |
|
else |
|
{ |
|
AddSelectedItem(itemID); |
|
} |
|
} |
|
else |
|
{ |
|
ClearSelectedItems(); |
|
AddSelectedItem(itemID); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnMouseDoublePressed( MouseCode code) |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnItemMouseDoublePressed(ListViewItem* pItem, MouseCode code) |
|
{ |
|
if (code == MOUSE_LEFT) |
|
{ |
|
OnKeyCodeTyped(KEY_ENTER); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::FinishKeyPress(int itemID) |
|
{ |
|
if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) ) |
|
{ |
|
OnShiftSelect(itemID); |
|
} |
|
else if ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) ) |
|
{ |
|
m_DataItems[itemID]->RequestFocus(); |
|
m_LastSelectedItemID = itemID; |
|
} |
|
else |
|
{ |
|
SetSingleSelectedItem(itemID); |
|
} |
|
ScrollToItem(itemID); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnKeyCodeTyped( KeyCode code ) |
|
{ |
|
if ( m_DataItems.Count() == 0 ) |
|
return; |
|
|
|
switch (code) |
|
{ |
|
case KEY_HOME: |
|
{ |
|
if (m_SortedItems.Count() > 0) |
|
{ |
|
int itemID = m_SortedItems[0]; |
|
FinishKeyPress(itemID); |
|
} |
|
break; |
|
} |
|
case KEY_END: |
|
{ |
|
if (m_DataItems.Count() > 0) |
|
{ |
|
int itemID = m_SortedItems[ m_SortedItems.Count() - 1 ]; |
|
FinishKeyPress(itemID); |
|
} |
|
break; |
|
} |
|
|
|
case KEY_UP: |
|
{ |
|
int itemPos = m_SortedItems.Find( m_LastSelectedItemID ); |
|
itemPos--; |
|
if (itemPos < 0) |
|
itemPos = 0; |
|
|
|
FinishKeyPress(m_SortedItems[itemPos]); |
|
break; |
|
} |
|
|
|
case KEY_DOWN: |
|
{ |
|
int itemPos = m_SortedItems.Find( m_LastSelectedItemID ); |
|
itemPos++; |
|
if (itemPos >= m_DataItems.Count()) |
|
itemPos = m_DataItems.Count() - 1; |
|
|
|
FinishKeyPress(m_SortedItems[itemPos]); |
|
break; |
|
} |
|
|
|
case KEY_LEFT: |
|
{ |
|
int itemPos = m_SortedItems.Find( m_LastSelectedItemID ); |
|
itemPos -= GetItemsPerColumn(); |
|
if (itemPos < 0) |
|
{ |
|
itemPos = 0; |
|
} |
|
FinishKeyPress(m_SortedItems[itemPos]); |
|
break; |
|
} |
|
|
|
case KEY_RIGHT: |
|
{ |
|
int itemPos = m_SortedItems.Find( m_LastSelectedItemID ); |
|
itemPos += GetItemsPerColumn(); |
|
if (itemPos >= m_SortedItems.Count()) |
|
{ |
|
itemPos = m_SortedItems.Count() - 1; |
|
} |
|
FinishKeyPress(m_SortedItems[itemPos]); |
|
break; |
|
} |
|
|
|
case KEY_PAGEUP: |
|
{ |
|
int wide, tall; |
|
GetSize(wide, tall); |
|
|
|
int maxWidth = GetItemsMaxWidth(); |
|
if (maxWidth == 0) |
|
{ |
|
maxWidth = wide; |
|
} |
|
int maxColVisible = wide / maxWidth; |
|
int delta = maxColVisible * GetItemsPerColumn(); |
|
|
|
int itemPos = m_SortedItems.Find( m_LastSelectedItemID ); |
|
itemPos -= delta; |
|
if (itemPos < 0) |
|
{ |
|
itemPos = 0; |
|
} |
|
|
|
FinishKeyPress(m_SortedItems[itemPos]); |
|
break; |
|
} |
|
case KEY_PAGEDOWN: |
|
{ |
|
int wide, tall; |
|
GetSize(wide, tall); |
|
|
|
int maxWidth = GetItemsMaxWidth(); |
|
if (maxWidth == 0) |
|
{ |
|
maxWidth = wide; |
|
} |
|
int maxColVisible = wide / maxWidth; |
|
int delta = maxColVisible * GetItemsPerColumn(); |
|
|
|
int itemPos = m_SortedItems.Find( m_LastSelectedItemID ); |
|
itemPos += delta; |
|
if (itemPos >= m_SortedItems.Count()) |
|
{ |
|
itemPos = m_SortedItems.Count() - 1; |
|
} |
|
|
|
FinishKeyPress(m_SortedItems[itemPos]); |
|
break; |
|
} |
|
default: |
|
{ |
|
BaseClass::OnKeyCodeTyped(code); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnKeyTyped(wchar_t unichar) |
|
{ |
|
if (!iswcntrl(unichar)) |
|
{ |
|
wchar_t uniString[2]; |
|
uniString[0] = unichar; |
|
uniString[1] = 0; |
|
|
|
char buf[2]; |
|
g_pVGuiLocalize->ConvertUnicodeToANSI(uniString, buf, sizeof(buf)); |
|
|
|
int i; |
|
int itemPos = m_SortedItems.Find(m_LastSelectedItemID); |
|
if ( m_SortedItems.IsValidIndex(itemPos)) |
|
{ |
|
itemPos++; |
|
// start from the item AFTER our last selected Item and go to end |
|
for ( i = itemPos ; i != m_SortedItems.Count(); i++) |
|
{ |
|
KeyValues *kv = m_DataItems[ m_SortedItems[i] ]->GetData(); |
|
const char *pszText = kv->GetString("text"); |
|
if (!strnicmp(pszText, buf, 1)) |
|
{ |
|
// select the next of this letter |
|
SetSingleSelectedItem(m_SortedItems[i]); |
|
ScrollToItem(m_SortedItems[i]); |
|
return; |
|
} |
|
} |
|
// if the after this item we couldn't fine an item with the same letter, fall through and just start from the beginning of list to the last selected item |
|
} |
|
|
|
for ( i = 0 ; i < m_SortedItems.Count() ; i++ ) |
|
{ |
|
// we've gone all the way around - break - if we had a valid index, this is one more that last selectedItem, if not it's an illegal index |
|
if ( i == itemPos) |
|
break; |
|
|
|
KeyValues *kv = m_DataItems[ m_SortedItems[i] ]->GetData(); |
|
const char *pszText = kv->GetString("text"); |
|
if (!strnicmp(pszText, buf, 1)) |
|
{ |
|
SetSingleSelectedItem(m_SortedItems[i]); |
|
ScrollToItem(m_SortedItems[i]); |
|
return; |
|
} |
|
} |
|
} |
|
else |
|
BaseClass::OnKeyTyped(unichar); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ListViewPanel::OnSliderMoved() |
|
{ |
|
InvalidateLayout(); |
|
Repaint(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int ListViewPanel::GetItemsPerColumn() |
|
{ |
|
int wide, tall; |
|
GetSize(wide, tall); |
|
|
|
if ( m_hbar->IsVisible() ) |
|
{ |
|
tall -= m_hbar->GetTall(); |
|
} |
|
|
|
return tall / m_iRowHeight; // should round down |
|
} |
|
|
|
|