|
|
/*****************************************************************************
* * lvframe.cpp * * Frame window that hosts a listview. * *****************************************************************************/
#include "sdview.h"
/*****************************************************************************
* * class LVFrame * *****************************************************************************/
LRESULT LVFrame::HandleMessage(UINT uiMsg, WPARAM wParam, LPARAM lParam) { switch (uiMsg) { FW_MSG(WM_NOTIFY); FW_MSG(WM_COMMAND); FW_MSG(WM_CONTEXTMENU); }
return super::HandleMessage(uiMsg, wParam, lParam); }
LRESULT LVFrame::ON_WM_NOTIFY(UINT uiMsg, WPARAM wParam, LPARAM lParam) { NMHDR *pnm = RECAST(NMHDR *, lParam);
if (pnm->idFrom == IDC_LIST) { switch (pnm->code) {
case LVN_ITEMACTIVATE: { NMITEMACTIVATE *pia = CONTAINING_RECORD(pnm, NMITEMACTIVATE, hdr); return SendSelfMessage(LM_ITEMACTIVATE, pia->iItem, 0); } break;
case LVN_GETINFOTIP: { NMLVGETINFOTIP *pgit = CONTAINING_RECORD(pnm, NMLVGETINFOTIP, hdr); LPTSTR pszBuf = pgit->pszText; SendSelfMessage(LM_GETINFOTIP, pgit->iItem, RECAST(LPARAM, pgit)); LPTSTR pszInfoTip = pgit->pszText; pgit->pszText = pszBuf; _it.SetInfoTip(pgit, pszInfoTip); } return 0;
case LVN_DELETEITEM: { NMLISTVIEW *plv = CONTAINING_RECORD(pnm, NMLISTVIEW, hdr); SendSelfMessage(LM_DELETEITEM, plv->iItem, plv->lParam); } return 0;
default:; } } return super::HandleMessage(uiMsg, wParam, lParam); }
LRESULT LVFrame::ON_WM_COMMAND(UINT uiMsg, WPARAM wParam, LPARAM lParam) { int iSel;
switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDM_COPY: iSel = GetCurSel(); if (iSel >= 0) { SendSelfMessage(LM_COPYTOCLIPBOARD, iSel, iSel + 1); } return 0;
case IDM_COPYALL: SendSelfMessage(LM_COPYTOCLIPBOARD, 0, ListView_GetItemCount(_hwndChild)); return 0; } return super::HandleMessage(uiMsg, wParam, lParam); }
LRESULT LVFrame::ON_WM_CONTEXTMENU(UINT uiMsg, WPARAM wParam, LPARAM lParam) { int iItem; HMENU hmenu;
if ((DWORD)lParam == 0xFFFFFFFF) { iItem = ListView_GetCurSel(_hwndChild); if (iItem < 0) { goto fail; }
RECT rc; if (!ListView_GetItemRect(_hwndChild, iItem, &rc, LVIR_LABEL)) { goto fail; } MapWindowRect(_hwndChild, HWND_DESKTOP, &rc); int cyHalf = (rc.bottom - rc.top)/2; lParam = MAKELPARAM(rc.left + cyHalf, rc.top + cyHalf); } else { LVHITTESTINFO hti; hti.pt.x = GET_X_LPARAM(lParam); hti.pt.y = GET_Y_LPARAM(lParam); ScreenToClient(_hwndChild, &hti.pt); iItem = ListView_HitTest(_hwndChild, &hti); if (iItem < 0) { goto fail; } ListView_SetCurSel(_hwndChild, iItem); }
hmenu = RECAST(HMENU, SendSelfMessage(LM_GETCONTEXTMENU, iItem, 0)); if (!hmenu) { goto fail; }
TrackPopupMenuEx(hmenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_NONOTIFY, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), _hwnd, NULL); DestroyMenu(hmenu); return 0;
fail: return super::HandleMessage(uiMsg, wParam, lParam); }
BOOL LVFrame::CreateChild(DWORD dwStyle, DWORD dwExStyle) { _hwndChild = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, 0,0,0,0, _hwnd, RECAST(HMENU, IDC_LIST), g_hinst, 0);
if (!_hwndChild) return FALSE;
ListView_SetExtendedListViewStyleEx(_hwndChild, dwExStyle, dwExStyle);
SetFocus(_hwndChild);
_it.Attach(_hwndChild);
return TRUE; }
BOOL LVFrame::AddColumns(const LVFCOLUMN *pcol) { int cxChar = LOWORD(GetDialogBaseUnits());
for (; pcol->cch; pcol++) { LVCOLUMN lvc; TCHAR szName[MAX_PATH]; LoadString(g_hinst, pcol->ids, szName, ARRAYSIZE(szName));
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvc.fmt = pcol->fmt; lvc.pszText = szName; lvc.cx = pcol->cch * cxChar; ListView_InsertColumn(_hwndChild, MAXLONG, &lvc); } return TRUE; }
void *LVFrame::GetLVItem(int iItem) { LVITEM lvi; lvi.iItem = iItem; lvi.iSubItem = 0; lvi.mask = LVIF_PARAM; lvi.lParam = 0; ListView_GetItem(_hwndChild, &lvi); return RECAST(LPVOID, lvi.lParam); }
/*****************************************************************************
* * LVInfoTip * *****************************************************************************/
void LVInfoTip::Attach(HWND hwnd) { if (SetProp(hwnd, GetSubclassProperty(), RECAST(HANDLE, this))) { _wndprocPrev = SubclassWindow(hwnd, SubclassWndProc); }
// Those infotips can get really long, so set the autopop delay
// to the maximum allowable value.
HWND hwndTT = ListView_GetToolTips(hwnd); if (hwndTT) { SendMessage(hwndTT, TTM_SETDELAYTIME, TTDT_AUTOPOP, MAXSHORT); }
}
void LVInfoTip::FreeLastTipAlt() { if (_pszLastTipAlt) { LPSSTR pszFree = _pszLastTipAlt; _pszLastTipAlt = NULL; delete [] pszFree; } }
void LVInfoTip::SetInfoTip(NMLVGETINFOTIP *pgit, LPCTSTR pszTip) { _pszLastTip = NULL; FreeLastTipAlt();
if (pgit->pszText != pszTip) { if (lstrlen(pszTip) >= pgit->cchTextMax) { _pszLastTip = pszTip; } lstrcpyn(pgit->pszText, pszTip, pgit->cchTextMax); }
}
//
// Convert from TCHAR to SCHAR.
//
inline int T2S(LPCTSTR pszIn, int cchIn, LPSSTR pszOut, int cchOut) { #ifdef UNICODE
return WideCharToMultiByte(CP_ACP, 0, pszIn, cchIn, pszOut, cchOut, NULL, NULL); #else
return MultiByteToWideChar(CP_ACP, 0, pszIn, cchIn, pszOut, cchOut); #endif
}
//
// Make _pszLastTipAlt match _pszLastTip, but of opposite character set.
//
BOOL LVInfoTip::ThunkLastTip() { ASSERT(_pszLastTip); FreeLastTipAlt(); int cch = T2S(_pszLastTip, -1, NULL, 0); if (cch) { _pszLastTipAlt = new SCHAR[cch]; if (_pszLastTipAlt && T2S(_pszLastTip, -1, _pszLastTipAlt, cch)) { return TRUE; } } return FALSE; }
LRESULT LVInfoTip::SubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LVInfoTip *self = RECAST(LVInfoTip *, GetProp(hwnd, GetSubclassProperty())); if (self) { LRESULT lres; NMHDR *pnm; switch (uMsg) { case WM_NOTIFY: pnm = RECAST(NMHDR *, lParam); switch (pnm->code) { case TTN_GETDISPINFOA: case TTN_GETDISPINFOW: lres = CallWindowProc(self->_wndprocPrev, hwnd, uMsg, wParam, lParam); if (SendMessage(pnm->hwndFrom, TTM_GETMAXTIPWIDTH, 0, 0) >= 0) {
// It's an infotip. Tweak it to suit our needs.
NMTTDISPINFO *ptdi = CONTAINING_RECORD(pnm, NMTTDISPINFO, hdr);
// Set the width to the maximum allowed without going single-line.
SendMessage(pnm->hwndFrom, TTM_SETMAXTIPWIDTH, 0, MAXLONG);
// If we overflowed the returned buffer, then listview used
// only a partial infotip. So fill in the rest here.
if (self->_pszLastTip) { if (pnm->code == TTN_GETDISPINFO) { ptdi->lpszText = CCAST(LPTSTR, self->_pszLastTip); } else { if (self->ThunkLastTip()) { ptdi->lpszText = RECAST(LPTSTR, self->_pszLastTipAlt); } } } } else { self->_pszLastTip = NULL; } return lres; } } return CallWindowProc(self->_wndprocPrev, hwnd, uMsg, wParam, lParam); } else { return DefWindowProc(hwnd, uMsg, wParam, lParam); } }
|