879 lines
22 KiB
C++
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);
|
|
|
|
}
|