winamp/Src/Plugins/Library/ml_online/Setup/setupListbox.cpp
2024-09-24 14:54:57 +02:00

879 lines
22 KiB
C++

#include "./setupPage.h"
#include "./setupListbox.h"
#include "./setupGroupList.h"
#include "./setupImage.h"
#include "../common.h"
#include "../resource.h"
#include "../api__ml_online.h"
#include "../../nu/windowsTheme.h"
#include <vssym32.h>
//#include <tmschema.h>
static ATOM SERVICELIST_PROP = 0;
#define SLF_UNICODE 0x0001
#define SLF_DRAGMOVE 0x0002
typedef BOOL (SetupListboxItem::*ITEMMOUSEPROC)(SetupListbox*, const RECT*, UINT, POINT);
class Listbox : public SetupListbox
{
protected:
Listbox(HWND hListbox, SetupGroupList *groupList);
~Listbox();
public:
static HRESULT AttachToWindow(HWND hwndListbox, SetupGroupList *groupList, SetupListbox **pInstance);
public:
HWND GetHwnd() { return hwnd; }
HFONT GetFont() { return (HFONT)::SendMessage(hwnd, WM_GETFONT, 0, 0L); }
LRESULT CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL MeasureItem(INT itemId, UINT *cx, UINT *cy);
BOOL DrawItem(HDC hdc, const RECT *itemRect, INT itemId, UINT itemState, UINT itemAction);
INT_PTR KeyToItem(INT vKey, INT caretPos);
INT_PTR CharToItem(INT vKey, INT caretPos);
BOOL DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect);
BOOL GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize);
INT GetCheckboxThemeState(BOOL checked, UINT state);
INT HitTest(POINT pt, RECT *prcItem);
void SetCapture(SetupListboxItem *item);
SetupListboxItem *GetCapture();
void ReleaseCapture();
BOOL InvalidateRect(const RECT *prcInvalidate, BOOL fErase);
BOOL InvalidateItem(INT itemId, BOOL fErase);
void UpdateCount();
BOOL DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg);
BOOL GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize);
INT GetPageCount();
INT GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut);
INT GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut);
SetupListboxItem *GetSelection();
BOOL SetSelection(SetupListboxItem *item);
BOOL GetIndex(SetupListboxItem *item, INT *iItem);
BOOL DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt);
HMENU GetContextMenu(UINT menuId);
protected:
friend static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnDestroy();
void GetItemRect(INT itemId, RECT *prcItem);
SetupImage *GetExpandboxImage(HDC hdc, BOOL fExpanded);
void OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc);
void OnMouseLeave();
void OnEraseBkGround(HDC hdc);
void OnCaptureChanged(HWND hwndGained);
void NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain);
void OnCommand(INT commandId, INT eventId, HWND hControl);
protected:
HWND hwnd;
UINT flags;
WNDPROC originalProc;
UXTHEME buttonTheme;
SetupGroupList *groups;
INT mouseoverId;
INT capturedId;
SetupImage *expandedImage;
SetupImage *collapsedImage;
};
#define GetList(__hwnd) ((Listbox*)GetPropW((__hwnd), MAKEINTATOM(SERVICELIST_PROP)))
HRESULT SetupListbox::CreateInstance(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance)
{
return Listbox::AttachToWindow(hListbox, groupList, pInstance);
}
SetupListbox *SetupListbox::GetInstance(HWND hListbox)
{
return GetList(hListbox);
}
Listbox::Listbox(HWND hListbox, SetupGroupList *groupList)
: hwnd(hListbox), flags(0), originalProc(NULL), buttonTheme(NULL), groups(groupList),
mouseoverId(LB_ERR), capturedId(LB_ERR), expandedImage(NULL), collapsedImage(NULL)
{
if (IsWindowUnicode(hwnd))
flags |= SLF_UNICODE;
buttonTheme = (UxIsAppThemed()) ? UxOpenThemeData(hwnd, L"Button") : NULL;
groups->AddRef();
UpdateCount();
}
Listbox::~Listbox()
{
if (NULL != hwnd)
{
RemoveProp(hwnd, MAKEINTATOM(SERVICELIST_PROP));
if (NULL != originalProc)
{
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc);
CallPrevProc(WM_DESTROY, 0, 0L);
}
}
if (NULL != groups)
groups->Release();
if (NULL != buttonTheme)
UxCloseThemeData(buttonTheme);
if (NULL != expandedImage)
expandedImage->Release();
if (NULL != collapsedImage)
collapsedImage->Release();
}
HRESULT Listbox::AttachToWindow(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance)
{
if (0 == SERVICELIST_PROP)
{
SERVICELIST_PROP = GlobalAddAtom(TEXT("omSetupListbox"));
if (0 == SERVICELIST_PROP) return E_UNEXPECTED;
}
if(NULL == hListbox || !IsWindow(hListbox) || NULL == groupList)
return E_INVALIDARG;
Listbox *list = new Listbox(hListbox, groupList);
if (NULL == list)
return E_OUTOFMEMORY;
list->originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hListbox, GWLP_WNDPROC,
(LONGX86)(LONG_PTR)Listbox_WindowProc);
if (NULL == list->originalProc || !SetProp(hListbox, MAKEINTATOM(SERVICELIST_PROP), list))
{
if (NULL != list->originalProc)
SetWindowLongPtr(hListbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)list->originalProc);
delete(list);
return E_FAIL;
}
if (NULL != pInstance)
*pInstance = list;
return S_OK;
}
LRESULT Listbox::CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return (0 != (SLF_UNICODE & flags)) ?
DefWindowProcW(hwnd, uMsg, wParam, lParam) :
DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
LRESULT Listbox::CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return (0 != (SLF_UNICODE & flags)) ?
CallWindowProcW(originalProc, hwnd, uMsg, wParam, lParam) :
CallWindowProcA(originalProc, hwnd, uMsg, wParam, lParam);
}
void Listbox::UpdateCount()
{
SendMessage(hwnd, WM_SETREDRAW, FALSE, 0L);
INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L);
size_t recordCount = (NULL != groups) ? groups->GetListboxCount() : 0;
SendMessage(hwnd, LB_SETCOUNT, (WPARAM)recordCount, 0L);
SetupListboxItem *item;
UINT cy, maxCY = 0;
for (size_t i = 0; i < recordCount; i++)
{
if (SUCCEEDED(groups->FindListboxItem(i, &item)) &&
item->MeasureItem(this, NULL, &cy) && cy > maxCY)
{
maxCY = cy;
}
}
SendMessage(hwnd, LB_SETITEMHEIGHT, (WPARAM)0, (LPARAM)maxCY);
if (recordCount > 0)
{
if (iSelected < 0)
iSelected = 0;
if ((size_t)iSelected >= recordCount)
iSelected = (INT)(recordCount - 1);
SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iSelected, TRUE);
SendMessage(hwnd, LB_SETANCHORINDEX, (WPARAM)iSelected, 0L);
SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iSelected, 0L);
}
SendMessage(hwnd, WM_SETREDRAW, TRUE, 0L);
}
BOOL Listbox::MeasureItem(INT itemId, UINT *cx, UINT *cy)
{
SetupListboxItem *item;
HRESULT hr = groups->FindListboxItem(itemId, &item);
return (SUCCEEDED(hr)) ? item->MeasureItem(this, cx, cy) : FALSE;
}
BOOL Listbox::DrawItem(HDC hdc, const RECT *prcItem, INT itemId, UINT itemState, UINT itemAction)
{
SetupListboxItem *item;
HRESULT hr = groups->FindListboxItem(itemId, &item);
if (FAILED(hr)) return FALSE;
if (0 != (ODS_SELECTED & itemState) && GetFocus() != hwnd)
itemState |= ODS_INACTIVE;
if (item->IsDisabled())
itemState |= ODS_DISABLED;
return item->DrawItem(this, hdc, prcItem, itemState);
}
INT Listbox::GetPageCount()
{
RECT clientRect;
if (NULL == hwnd || !GetClientRect(hwnd, &clientRect))
return 0;
INT itemHeight = (INT)SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0L);
return (clientRect.bottom - clientRect.top) / itemHeight;
}
INT Listbox::GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut)
{
INT iLast = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
if (iLast >= 0) iLast--;
SetupListboxItem *testItem;
while(iItem++ < iLast)
{
if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem)))
{
if (FALSE == testItem->IsDisabled()) break;
}
}
if (NULL != itemOut)
{
*itemOut = (iItem <= iLast) ? testItem : NULL;
}
return (iItem <= iLast) ? iItem : LB_ERR;
}
INT Listbox::GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut)
{
SetupListboxItem *testItem;
while(iItem-- > 0)
{
if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem)))
{
if (FALSE == testItem->IsDisabled()) break;
}
}
if (NULL != itemOut)
{
*itemOut = (iItem >= 0) ? testItem : NULL;
}
return (iItem >= 0) ? iItem : LB_ERR;
}
SetupListboxItem *Listbox::GetSelection()
{
INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L);
if (LB_ERR == iSelected)
return NULL;
SetupListboxItem *item;
return (SUCCEEDED(groups->FindListboxItem(iSelected, &item))) ? item : NULL;
}
BOOL Listbox::SetSelection(SetupListboxItem *item)
{
INT iItem = LB_ERR;
if (NULL != item)
{
iItem = groups->GetListboxItem(item);
if (LB_ERR == iItem)
return FALSE;
}
BOOL resultOk = (LB_ERR != SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iItem, 0L));
if (LB_ERR == iItem) resultOk = TRUE;
if (LB_ERR != iItem)
{
HWND hParent = GetParent(hwnd);
if (NULL != hParent)
SendMessage(hParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), LBN_SELCHANGE), (LPARAM)hwnd);
}
return resultOk;
}
BOOL Listbox::GetIndex(SetupListboxItem *item, INT *iItem)
{
if (NULL == iItem)
return FALSE;
*iItem = (NULL != item && NULL != groups) ? groups->GetListboxItem(item) : LB_ERR;
return (LB_ERR != *iItem);
}
INT_PTR Listbox::KeyToItem(INT vKey, INT iCaret)
{
SetupListboxItem *item;
HRESULT hr = groups->FindListboxItem(iCaret, &item);
if (FAILED(hr)) return -1;
RECT itemRect;
GetItemRect(iCaret, &itemRect);
INT_PTR result = item->KeyToItem(this, &itemRect, vKey);
if (-1 != result) return result;
INT iTarget, iCount;
switch(vKey)
{
case VK_UP:
case VK_LEFT:
iTarget = GetPrevEnabledItem(iCaret, NULL);
if (LB_ERR != iTarget) return iTarget;
SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L);
SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
return -2;
case VK_DOWN:
case VK_RIGHT:
iTarget = GetNextEnabledItem(iCaret, NULL);
if (LB_ERR != iTarget) return iTarget;
SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)iCaret, 0L);
return -2;
case VK_HOME:
if (iCaret > 0)
{
SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L);
iTarget = GetNextEnabledItem(-1, NULL);
if (iTarget >= iCaret) iTarget = LB_ERR;
if (LB_ERR != iTarget) return iTarget;
SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
}
return -2;
case VK_PRIOR:
if (iCaret > 0)
{
INT iTop = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L);
if (iTop == iCaret)
{
INT iPage = iCaret - GetPageCount() + 1;
iTop = (iPage <= 0) ? 0 : (iPage - 1);
}
iTarget = GetPrevEnabledItem(iTop + 1, NULL);
if (LB_ERR == iTarget)
{
SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L);
iTarget = GetNextEnabledItem(iTop, NULL);
if (iTarget > iCaret) iTarget = LB_ERR;
}
if (LB_ERR != iTarget) return iTarget;
SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
}
return -2;
case VK_END:
iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
if (iCount > 0 && iCaret != (iCount - 1))
{
SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L);
iTarget = GetPrevEnabledItem(iCount, NULL);
if (iTarget <= iCaret) iTarget = LB_ERR;
if (LB_ERR != iTarget) return iTarget;
SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
}
return -2;
case VK_NEXT:
iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
if (iCount > 0 && iCaret != (iCount - 1))
{
INT iPage = GetPageCount();
INT iBottom = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L) + iPage - 1;
if (iBottom == iCaret)
{
iBottom += iPage;
if (iBottom >= iCount) iBottom = iCount -1;
}
iTarget = GetNextEnabledItem(iBottom - 1, NULL);
if (LB_ERR == iTarget)
{
SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L);
iTarget = GetPrevEnabledItem(iBottom, NULL);
if (iTarget < iCaret) iTarget = LB_ERR;
}
if (LB_ERR != iTarget) return iTarget;
SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE);
}
return -2;
}
return result;
}
INT_PTR Listbox::CharToItem(INT vKey, INT caretPos)
{
return -2;
//SetupListboxItem *item;
//HRESULT hr = groups->FindListboxItem(caretPos, &item);
//return (SUCCEEDED(hr)) ? item->CharToItem(this, vKey) : -1;
}
INT Listbox::GetCheckboxThemeState(BOOL checked, UINT state)
{
if (FALSE != checked)
{
if (0 != (ODS_DISABLED & state)) return CBS_CHECKEDDISABLED;
if (0 != (ODS_HOTLIGHT & state)) return CBS_CHECKEDHOT;
if (0 != (ODS_SELECTED & state)) return CBS_CHECKEDPRESSED;
return CBS_CHECKEDNORMAL;
}
if (0 != (ODS_DISABLED & state)) return CBS_UNCHECKEDDISABLED;
if (0 != (ODS_HOTLIGHT & state)) return CBS_UNCHECKEDHOT;
if (0 != (ODS_SELECTED & state)) return CBS_UNCHECKEDPRESSED;
return CBS_UNCHECKEDNORMAL;
}
BOOL Listbox::DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect)
{
if (NULL != buttonTheme)
{
INT stateId = GetCheckboxThemeState(checked, state);
if (SUCCEEDED(UxDrawThemeBackground(buttonTheme, hdc, BP_CHECKBOX, stateId, pRect, pClipRect)))
return TRUE;
}
UINT stateId = DFCS_BUTTONCHECK;
if (FALSE != checked) stateId |= DFCS_CHECKED;
if (0 != (ODS_DISABLED & state)) stateId |= DFCS_INACTIVE;
if (0 != (ODS_HOTLIGHT & state)) stateId |= DFCS_HOT;
if (0 != (ODS_SELECTED & state)) stateId |= DFCS_PUSHED;
return DrawFrameControl(hdc, (LPRECT)pRect,DFC_BUTTON, stateId);
}
BOOL Listbox::GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize)
{
if (NULL != buttonTheme)
{
HDC hdcMine = NULL;
if (NULL == hdc)
{
hdcMine = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
hdc = hdcMine;
}
INT stateId = GetCheckboxThemeState(checked, state);
HRESULT hr = UxGetThemePartSize(buttonTheme, hdc, BP_CHECKBOX,
stateId, NULL, TS_DRAW, pSize);
if (NULL != hdcMine)
ReleaseDC(hwnd, hdcMine);
if (SUCCEEDED(hr)) return TRUE;
}
pSize->cx = 13;
pSize->cy = 13;
return TRUE;
}
void Listbox::OnDestroy()
{
delete(this);
}
INT Listbox::HitTest(POINT pt, RECT *prcItem)
{
RECT itemRect;
INT itemId = (INT)SendMessage(hwnd, LB_ITEMFROMPOINT, 0, MAKELONG(pt.x, pt.y));
if (LB_ERR == itemId ||
LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect) ||
FALSE == PtInRect(&itemRect, pt))
{
return LB_ERR;
}
if (NULL != prcItem)
CopyRect(prcItem, &itemRect);
return itemId;
}
void Listbox::GetItemRect(INT itemId, RECT *prcItem)
{
if (LB_ERR == ::SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)prcItem))
SetRectEmpty(prcItem);
}
BOOL Listbox::DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt)
{
if (WM_MOUSEMOVE == mouseEvent &&
0 != ((MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) & mouseFlags))
{
flags |= SLF_DRAGMOVE;
}
else
{
flags &= ~SLF_DRAGMOVE;
}
return (0 != (SLF_DRAGMOVE & flags));
}
void Listbox::OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc)
{
POINT pt;
POINTSTOPOINT(pt, pts);
SetupListboxItem *item;
RECT itemRect;
if (LB_ERR != capturedId)
{
if (SUCCEEDED(groups->FindListboxItem(capturedId, &item)))
{
GetItemRect(capturedId, &itemRect);
if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt)))
{
CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts));
}
return;
}
capturedId = LB_ERR;
}
if (DoDragAndDrop(mouseEvent, mouseFlags, pt))
return;
INT itemId = HitTest(pt, &itemRect);
if (mouseoverId != itemId)
{
if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item)))
{
RECT leaveRect;
GetItemRect(mouseoverId, &leaveRect);
item->MouseLeave(this, &leaveRect);
}
mouseoverId = itemId;
TRACKMOUSEEVENT tm;
tm.cbSize = sizeof(TRACKMOUSEEVENT);
tm.hwndTrack = hwnd;
tm.dwFlags = TME_LEAVE;
if (LB_ERR == mouseoverId)
tm.dwFlags |= TME_CANCEL;
TrackMouseEvent(&tm);
}
if (LB_ERR != mouseoverId)
{
if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item)))
{
BOOL callListbox = FALSE;
if (FALSE != item->IsDisabled())
{
switch(mouseEvent)
{
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case 0x020C /*WM_XBUTTONUP*/:
callListbox = TRUE;
break;
}
}
else
{
if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt)))
{
callListbox = TRUE;
}
}
if (FALSE != callListbox)
{
CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts));
}
return;
}
}
if (FALSE != fDefaultHandler)
{
CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts));
}
}
void Listbox::OnMouseLeave()
{
if (LB_ERR != mouseoverId)
{
SetupListboxItem *item;
INT itemId = mouseoverId;
mouseoverId = LB_ERR;
if (SUCCEEDED(groups->FindListboxItem(itemId, &item)))
{
RECT itemRect;
GetItemRect(itemId, &itemRect);
if (item->MouseLeave(this, &itemRect))
return;
}
}
CallPrevProc(WM_MOUSELEAVE, 0, 0L);
}
void Listbox::SetCapture(SetupListboxItem *item)
{
INT prevCapturedId = capturedId;
capturedId = (NULL != item) ? groups->GetListboxItem(item) : LB_ERR;
NotifyReleaseCapture(prevCapturedId, item);
if (LB_ERR != capturedId && ::GetCapture() != hwnd)
::SetCapture(hwnd);
}
SetupListboxItem *Listbox::GetCapture()
{
SetupListboxItem *capturedItem;
if (LB_ERR == capturedId || FAILED(groups->FindListboxItem(capturedId, &capturedItem)))
capturedItem = NULL;
return capturedItem;
}
void Listbox::ReleaseCapture()
{
if (LB_ERR != capturedId)
{
INT prevCapturedId = capturedId;
capturedId = LB_ERR;
NotifyReleaseCapture(prevCapturedId, NULL);
if (::GetCapture() == hwnd)
::ReleaseCapture();
}
}
void Listbox::NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain)
{
if (LB_ERR == itemId)
return;
SetupListboxItem *item;
if (SUCCEEDED(groups->FindListboxItem(itemId, &item)))
{
RECT itemRect;
GetItemRect(itemId, &itemRect);
item->CaptureChanged(this, &itemRect, itemGain);
}
}
void Listbox::OnCaptureChanged(HWND hwndGained)
{
if (hwnd != hwndGained && LB_ERR != capturedId)
{
INT prevCapturedId = capturedId;
capturedId = LB_ERR;
NotifyReleaseCapture(prevCapturedId, NULL);
}
}
BOOL Listbox::InvalidateRect(const RECT *prcInvalidate, BOOL fErase)
{
return ::InvalidateRect(hwnd, prcInvalidate, fErase);
}
BOOL Listbox::InvalidateItem(INT itemId, BOOL fErase)
{
if (itemId < 0) return FALSE;
RECT itemRect;
if (LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect))
return FALSE;
return ::InvalidateRect(hwnd, &itemRect, fErase);
}
void Listbox::OnEraseBkGround(HDC hdc)
{
INT iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
RECT clientRect, itemRect;
GetClientRect(hwnd, &clientRect);
if (iCount > 0 &&
LB_ERR != SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)(iCount - 1), (LPARAM)&itemRect))
{
clientRect.top = itemRect.top;
}
if (clientRect.top < clientRect.bottom)
{
HBRUSH hb = NULL;
HWND hParent = GetParent(hwnd);
if (NULL != hParent)
{
hb = (HBRUSH)SendMessage(hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc, (LPARAM)hwnd);
}
if (NULL == hb)
{
hb = GetSysColorBrush(COLOR_WINDOW);
}
FillRect(hdc, &clientRect, hb);
}
}
void Listbox::OnCommand(INT commandId, INT eventId, HWND hControl)
{
if (NULL == hControl)
{
SetupListboxItem *item = GetSelection();
if (NULL != item)
{
item->Command(this, commandId, eventId);
}
}
}
SetupImage *Listbox::GetExpandboxImage(HDC hdc, BOOL fExpanded)
{
if (fExpanded)
{
if (NULL == expandedImage)
expandedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(137), 3);
return expandedImage;
}
if (NULL == collapsedImage)
collapsedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(135), 3);
return collapsedImage;
}
BOOL Listbox::DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg)
{
SetupImage *image = GetExpandboxImage(hdc, fExpanded);
return (NULL != image) ?
image->DrawImage(hdc, pRect->left, pRect->top,
pRect->right - pRect->left, pRect->bottom- pRect->top,
0, 0, rgbBk, rgbFg)
: FALSE;
}
BOOL Listbox::GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize)
{
SetupImage *image = GetExpandboxImage(hdc, fExpanded);
return (NULL != image) ? image->GetSize(pSize) : FALSE;
}
HMENU Listbox::GetContextMenu(UINT menuId)
{
HMENU baseMenu = WASABI_API_LOADMENUW(IDR_SETUPMENU);
if (NULL == baseMenu)
return NULL;
switch(menuId)
{
case menuGroupContext:
return GetSubMenu(baseMenu, 0);
}
return NULL;
}
LRESULT Listbox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY:
OnDestroy();
return 0;
case WM_MOUSEMOVE:
OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::MouseMove);
return 0;
case WM_LBUTTONDOWN:
OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDown);
return 0;
case WM_LBUTTONUP:
OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::LButtonUp);
return 0;
case WM_LBUTTONDBLCLK:
OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDblClk);
return 0;
case WM_RBUTTONDOWN:
OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::RButtonDown);
return 0;
case WM_RBUTTONUP:
OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::RButtonUp);
return 0;
case WM_MOUSELEAVE:
OnMouseLeave();
return 0;
case WM_CAPTURECHANGED:
OnCaptureChanged((HWND)lParam);
break;
case WM_ERASEBKGND:
OnEraseBkGround((HDC)wParam);
return TRUE;
case WM_COMMAND:
OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
return 0;
}
return CallPrevProc(uMsg, wParam, lParam);
}
static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Listbox *list = GetList(hwnd);
if (NULL != list)
return list->WindowProc(uMsg, wParam, lParam);
return (IsWindowUnicode(hwnd)) ?
DefWindowProcW(hwnd, uMsg, wParam, lParam) :
DefWindowProcA(hwnd, uMsg, wParam, lParam);
}