- Preliminary implementation of TVS_NOSCROLL and TVS_NOHSCROLL

- Implement A and W versions of WM_NOTIFY based on response to
  WM_NOTIFYFORMAT. Note that the EDITLABEL notifies are not done.
- Implement WM_NOTIFYFORMAT.
This commit is contained in:
Guy L. Albertelli 2002-03-20 01:29:04 +00:00 committed by Alexandre Julliard
parent 94e9a6f901
commit b4994d18e9
1 changed files with 212 additions and 47 deletions

View File

@ -127,6 +127,8 @@ typedef struct tagTREEVIEW_INFO
BOOL bIgnoreEditKillFocus;
BOOL bLabelChanged;
BOOL bNtfUnicode; /* TRUE if should send NOTIFY with W */
BOOL bUnicode; /* set by CCM_SETUNICODEFORMAT */
HIMAGELIST himlNormal;
int normalImageHeight;
int normalImageWidth;
@ -192,6 +194,7 @@ static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT);
static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel);
static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr);
static LRESULT TREEVIEW_HScroll(TREEVIEW_INFO *, WPARAM);
static LRESULT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam);
/* Random Utilities *****************************************************/
@ -409,6 +412,17 @@ TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
/* Notifications ************************************************************/
static LRESULT
TREEVIEW_SendRealNotify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
if (infoPtr->bNtfUnicode)
return (BOOL)SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
wParam, lParam);
else
return (BOOL)SendMessageA(infoPtr->hwndNotify, WM_NOTIFY,
wParam, lParam);
}
static BOOL
TREEVIEW_SendSimpleNotify(TREEVIEW_INFO *infoPtr, UINT code)
{
@ -420,24 +434,38 @@ TREEVIEW_SendSimpleNotify(TREEVIEW_INFO *infoPtr, UINT code)
nmhdr.idFrom = GetWindowLongA(hwnd, GWL_ID);
nmhdr.code = code;
return (BOOL)SendMessageA(infoPtr->hwndNotify, WM_NOTIFY,
(WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
return (BOOL)TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
}
static VOID
TREEVIEW_TVItemFromItem(UINT mask, TVITEMA *tvItem, TREEVIEW_ITEM *item)
TREEVIEW_TVItemFromItem(TREEVIEW_INFO *infoPtr, UINT mask, TVITEMA *tvItem, TREEVIEW_ITEM *item)
{
tvItem->mask = mask;
tvItem->hItem = item;
tvItem->state = item->state;
tvItem->stateMask = 0;
tvItem->iImage = item->iImage;
tvItem->pszText = item->pszText;
tvItem->cchTextMax = item->cchTextMax;
tvItem->iImage = item->iImage;
tvItem->iSelectedImage = item->iSelectedImage;
tvItem->cChildren = item->cChildren;
tvItem->lParam = item->lParam;
/* **** **** **** **** WARNING **** **** **** **** */
/* This control stores all the data in A format */
/* we will convert it to W if the notify format */
/* is Unicode. */
/* **** **** **** **** WARNING **** **** **** **** */
if (infoPtr->bNtfUnicode) {
INT len = MultiByteToWideChar( CP_ACP, 0, item->pszText, -1, NULL, 0 );
if (len > 1) {
tvItem->pszText = (LPSTR)COMCTL32_Alloc (len*sizeof(WCHAR));
MultiByteToWideChar( CP_ACP, 0, item->pszText, -1, (LPWSTR)tvItem->pszText, len*sizeof(WCHAR) );
}
}
else
tvItem->pszText = item->pszText;
}
static BOOL
@ -446,6 +474,7 @@ TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr, UINT code, UINT action,
{
HWND hwnd = infoPtr->hwnd;
NMTREEVIEWA nmhdr;
BOOL ret;
TRACE("code:%x action:%x olditem:%p newitem:%p\n",
code, action, oldItem, newItem);
@ -458,17 +487,22 @@ TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr, UINT code, UINT action,
nmhdr.action = action;
if (oldItem)
TREEVIEW_TVItemFromItem(mask, &nmhdr.itemOld, oldItem);
TREEVIEW_TVItemFromItem(infoPtr, mask, &nmhdr.itemOld, oldItem);
if (newItem)
TREEVIEW_TVItemFromItem(mask, &nmhdr.itemNew, newItem);
TREEVIEW_TVItemFromItem(infoPtr, mask, &nmhdr.itemNew, newItem);
nmhdr.ptDrag.x = 0;
nmhdr.ptDrag.y = 0;
return (BOOL)SendMessageA(infoPtr->hwndNotify, WM_NOTIFY,
ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)GetWindowLongA(hwnd, GWL_ID),
(LPARAM)&nmhdr);
if (infoPtr->bNtfUnicode) {
COMCTL32_Free(nmhdr.itemOld.pszText);
COMCTL32_Free(nmhdr.itemNew.pszText);
}
return ret;
}
static BOOL
@ -492,7 +526,7 @@ TREEVIEW_SendTreeviewDnDNotify(TREEVIEW_INFO *infoPtr, UINT code,
nmhdr.ptDrag.x = pt.x;
nmhdr.ptDrag.y = pt.y;
return (BOOL)SendMessageA(infoPtr->hwndNotify, WM_NOTIFY,
return (BOOL)TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)GetWindowLongA(hwnd, GWL_ID),
(LPARAM)&nmhdr);
}
@ -522,7 +556,7 @@ TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage,
nmcdhdr.clrTextBk = infoPtr->clrBk;
nmcdhdr.iLevel = 0;
return (BOOL)SendMessageA(infoPtr->hwndNotify, WM_NOTIFY,
return (BOOL)TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)GetWindowLongA(hwnd, GWL_ID),
(LPARAM)&nmcdhdr);
}
@ -570,7 +604,7 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
nmcd->uItemState, nmcd->lItemlParam);
retval = SendMessageA(infoPtr->hwndNotify, WM_NOTIFY,
retval = TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)GetWindowLongA(hwnd, GWL_ID),
(LPARAM)&nmcdhdr);
@ -583,7 +617,9 @@ static BOOL
TREEVIEW_BeginLabelEditNotify(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *editItem)
{
HWND hwnd = infoPtr->hwnd;
LPSTR allocated = NULL;
NMTVDISPINFOA tvdi;
BOOL ret;
tvdi.hdr.hwndFrom = hwnd;
tvdi.hdr.idFrom = GetWindowLongA(hwnd, GWL_ID);
@ -593,11 +629,29 @@ TREEVIEW_BeginLabelEditNotify(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *editItem)
tvdi.item.hItem = editItem;
tvdi.item.state = editItem->state;
tvdi.item.lParam = editItem->lParam;
tvdi.item.pszText = editItem->pszText;
tvdi.item.cchTextMax = editItem->cchTextMax;
if (infoPtr->bNtfUnicode) {
INT len = MultiByteToWideChar( CP_ACP, 0, editItem->pszText, -1, NULL, 0 );
if (len > 1) {
tvdi.item.pszText = allocated = (LPSTR)COMCTL32_Alloc (len*sizeof(WCHAR));
MultiByteToWideChar( CP_ACP, 0, editItem->pszText, -1, (LPWSTR)tvdi.item.pszText, len*sizeof(WCHAR) );
tvdi.item.cchTextMax = len*sizeof(WCHAR);
}
else {
tvdi.item.pszText = editItem->pszText; /* ??? */
tvdi.item.cchTextMax = editItem->cchTextMax; /* ??? */
}
}
else {
tvdi.item.pszText = editItem->pszText;
tvdi.item.cchTextMax = editItem->cchTextMax;
}
return SendMessageA(infoPtr->hwndNotify, WM_NOTIFY, tvdi.hdr.idFrom,
(LPARAM)&tvdi);
ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr,
tvdi.hdr.idFrom,
(LPARAM)&tvdi);
if (allocated)
COMCTL32_Free(allocated);
return ret;
}
static void
@ -613,7 +667,8 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
callback.hdr.hwndFrom = hwnd;
callback.hdr.idFrom = GetWindowLongA(hwnd, GWL_ID);
callback.hdr.code = TVN_GETDISPINFOA;
callback.hdr.code = (infoPtr->bNtfUnicode) ? TVN_GETDISPINFOW :
TVN_GETDISPINFOA;
/* 'state' always contains valid value, as well as 'lParam'.
* All other parameters are uninitialized.
@ -629,7 +684,8 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
if (mask & TVIF_TEXT)
wineItem->textWidth = 0;
SendMessageA(infoPtr->hwndNotify, WM_NOTIFY, callback.hdr.idFrom, (LPARAM)&callback);
TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)callback.hdr.idFrom, (LPARAM)&callback);
/* It may have changed due to a call to SetItem. */
mask &= wineItem->callbackMask;
@ -637,18 +693,75 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
if ((mask & TVIF_TEXT) && callback.item.pszText != wineItem->pszText)
{
/* Instead of copying text into our buffer user specified its own */
int len = max(lstrlenA(callback.item.pszText) + 1, TEXT_CALLBACK_SIZE);
LPSTR newText = COMCTL32_ReAlloc(wineItem->pszText, len);
if (infoPtr->bNtfUnicode) {
LPWSTR newText;
int buflen;
int len = WideCharToMultiByte( CP_ACP, 0,
(LPWSTR)callback.item.pszText, -1,
NULL, 0, NULL, NULL );
buflen = max((len+1)*sizeof(WCHAR), TEXT_CALLBACK_SIZE);
newText = (LPWSTR)COMCTL32_ReAlloc(wineItem->pszText, buflen);
if (newText)
{
wineItem->pszText = newText;
strcpy(wineItem->pszText, callback.item.pszText);
wineItem->cchTextMax = len;
TRACE("returned wstr %s, len=%d, buflen=%d\n",
debugstr_w((LPWSTR)callback.item.pszText), len, buflen);
if (newText)
{
wineItem->pszText = (LPSTR)newText;
WideCharToMultiByte( CP_ACP, 0,
(LPWSTR)callback.item.pszText, -1,
wineItem->pszText, buflen,
NULL, NULL );
wineItem->cchTextMax = buflen;
}
/* If ReAlloc fails we have nothing to do, but keep original text */
}
/* If ReAlloc fails we have nothing to do, but keep original text */
}
else {
int len = max(lstrlenA(callback.item.pszText) + 1,
TEXT_CALLBACK_SIZE);
LPSTR newText = COMCTL32_ReAlloc(wineItem->pszText, len);
TRACE("returned str %s, len=%d\n",
debugstr_a(callback.item.pszText), len);
if (newText)
{
wineItem->pszText = newText;
strcpy(wineItem->pszText, callback.item.pszText);
wineItem->cchTextMax = len;
}
/* If ReAlloc fails we have nothing to do, but keep original text */
}
}
else if (mask & TVIF_TEXT) {
/* User put text into our buffer, that is ok unless W string */
if (infoPtr->bNtfUnicode) {
LPWSTR newText;
LPSTR oldText = NULL;
int buflen;
int len = WideCharToMultiByte( CP_ACP, 0,
(LPWSTR)callback.item.pszText, -1,
NULL, 0, NULL, NULL );
buflen = max((len+1)*sizeof(WCHAR), TEXT_CALLBACK_SIZE);
newText = (LPWSTR)COMCTL32_Alloc(buflen);
TRACE("same buffer wstr %s, len=%d, buflen=%d\n",
debugstr_w((LPWSTR)callback.item.pszText), len, buflen);
if (newText)
{
oldText = wineItem->pszText;
wineItem->pszText = (LPSTR)newText;
WideCharToMultiByte( CP_ACP, 0,
(LPWSTR)callback.item.pszText, -1,
wineItem->pszText, buflen, NULL, NULL );
wineItem->cchTextMax = buflen;
if (oldText)
COMCTL32_Free(oldText);
}
}
}
if (mask & TVIF_IMAGE)
wineItem->iImage = callback.item.iImage;
@ -948,6 +1061,8 @@ TREEVIEW_DoSetItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
wineItem->pszText = newText;
wineItem->cchTextMax = len;
lstrcpynA(wineItem->pszText, tvItem->pszText, len);
TRACE("setting text %s, item %p\n",
debugstr_a(wineItem->pszText), wineItem);
}
else
{
@ -956,6 +1071,8 @@ TREEVIEW_DoSetItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
wineItem->pszText = COMCTL32_ReAlloc(wineItem->pszText,
TEXT_CALLBACK_SIZE);
wineItem->cchTextMax = TEXT_CALLBACK_SIZE;
TRACE("setting callback, item %p\n",
wineItem);
}
}
@ -1318,7 +1435,9 @@ TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
{
TRACE("%p, (%s)\n", wineItem, TREEVIEW_ItemName(wineItem));
TREEVIEW_SendTreeviewNotify(infoPtr, TVN_DELETEITEMA,
TREEVIEW_SendTreeviewNotify(infoPtr,
(infoPtr->bNtfUnicode) ? TVN_DELETEITEMW :
TVN_DELETEITEMA,
TVIF_HANDLE | TVIF_PARAM, 0, wineItem, 0);
if (wineItem->firstChild)
@ -1948,7 +2067,7 @@ TREEVIEW_SetItemA(TREEVIEW_INFO *infoPtr, LPTVITEMEXA tvItem)
}
static LRESULT
TREEVIEW_GetItemW(TREEVIEW_INFO *infoPtr, LPTVITEMEXA tvItem)
TREEVIEW_GetItemW(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem)
{
TREEVIEW_ITEM *wineItem;
INT iItem;
@ -1987,17 +2106,20 @@ TREEVIEW_GetItemW(TREEVIEW_INFO *infoPtr, LPTVITEMEXA tvItem)
if (tvItem->mask & TVIF_TEXT) {
if (wineItem->pszText == LPSTR_TEXTCALLBACKA) {
tvItem->pszText = LPSTR_TEXTCALLBACKA;
tvItem->pszText = LPSTR_TEXTCALLBACKW;
FIXME(" GetItem called with LPSTR_TEXTCALLBACK\n");
}
else if (wineItem->pszText) {
TRACE("orig str %s at %p\n",
debugstr_a(wineItem->pszText), wineItem->pszText);
MultiByteToWideChar(CP_ACP, 0, wineItem->pszText,
-1 , (LPWSTR)tvItem->pszText, tvItem->cchTextMax);
-1 , tvItem->pszText, tvItem->cchTextMax);
}
}
TRACE("item %d<%p>, txt %p, img %p, action %x\n",
iItem, tvItem, tvItem->pszText, &tvItem->iImage, tvItem->mask);
TRACE("item %d<%p>, txt %p<%s>, img %p, action %x\n",
iItem, tvItem, tvItem->pszText, debugstr_w(tvItem->pszText),
&tvItem->iImage, tvItem->mask);
return TRUE;
}
@ -2012,17 +2134,19 @@ TREEVIEW_SetItemW(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem)
tvItemA.hItem = tvItem->hItem;
tvItemA.state = tvItem->state;
tvItemA.stateMask = tvItem->stateMask;
len = WideCharToMultiByte(CP_ACP, 0, tvItem->pszText, -1,
NULL ,0 , NULL,NULL);
if (len)
{
len ++;
tvItemA.pszText = HeapAlloc(GetProcessHeap(),0,len);
len = WideCharToMultiByte(CP_ACP, 0, tvItem->pszText, -1,
tvItemA.pszText ,len , NULL,NULL);
if (tvItem->mask & TVIF_TEXT) {
len = WideCharToMultiByte(CP_ACP, 0, tvItem->pszText, -1,
NULL ,0 , NULL,NULL);
if (len) {
len ++;
tvItemA.pszText = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
len = WideCharToMultiByte(CP_ACP, 0, tvItem->pszText, -1,
tvItemA.pszText ,len*sizeof(WCHAR),
NULL,NULL);
}
else
tvItemA.pszText = NULL;
}
else
tvItemA.pszText = NULL;
tvItemA.cchTextMax = tvItem->cchTextMax;
tvItemA.iImage = tvItem->iImage;
tvItemA.iSelectedImage = tvItem->iSelectedImage;
@ -2413,6 +2537,10 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
InflateRect(&rcText, -2, -1); /* allow for the focus rect */
TRACE("drawing text %s at (%d,%d)-(%d,%d)\n",
debugstr_a(wineItem->pszText),
rcText.left, rcText.top, rcText.right, rcText.bottom);
/* Draw it */
DrawTextA(hdc,
wineItem->pszText,
@ -2515,6 +2643,8 @@ TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr)
infoPtr->treeWidth += infoPtr->scrollX;
if (infoPtr->dwStyle & TVS_NOSCROLL) return;
/* Adding one scroll bar may take up enough space that it forces us
* to add the other as well. */
if (infoPtr->treeHeight > infoPtr->clientHeight)
@ -2532,6 +2662,8 @@ TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr)
> infoPtr->clientHeight - GetSystemMetrics(SM_CYVSCROLL))
vert = TRUE;
if (horz && (infoPtr->dwStyle & TVS_NOHSCROLL)) horz = FALSE;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE;
si.nMin = 0;
@ -2917,7 +3049,10 @@ static BOOL
TREEVIEW_SendExpanding(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
UINT action)
{
return !TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDINGA, action,
return !TREEVIEW_SendTreeviewNotify(infoPtr,
(infoPtr->bNtfUnicode) ? TVN_ITEMEXPANDINGW :
TVN_ITEMEXPANDINGA,
action,
TVIF_HANDLE | TVIF_STATE | TVIF_PARAM
| TVIF_IMAGE | TVIF_SELECTEDIMAGE,
0, wineItem);
@ -2927,7 +3062,10 @@ static VOID
TREEVIEW_SendExpanded(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
UINT action)
{
TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDEDA, action,
TREEVIEW_SendTreeviewNotify(infoPtr,
(infoPtr->bNtfUnicode) ? TVN_ITEMEXPANDEDW :
TVN_ITEMEXPANDEDA,
action,
TVIF_HANDLE | TVIF_STATE | TVIF_PARAM
| TVIF_IMAGE | TVIF_SELECTEDIMAGE,
0, wineItem);
@ -3514,8 +3652,7 @@ TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel)
tvdi.item.cchTextMax = 0;
}
bCommit = (BOOL)SendMessageA(infoPtr->hwndNotify,
WM_NOTIFY,
bCommit = (BOOL)TREEVIEW_SendRealNotify(infoPtr,
(WPARAM)tvdi.hdr.idFrom, (LPARAM)&tvdi);
if (!bCancel && bCommit) /* Apply the changes */
@ -4626,6 +4763,13 @@ TREEVIEW_Create(HWND hwnd)
#endif
infoPtr->hwndToolTip = 0;
infoPtr->bUnicode = IsWindowUnicode (hwnd);
/* Determine what type of notify should be issued */
/* sets infoPtr->bNtfUnicode */
TREEVIEW_NotifyFormat(infoPtr, 0, NF_REQUERY);
if (!(infoPtr->dwStyle & TVS_NOTOOLTIPS))
infoPtr->hwndToolTip = COMCTL32_CreateToolTip(hwnd);
@ -4878,6 +5022,26 @@ TREEVIEW_Notify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
return DefWindowProcA(infoPtr->hwnd, WM_NOTIFY, wParam, lParam);
}
static LRESULT
TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
INT i;
if (lParam == NF_REQUERY) {
i = SendMessageA(GetParent (infoPtr->hwnd),
WM_NOTIFYFORMAT, infoPtr->hwnd, NF_QUERY);
if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n",
i);
i = NFR_ANSI;
}
infoPtr->bNtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
return (LRESULT)i;
}
return (LRESULT)((infoPtr->bNtfUnicode) ? NFR_UNICODE : NFR_ANSI);
}
static LRESULT
TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
@ -5027,7 +5191,7 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return TREEVIEW_GetItemA(infoPtr, (LPTVITEMEXA)lParam);
case TVM_GETITEMW:
return TREEVIEW_GetItemW(infoPtr, (LPTVITEMEXA)lParam);
return TREEVIEW_GetItemW(infoPtr, (LPTVITEMEXW)lParam);
case TVM_GETITEMHEIGHT:
return TREEVIEW_GetItemHeight(infoPtr);
@ -5161,7 +5325,8 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_NOTIFY:
return TREEVIEW_Notify(infoPtr, wParam, lParam);
/* WM_NOTIFYFORMAT */
case WM_NOTIFYFORMAT:
return TREEVIEW_NotifyFormat(infoPtr, wParam, lParam);
case WM_PAINT:
return TREEVIEW_Paint(infoPtr, wParam);