#include "ListView.h"
#include "LogSingleton.h"
#include "resource.h"
+#include "String++.h"
#include <commctrl.h>
SendMessage(hWndTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM) MAKELONG (30000, 0));
// match tip width used elsewhere
SendMessage(hWndTip, TTM_SETMAXTIPWIDTH, 0, 450);
+
+ // switch to using wide-char WM_NOTIFY messages
+ ListView_SetUnicodeFormat(hWndListView, TRUE);
}
void
headers = headers_;
// create the columns
- LVCOLUMN lvc;
+ LVCOLUMNW lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
int i;
for (i = 0; headers[i].text != 0; i++)
{
+ std::wstring h = LoadStringW(headers[i].text);
+
lvc.iSubItem = i;
- lvc.pszText = const_cast <char *> (headers[i].text);
+ lvc.pszText = const_cast <wchar_t *> (h.c_str());
lvc.cx = 100;
lvc.fmt = headers[i].fmt;
- ListView_InsertColumn(hWndListView, i, &lvc);
+ SendMessage(hWndListView, LVM_INSERTCOLUMNW, i, (LPARAM)&lvc);
}
// now do some width calculations
}
}
+// wrappers to help instantiations of the noteColumnWidth() template call the
+// right version of GetTextExtentPoint32
+#undef GetTextExtentPoint32
+
+static BOOL GetTextExtentPoint32(HDC hdc, LPCSTR lpString, int c, LPSIZE psizl)
+{
+ return GetTextExtentPoint32A(hdc, lpString, c, psizl);
+}
+
+static BOOL GetTextExtentPoint32(HDC hdc, LPCWSTR lpString, int c, LPSIZE psizl)
+{
+ return GetTextExtentPoint32W(hdc, lpString, c, psizl);
+}
+
+template <typename T>
void
-ListView::noteColumnWidth(int col_num, const std::string& string)
+ListView::noteColumnWidth(int col_num, const T& string)
{
SIZE s = { 0, 0 };
headers[col_num].width = width;
}
+// explicit instantiation
+template void ListView::noteColumnWidth(int col_num, const std::string& string);
+template void ListView::noteColumnWidth(int col_num, const std::wstring& wstring);
+
void
ListView::noteColumnWidthEnd()
{
RedrawWindow(hWndListView, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
-// Helper class: The char * pointer we hand back needs to remain valid for some
-// time after OnNotify returns, when the std::string we have retrieved has gone
-// out of scope, so a static instance of this class maintains a local cache.
-class StringCache
+// Helper class: The pointer we hand back needs to remain valid for some time
+// after OnNotify returns, when the string object we have retrieved has gone out
+// of scope, so a static instance of this class maintains a local cache.
+template <class T> class StringCache
{
+ typedef typename T::traits_type::char_type char_type;
public:
StringCache() : cache(NULL), cache_size(0) { }
- StringCache & operator = (const std::string & s)
+ StringCache & operator = (const T & s)
{
if ((s.length() + 1) > cache_size)
{
cache_size = s.length() + 1;
- cache = (char *)realloc(cache, cache_size);
+ cache = (char_type *)realloc(cache, cache_size * sizeof(char_type));
}
- strcpy(cache, s.c_str());
+ memcpy(cache, s.c_str(), (s.length() + 1) * sizeof(char_type));
return *this;
}
- operator char *() const
+ operator char_type *() const
{
return cache;
}
private:
- char *cache;
+ char_type *cache;
size_t cache_size;
};
switch (pNmHdr->code)
{
- case LVN_GETDISPINFO:
+ case LVN_GETDISPINFOW:
{
- NMLVDISPINFO *pNmLvDispInfo = (NMLVDISPINFO *)pNmHdr;
+ NMLVDISPINFOW *pNmLvDispInfo = (NMLVDISPINFOW *)pNmHdr;
#if DEBUG
Log (LOG_BABBLE) << "LVN_GETDISPINFO " << pNmLvDispInfo->item.iItem << endLog;
#endif
int iRow = pNmLvDispInfo->item.iItem;
int iCol = pNmLvDispInfo->item.iSubItem;
- static StringCache s;
+ static StringCache<std::wstring> s;
s = (*contents)[iRow]->get_text(iCol);
pNmLvDispInfo->item.pszText = s;
case LVN_GETEMPTYMARKUP:
{
NMLVEMPTYMARKUP *pNmMarkup = (NMLVEMPTYMARKUP*) pNmHdr;
-
- MultiByteToWideChar(CP_UTF8, 0,
- empty_list_text, -1,
- pNmMarkup->szMarkup, L_MAX_URL_LENGTH);
-
+ wcsncpy(pNmMarkup->szMarkup, empty_list_text.c_str(), L_MAX_URL_LENGTH);
*pResult = true;
return true;
}
if (headers[iCol].type == ListView::ControlType::popup)
{
POINT p;
- // position pop-up menu at the location of the click
GetCursorPos(&p);
+ RECT r;
+ ListView_GetSubItemRect(hWndListView, iRow, iCol, LVIR_BOUNDS, &r);
+ POINT cp = p;
+ ::ScreenToClient(hWndListView, &cp);
+
+ // if the click isn't over the pop-up button, do nothing yet (but this
+ // might be followed by a NM_DBLCLK)
+ if (cp.x < r.right - GetSystemMetrics(SM_CXVSCROLL))
+ return true;
+
+ // position pop-up menu at the location of the click
update = popup_menu(iRow, iCol, p);
}
else
}
break;
+ case NM_DBLCLK:
+ {
+ NMITEMACTIVATE *pNmItemAct = (NMITEMACTIVATE *) pNmHdr;
+#if DEBUG
+ Log (LOG_BABBLE) << "NM_DBLCLICK: pnmitem->iItem " << pNmItemAct->iItem << " pNmItemAct->iSubItem " << pNmItemAct->iSubItem << endLog;
+#endif
+ int iRow = pNmItemAct->iItem;
+ int iCol = pNmItemAct->iSubItem;
+ if (iRow < 0)
+ return false;
+
+ int update = 0;
+
+ // Inform the item of the double-click
+ update = (*contents)[iRow]->do_default_action(iCol );
+
+ // Update items, if needed
+ if (update > 0)
+ {
+ ListView_RedrawItems(hWndListView, iRow, iRow + update -1);
+ }
+
+ return true;
+ }
+ break;
+
case NM_CUSTOMDRAW:
{
NMLVCUSTOMDRAW *pNmLvCustomDraw = (NMLVCUSTOMDRAW *)pNmHdr;
case ListView::ControlType::checkbox:
{
- // get the subitem text
+ // get the subitem text (as ASCII)
char buf[3];
ListView_GetItemText(hWndListView, iRow, iCol, buf, _countof(buf));
#endif
// get the tooltip text for that item/subitem
- static StringCache tooltip;
+ static StringCache<std::string> tooltip;
tooltip = "";
if (contents)
tooltip = (*contents)[iRow]->get_tooltip(iCol);
}
void
-ListView::setEmptyText(const char *text)
+ListView::setEmptyText(unsigned int text)
{
- empty_list_text = text;
+ empty_list_text = LoadStringW(text);
}
int
// construct menu
HMENU hMenu = CreatePopupMenu();
- MENUITEMINFO mii;
+ MENUITEMINFOW mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING | MIIM_ID;
for (i = al->list.begin (); i != al->list.end (); ++i, ++j)
{
BOOL res;
- mii.dwTypeData = (char *)i->name.c_str();
+ mii.dwTypeData = const_cast <wchar_t *> (i->name.c_str());
mii.fState = (i->selected ? MFS_CHECKED : MFS_UNCHECKED |
i->enabled ? MFS_ENABLED : MFS_DISABLED);
mii.wID = j;
- res = InsertMenuItem(hMenu, -1, TRUE, &mii);
+ res = InsertMenuItemW(hMenu, -1, TRUE, &mii);
if (!res) Log (LOG_BABBLE) << "InsertMenuItem failed " << endLog;
}