📄 listbox.cpp
字号:
pRectangle->top = (Index - m_TopItem) * m_FixedItemHeight;
pRectangle->bottom = pRectangle->top + m_FixedItemHeight;
}
return 0;
#else
return DefWindowProc(LB_GETITEMRECT, Index, (LPARAM)pRectangle);
#endif
}
LRESULT
ListBoxImpl_t::OnGetCount(
void
)
{
#ifdef VIRTUAL_LISTBOX
return m_Items.size();
#else
return DefWindowProc(LB_GETCOUNT, 0, 0);
#endif
}
LRESULT
ListBoxImpl_t::OnGetCurSel(
void
)
{
#ifdef VIRTUAL_LISTBOX
return m_SelectedItem;
#else
return DefWindowProc(LB_GETCURSEL, 0, 0);
#endif
}
LRESULT
ListBoxImpl_t::OnGetTopIndex(
void
)
{
#ifdef VIRTUAL_LISTBOX
return m_TopItem;
#else
return DefWindowProc(LB_GETTOPINDEX, 0, 0);
#endif
}
LRESULT
ListBoxImpl_t::OnSetTopIndex(
int Index
)
{
#ifdef VIRTUAL_LISTBOX
if (IsValidIndex(Index))
{
return LB_ERR;
}
// Move this item to top of listbox
m_TopItem = Index;
return 0;
#else
return DefWindowProc(LB_SETTOPINDEX, Index, 0);
#endif
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnMouseButton
Handles a mouse button being clicked in the listbox's client area
WM_LBUTTONDOWN,
WM_LBUTTONDBLCLK
WM_RBUTTONDOWN
WM_RBUTTONDBLCLK
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnMouseButton(
WPARAM wParam,
LPARAM lParam
)
{
LRESULT Result = OnItemFromPoint(LOWORD(lParam), HIWORD(lParam));
bool IsInsideClientArea = (HIWORD(Result) == 0);
int Index = LOWORD(Result);
IVoIPDisplayItem * pItem = NULL;
if (!IsInsideClientArea || !IsValidIndex(Index))
{
return 0;
}
RECT ItemRect = {0};
OnGetItemRect(Index, &ItemRect);
//The width of an item spans the entire client width
//if the click is inside the item, select it
//otherwise bail out
if (ItemRect.bottom < HIWORD(lParam))
{
return 0;
}
pItem = (IVoIPDisplayItem *)OnGetItemData(Index);
if (!pItem)
{
return 0;
}
if (pItem->IsSelectable())
{
IVoIPDisplayControl* pControl;
if (FAILED(
pItem->QueryInterface(
IID_IVoIPDisplayControl,
reinterpret_cast<void**>(&pControl)
)
) ||
!pControl->SetFocus()
)
{
SetFocus(m_hwnd);
}
// Only choose the item when it is selectable
OnSetCurSel(Index);
SimulateItemActivated();
}
return 0;
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::SimulateItemActivated
Simulates an item being activated (e.g. clicked on - not just focused)
------------------------------------------------------------------------------*/
inline
void
ListBoxImpl_t::SimulateItemActivated(
void
)
{
//Inform the parent of a fake double click
ForwardMessageToParent(
WM_COMMAND,
MAKEWPARAM(GetWindowLong(m_hwnd, GWL_ID), LBN_DBLCLK),
(LPARAM)m_hwnd
);
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnKeydown
Handles WM_KEYDOWN messages.
Possibly, scrolls the listbox or activates an item
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnKeydown(
int VirtualKey,
UINT KeyData
)
{
int IndexToSelect = 0;
int SelectedItem = 0;
int BottomIndex = 0;
int ItemCount = OnGetCount();
//LOWORD of KeyData is the repeat count
bool IsRepeated = (LOWORD(KeyData) > 1);
if (ItemCount <= 0)
{
return 0;
}
switch (VirtualKey)
{
case VK_UP:
case VK_DOWN:
SelectedItem = OnGetCurSel();
//choose the next item by default
IndexToSelect = SelectedItem + ((VirtualKey == VK_UP) ? -1 : 1);
//if this is a new press (e.g. not repeated) we can wrap the selection around
if (!IsRepeated)
{
switch (VirtualKey)
{
case VK_UP:
if (SelectedItem == 0)
{
IndexToSelect = ItemCount-1;
}
break;
case VK_DOWN:
if (SelectedItem == ItemCount-1)
{
IndexToSelect = 0;
}
break;
}
}
IndexToSelect = GetNextSelectableIndex(IndexToSelect, (VirtualKey == VK_UP));
IndexToSelect = min(max(IndexToSelect, 0), ItemCount-1 );
if (IndexToSelect != SelectedItem)
{
OnSetCurSel(IndexToSelect);
}
break;
case VK_PRIOR:
//PAGE UP
OnSetRedraw(FALSE);
OnSetCurSel(OnGetTopIndex() - 1);
OnSetCurSel(OnGetTopIndex());
OnSetRedraw(TRUE);
break;
case VK_NEXT:
//PAGE DOWN
BottomIndex = GetBottomIndex();
IndexToSelect = min(BottomIndex + 1, ItemCount-1);
OnSetCurSel(IndexToSelect);
break;
default:
return DefWindowProc(WM_KEYDOWN, VirtualKey, KeyData);
}
return 0;
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnSetCurSel
Handles LB_SETCURSEL. We always want the LBN_SELCHANGE notification and
since this message doesn't cause the LBN_SELCHANGE notification to go to
the parent (see ListBox documentation), we simulate it.
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnSetCurSel(
int IndexToSelect
)
{
int TopItem = 0;
int NewTopItem = -1;
int SelectedItem = 0;
int ItemCount = OnGetCount();
RECT ItemRect = {0};
RECT ClientRect = {0};
bool NeedToSimulatePageUp = false;
bool NeedToSimulatePageDown = false;
LRESULT Result = 0;
WCHAR ToolTipText[MAX_PATH] = L"";
IVoIPDisplayItem *pItem = NULL;
//If the user wants to clear the selection, let the def wnd proc handle it
if (IndexToSelect == -1)
{
return DefWindowProc(LB_SETCURSEL, IndexToSelect, 0);
}
//hide the previous tooltip window
ShowWindow(m_ToolTip, SW_HIDE);
//Short circuit a same selection
SelectedItem = OnGetCurSel();
if (SelectedItem == IndexToSelect)
{
return 0;
}
if ((IndexToSelect > ItemCount) || (ItemCount == 0))
{
return 0;
}
//Check to see if the item we are going to select needs tooltip or not
//if so, assign the full text to the tooltip control
pItem = (IVoIPDisplayItem *)OnGetItemData(IndexToSelect);
OnGetItemRect(IndexToSelect, &ItemRect);
if (pItem)
{
m_CheckToolTip = pItem->NeedsToolTip(&ItemRect) ? true : false;
if (m_CheckToolTip)
{
pItem->GetText(
ToolTipText,
_countof(ToolTipText)
);
SetWindowText(
m_ToolTip,
ToolTipText
);
m_dwToolTipTimer = GetTickCount();
}
}
//Figure out if we need to scroll up or down
TopItem = OnGetTopIndex();
GetClientRect(m_hwnd, &ClientRect);
NeedToSimulatePageUp = (TopItem > IndexToSelect);
NeedToSimulatePageDown = (TopItem < IndexToSelect) && (ItemRect.bottom > ClientRect.bottom);
//figure out the new top index
if (NeedToSimulatePageUp)
{
//if we are paging up, we need to determine the new top index such
//that IndexToSelect is the bottom index!
NewTopItem = GetNewTopIndex(m_hwnd, IndexToSelect, ClientRect.bottom - ClientRect.top);
//Force to hide the Sip Panel when we page up
//Because if we don't hide the sip panel, the last item at previous page will
//not get redrawed since it will be all covered by the sip panel
Input_HideInputPanel();
}
else if (NeedToSimulatePageDown)
{
//Make the IndexToSelect the new top index
NewTopItem = IndexToSelect;
}
if (NewTopItem != -1)
{
//Reduce drawing flicker on page scroll
OnSetRedraw(FALSE);
OnSetTopIndex(NewTopItem);
Result = DefWindowProc(LB_SETCURSEL, IndexToSelect, 0);
OnSetRedraw(TRUE);
}
else
{
Result = DefWindowProc(LB_SETCURSEL, IndexToSelect, 0);
}
//Notify the parent
SendMessage(
GetParent(m_hwnd),
WM_COMMAND,
MAKEWPARAM(GetWindowLong(m_hwnd, GWL_ID), LBN_SELCHANGE),
(LPARAM)m_hwnd
);
return Result;
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnSetFocus
When we gain focus, we need to ensure that we have reset the redraw flag
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnSetFocus(
HWND OldFocus
)
{
LRESULT Result = DefWindowProc(WM_SETFOCUS, (WPARAM)OldFocus, 0);
int SelectedItem = OnGetCurSel();
IVoIPDisplayItem *pItem = reinterpret_cast<IVoIPDisplayItem*>(
OnGetItemData(SelectedItem)
);
if (pItem)
{
IVoIPDisplayControl* pControl;
if (SUCCEEDED(pItem->QueryInterface(
IID_IVoIPDisplayControl,
reinterpret_cast<void**>(&pControl)
)))
{
pControl->SetFocus();
}
}
if (!m_RedrawingEnabled)
{
OnSetRedraw(TRUE);
}
return Result;
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnSetRedraw
Optimizes a caller setting/unsetting redraw
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnSetRedraw(
BOOL Enable
)
{
#ifdef VIRTUAL_LISTBOX
LRESULT Result = 1;
if (!Enable)
{
//remember that drawing is now disabled
m_RedrawingEnabled = false;
}
else if (!m_RedrawingEnabled)
{
//SetCaret(TRUE);
// want the whole window to redraw including
// non-client area since scrollbars may have
// gone away or come back.
InvalidateRect(m_hwnd, NULL, TRUE);
SetWindowPos(
m_hwnd,
0,
0,
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOACTIVATE | SWP_FRAMECHANGED
);
m_RedrawingEnabled = true;
Result = 0;
}
return Result;
#else
bool NeedToCallDefWndProc = true;
LRESULT Result = 1;
if (! Enable)
{
//remember that drawing is now disabled
m_RedrawingEnabled = false;
}
else
{
//if redrawing is already enabled, we don't have to call the defwndproc
if (m_RedrawingEnabled)
{
NeedToCallDefWndProc = false;
}
else
{
m_RedrawingEnabled = true;
}
}
if (NeedToCallDefWndProc)
{
Result = DefWindowProc(WM_SETREDRAW, Enable, 0);
}
return Result;
#endif
}
/*------------------------------------------------------------------------------
ListBoxImpl_t::OnPaint
Handles WM_PAINT - paints the listview background and delegates the drawing
of the items to the actual items
Returns (LRESULT): indicating success or failure
------------------------------------------------------------------------------*/
LRESULT
ListBoxImpl_t::OnPaint(
HDC hdc
)
{
RECT UpdateRect = {0};
RECT ItemsArea = {0};
RECT NonItemsArea = {0};
RECT ClientRect = {0};
int ItemCount = OnGetCount();
HRESULT hr = S_OK;
PaintHelper_t paint;
//if paint is called between a SetRedraw(FALSE) and a SetRedraw(TRUE) block
//we shouldn't reposition our children controls because WM_DRAWITEM will NOT
//be generated
if (m_RedrawingEnabled)
{
RepositionSubcontrols();
}
else
{
COMMON_DEBUGMSG(0, (L"we are repainting, but not repositioning the subcontrols because we don't have parental-focus"));
}
NotifyParentOfOffscreenItems();
// Since we are not erasing the background we are responsible for drawing
// the entire control.
// Display items will draw themselves completely. We will get a notification
// from the parent before and after an item is going to be drawn
// The only part of the control that we need to concern ourselves with is
// the non-item portion, which will be filled in with the background color
// Get the entire client region of the window.
GetClientRect(m_hwnd, &ClientRect);
// Get the bottom y-coordinate of the last item in the control.
if (ItemCount > 0)
{
OnGetItemRect(ItemCount - 1, &ItemsArea);
}
// Can skip the rest of this if the control is completely covered by bands
if (ItemsArea.bottom >= ClientRect.bottom)
{
goto paint_items;
}
ItemsArea.top = ClientRect.top;
ItemsArea.left = ClientRect.left;
// Get the update rectangle.
GetUpdateRect(m_hwnd, &UpdateRect, FALSE);
//start the painting operation
if (FAILED(paint.Begin(m_hwnd)))
{
return 0;
}
if ((HDC)m_BackBuffer == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -