📄 listbox.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "ListBox.h"
#include "DisplayItem.hpp"
#include <commctrl.h>
#include <sipapi.h>
#include "Input.hpp"
#include <winuserm.h>
#include "PaintHelper.hpp"
#include "Layout.hpp"
#include "Common.hpp"
#include "Debug.hpp"
const UINT c_cmsToolTipLag = 1500;
/*------------------------------------------------------------------------------
Helper function to get the new top index
------------------------------------------------------------------------------*/
int GetNewTopIndex(
HWND hwndLB,
int LastVisibleItem,
int HeightLimit
)
{
if ((LastVisibleItem < 0) || (HeightLimit < 0))
{
ASSERT(FALSE);
return -1;
}
int NewTopItem = LastVisibleItem;
int TotalHeight = SendMessage(hwndLB, LB_GETITEMHEIGHT, (WPARAM)NewTopItem, 0);
while (NewTopItem > 0)
{
NewTopItem--;
TotalHeight += SendMessage(hwndLB, LB_GETITEMHEIGHT, (WPARAM)NewTopItem, 0);
if (TotalHeight > HeightLimit)
{
NewTopItem ++;
break;
}
}
NewTopItem = max(NewTopItem, 0);
return NewTopItem;
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::ListBoxImpl_t
Constructor
------------------------------------------------------------------------------*/
ListBoxImpl_t::ListBoxImpl_t()
{
TRACE(ZONE_COMMON_CTOR);
m_PositionControlNotification = true;
m_RedrawingEnabled = false;
m_ListBoxHeightChanged = false;
m_CheckToolTip = false;
m_dwToolTipTimer = 0;
m_OriginalHeight = 0;
#ifdef VIRTUAL_LISTBOX
m_SelectedItem = LB_ERR;
#endif
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::~ListBoxImpl_t
Destructor
------------------------------------------------------------------------------*/
ListBoxImpl_t::~ListBoxImpl_t()
{
TRACE(ZONE_COMMON_CTOR);
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::ControlWindowProc
Handle messages
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::ControlWindowProc(
UINT Message,
WPARAM wParam,
LPARAM lParam,
bool& Handled
)
{
LRESULT Result;
//by default assume we handled the message
Handled = true;
switch (Message)
{
#ifdef VIRTUAL_LISTBOX
case LB_GETITEMDATA:
return OnGetItemData(wParam);
case LB_SETITEMDATA:
return OnSetItemData(wParam, reinterpret_cast<IVoIPDisplayItem*>(lParam));
case LB_GETITEMRECT:
return OnGetItemRect(wParam, reinterpret_cast<RECT*>(lParam));
case LB_GETITEMHEIGHT:
return OnGetItemHeight(wParam);
case LB_GETCOUNT:
return OnGetCount();
case LB_GETCURSEL:
return OnGetCurSel();
case LB_GETTOPINDEX:
return OnGetTopIndex();
case LB_SETTOPINDEX:
return OnSetTopIndex(wParam);
case LB_FINDSTRING:
return OnFindItem(reinterpret_cast<IVoIPDisplayItem*>(lParam));
case LB_ITEMFROMPOINT:
return OnItemFromPoint(LOWORD(lParam), HIWORD(lParam));
case LB_RESETCONTENT:
return OnResetContent();
#endif
case WM_DELETEITEM:
return DeleteItem(
reinterpret_cast<DELETEITEMSTRUCT*>(lParam)
);
case WM_DRAWITEM:
return DrawItem(
reinterpret_cast<DRAWITEMSTRUCT*>(lParam)
);
case WM_MEASUREITEM:
return MeasureItem(
reinterpret_cast<MEASUREITEMSTRUCT*>(lParam)
);
#ifdef AUTOMATION
case LB_GETTEXT:
return OnGetText(
wParam,
reinterpret_cast<WCHAR*>(lParam)
);
case LB_GETTEXTLEN:
return OnGetTextLen(wParam);
#endif
case LB_ADDSTRING:
return OnAddItem(-1, reinterpret_cast<IVoIPDisplayItem*>(lParam));
case LB_INSERTSTRING:
return OnAddItem(wParam, reinterpret_cast<IVoIPDisplayItem*>(lParam));
case LB_DELETESTRING:
return OnDeleteItem(wParam);
case LB_SETCURSEL:
return OnSetCurSel(wParam);
case WM_CLOSE:
Handled = ForwardMessageToParent(Message, wParam, lParam, &Result);
return Result;
case WM_CREATE:
return OnCreate(reinterpret_cast<const CREATESTRUCT*>(lParam));
case WM_DESTROY:
Handled = false;
return OnDestroy();
case WM_CTLCOLOREDIT:
case WM_CTLCOLORSTATIC:
return OnSetControlBackground(
Message,
reinterpret_cast<HDC>(wParam),
reinterpret_cast<HWND>(lParam)
);
case WM_ERASEBKGND:
// Pretend that the background was erased
return 1;
case WM_KEYDOWN:
return OnKeydown(wParam, lParam);
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_RBUTTONDOWN:
return OnMouseButton(wParam, lParam);
case WM_NOTIFY:
return OnNotify(wParam, reinterpret_cast<NMHDR*>(lParam));
case WM_PAINT:
Handled = false;
return OnPaint(reinterpret_cast<HDC>(wParam));
case WM_SETFOCUS:
return OnSetFocus(reinterpret_cast<HWND>(wParam));
case WM_SETREDRAW:
return OnSetRedraw(wParam);
case WM_SETTINGCHANGE:
return OnSettingChange(wParam);
case WM_TIMER:
return OnTimer();
case WM_HSCROLL:
case WM_VSCROLL:
//trackbar's notify in the WM_HSCROLL or WM_VSCROLL messages
switch(LOWORD(wParam))
{
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_THUMBPOSITION:
Handled = ForwardMessageToParent(Message, wParam, lParam, &Result);
return Result;
}
Handled = false;
return 0;
default:
Handled = false;
return 0;
}
}
bool
ListBoxImpl_t::IsValidIndex(
int Index
)
{
#ifdef VIRTUAL_LISTBOX
return ((Index >= 0) && (Index < m_Items.size()));
#else
return ((Index >= 0) && (Index < OnGetCount()));
#endif
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnCreate
Handles WM_CREATE.
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnCreate(
const CREATESTRUCT* pCreateStruct
)
{
LRESULT Result;
RECT ClientRect;
if (!pCreateStruct)
{
ASSERT(0);
return -1;
}
//Styles not supported by virtual listbox
if (pCreateStruct->style & (
LBS_SORT |
LBS_NOREDRAW |
LBS_MULTIPLESEL |
LBS_USETABSTOPS |
LBS_NOINTEGRALHEIGHT |
LBS_MULTICOLUMN |
LBS_NODATA |
LBS_EXTENDEDSEL |
LBS_NOSEL
))
{
ASSERT(0);
}
// Set default input mode to numbers
Input_SetInputMode(m_hwnd, EIM_NUMBERS);
Result = 0;
// Create the tool tip window
if (FAILED(
m_ToolTip.Create(
ToolTip_t::GetWindowClassName(),
L"Tool Tip",
WS_CHILD,
0,
m_hwnd,
0,
0,
0,
0
)
))
{
ASSERT(FALSE);
Result = -1;
}
//remember the original height of the listbox, so when we stretch/shrink the box
//we have the proper restore size
GetClientRect(m_hwnd, &ClientRect);
m_OriginalHeight = ClientRect.bottom;
return Result;
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnDestroy
Handles WM_DESTROY by deleting all exisiting IVoIPDisplayItems in the
listbox
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnDestroy(
void
)
{
OnResetContent();
return 0;
}
LRESULT
ListBoxImpl_t::OnResetContent(
void
)
{
return DefWindowProc(LB_RESETCONTENT, 0, 0);
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnItemFromPoint
Retrieve the zero-based index of the item nearest the specified point.
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnItemFromPoint(
unsigned short xCoordinate,
unsigned short yCoordinate
)
{
#ifdef VIRTUAL_LISTBOX
bool IsOutsideClientArea = false;
int Index;
RECT ClientRect;
GetClientRect(m_hwnd, &ClientRect);
if (yCoordinate < 0)
{
IsOutsideClientArea = true;
yCoordinate = 0;
}
else if (yCoordinate > ClientRect.bottom)
{
IsOutsideClientArea = true;
yCoordinate = ClientRect.bottom;
}
if (xCoordinate < 0)
{
IsOutsideClientArea = true;
xCoordinate = 0;
}
else if (xCoordinate > ClientRect.right)
{
IsOutsideClientArea = 1;
xCoordinate = ClientRect.right;
}
if (m_OwnerDraw != OWNERDRAWVAR)
{
Index = m_TopItem + (yCoordinate / m_FixedItemHeight);
}
else
{
POINT Position;
// Hit test anywhere inside the listbox
Position.x = xCoordinate;
Position.y = yCoordinate;
for (Index = m_TopItem; Index < m_VariableHeight.size(); Index++)
{
RECT ItemRect;
OnGetItemRect(Index, &ItemRect);
if (PtInRect(&ItemRect, Position))
{
break;
}
}
}
// The point might be on the blank area at the bottom of a not full list.
if (Index >= m_Items.size())
{
IsOutsideClientArea = true;
Index = max(m_Items.size() - 1, 0);
}
return MAKELONG(Index, IsOutsideClientArea ? 1 : 0);
#else
return DefWindowProc(LB_ITEMFROMPOINT, 0, MAKELONG(xCoordinate, yCoordinate));
#endif
}
LRESULT
ListBoxImpl_t::OnGetItemData(
int Index
)
{
#ifdef VIRTUAL_LISTBOX
if (!IsValidIndex(Index))
{
return LB_ERR;
}
return reinterpret_cast<LRESULT>(m_Items[Index]);
#else
LRESULT Result = DefWindowProc(LB_GETITEMDATA, (WPARAM)Index, 0);
return (Result == LB_ERR) ? NULL : Result;
#endif
}
LRESULT
ListBoxImpl_t::OnSetItemData(
int Index,
IVoIPDisplayItem* pItem
)
{
#ifdef VIRTUAL_LISTBOX
if (!IsValidIndex(Index))
{
return LB_ERR;
}
m_Items[Index] = pItem;
return 0;
#else
return DefWindowProc(LB_SETITEMDATA, (WPARAM)Index, (LPARAM)pItem);
#endif
}
#ifdef VIRTUAL_LISTBOX
LRESULT
ListBoxImpl_t::OnGetItemHeight(
int Index
)
{
if (m_OwnerDraw != OWNERDRAWVAR)
{
return m_FixedItemHeight;
}
if (!IsValidIndex(Index))
{
return LB_ERR;
}
return m_VariableHeight[Index];
}
#endif
LRESULT
ListBoxImpl_t::OnGetItemRect(
int Index,
RECT* pRectangle
)
{
#ifdef VIRTUAL_LISTBOX
if (!pRectangle)
{
SetLastError(ERROR_INVALID_PARAMETER);
return LB_ERR;
}
if (Index && !IsValidIndex(Index))
{
SetRectEmpty(pRectangle);
return LB_ERR;
}
GetClientRect(m_hwnd, pRectangle);
if (m_OwnerDraw == OWNERDRAWVAR)
{
int i;
if (Index >= m_TopItem)
{
for (i = m_TopItem; i < Index; i++)
{
pRectangle->top += OnGetItemHeight(i);
}
// If item number is 0, it may be we are asking for the rect
// associated with a nonexistant item so that we can draw a caret
// indicating focus on an empty listbox.
pRectangle->bottom = pRectangle->top +
(i < m_Items.size() ? OnGetItemHeight(i) : m_FixedItemHeight);
}
else
{
// Item we want the rect of is before TopItem. Thus, negative
// offsets for the rect and it is never visible.
for (i = Index; i < m_TopItem; i++)
{
pRectangle->top -= OnGetItemHeight(i);
}
pRectangle->bottom = pRectangle->top + OnGetItemHeight(i);
}
}
else
{
// For fixed height listboxes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -