winamp/Src/Plugins/General/gen_ml/navigation.cpp

2733 lines
79 KiB
C++

#include "./navigation.h"
#include "./ml.h"
#include "./ml_ipc_0313.h"
#include "../nu/AutoChar.h"
#include "../nu/AutoWide.h"
#include "./skinning.h"
#include "./stockobjects.h"
#include "../winamp/wa_dlg.h"
#include "../winamp/gen.h"
#include "resource.h"
#include "api__gen_ml.h"
#include "../nu/CGlobalAtom.h"
#include "../nu/trace.h"
#include <windowsx.h>
#include <strsafe.h>
extern "C" winampGeneralPurposePlugin plugin;
#ifndef LONGX86
#ifdef _WIN64
#define LONGX86 LONG_PTR
#else /*_WIN64*/
#define LONGX86 LONG
#endif /*_WIN64*/
#endif // LONGX86
#define PACKVERSION(major,minor) MAKELONG(minor,major)
#define SEPARATOR L'/'
#define MLV_PREFIX_A L"mlv10_"
#define EMPTY_ITEM_NAME L"<<empty>>"
#define ITEM_SHORTNAME_MAX 512
#define SAVEVIEW_BUFFER_MAX 1024
#define ML_VIEW_MAX 32
#define NAVITEM_RANGE_MIN 8000
static CGlobalAtom NAVMGR_HWNDPROPW(L"NAVMNGR");
static CGlobalAtom WNDPROP_SCCTRLW(L"SCCTRL");
#define IREC_COUNT 3
#define IREC_NORMAL 0x00
#define IREC_SELECTED 0x01
#define IREC_INACTIVE 0x02
#define DRAGIMAGE_OFFSET_X 8
#define DRAGIMAGE_OFFSET_Y 0
typedef struct _SCEDIT
{
WNDPROC fnOldProc;
BOOL fUnicode;
}SCEDIT;
typedef struct _SCTREE
{
WNDPROC fnOldProc;
BOOL fUnicode;
DWORD focused;
BOOL supressEdit;
}SCTREE;
typedef struct _NAVITEMSTATEREC
{
LPWSTR pszFullName;
INT fCollapsed;
INT nOrder;
} NAVITEMSTATEREC;
typedef struct _NAVMNGR
{
HWND hwndHost;
INT lastUsedId;
C_Config *pConfig;
HMLIMGLST hmlilImages;
INT lockUpdate;
HTREEITEM lockFirst;
HTREEITEM lockSelected;
INT lockSelPos;
INT lastOrderIndex;
NAVITEMSTATEREC *pStates;
INT statesCount;
UINT style;
NAVITEMDRAW_I drawStruct;
HFONT hfontOld;
UINT drawInternal;
// callbacks
ONNAVITEMCLICK_I fnOnItemClick;
ONNAVITEMSELECTED_I fnOnItemSelected;
ONNAVCTRLKEYDOWN_I fnOnKeyDown;
ONNAVCTRLBEGINDRAG_I fnOnBeginDrag;
ONNAVITEMGETIMAGEINDEX_I fnOnItemGetImageIndex;
ONNAVITEMBEGINTITLEEDIT_I fnOnBeginTitleEdit;
ONNAVCTRLENDTITLEEDIT_I fnOnEndTitleEdit;
ONNAVITEMDELETE_I fnOnItemDelete;
ONNAVITEMDRAW_I fnOnCustomDraw;
ONNAVITEMSETCURSOR_I fnOnSetCursor;
ONNAVITEMHITTEST_I fnOnHitTest;
ONNAVCTRLDESTROY_I fnOnDestroy;
} NAVMNGR, *PNAVMNGR;
typedef struct _NAVITM
{
INT id;
INT iImage;
INT iSelectedImage;
WORD sortOrder;
UINT style;
HWND hwndTree;
HTREEITEM hTreeItem;
LPWSTR pszText;
INT cchTextMax;
LPWSTR pszInvariant;
INT cchInvariantMax;
HFONT hFont;
BOOL fBlockInvalid; // if set to TRUE operation do not need to inavlidate item it will be invalidated later;
LPARAM lParam;
} NAVITM, *PNAVITM;
typedef struct _TREEITEMSEARCH
{
TVITEMEXW item;
INT_PTR itemData;
BOOL fFound;
UINT flags;
} TREEITEMSEARCH;
typedef struct _SAVEVIEWDATA
{
TVITEMEXW item;
WCHAR buffer[SAVEVIEW_BUFFER_MAX];
WCHAR mlview[ML_VIEW_MAX];
C_Config *pConfig;
INT counter_root;
INT counter_write;
}SAVEVIEWDATA;
typedef struct _NAVENUMSTRUCT
{
TVITEMW item;
NAVENUMPROC_I callback;
LPARAM lParam;
HNAVCTRL hNav;
} NAVENUMSTRUCT;
typedef BOOL (CALLBACK *TREEITEMCB)(HWND, HTREEITEM, LPVOID);
#define ABS(x) (((x) > 0) ? (x) : (-x))
#define NAVSTYLE_DEFAULT 0x0000
#define NAVSTYLE_MOUSEDOWNSELECT 0x0001
#define NAVSTYLE_FOCUSED 0x0002
#define NAVSTYLE_EDITMODE 0x0004
// helpers
static BOOL GetItemColors(HNAVCTRL hNav, UINT itemState, COLORREF *rgbBk, COLORREF *rgbFg)
{
INT rgbBkIndex, rgbFgIndex;
switch(itemState)
{
case (NIS_SELECTED_I | NIS_FOCUSED_I): rgbBkIndex = WADLG_SELBAR_BGCOLOR; rgbFgIndex = WADLG_SELBAR_FGCOLOR; break;
case NIS_SELECTED_I: rgbBkIndex = WADLG_INACT_SELBAR_BGCOLOR; rgbFgIndex = WADLG_INACT_SELBAR_FGCOLOR; break;
case NIS_DROPHILITED_I: rgbBkIndex = WADLG_INACT_SELBAR_BGCOLOR; rgbFgIndex = WADLG_INACT_SELBAR_FGCOLOR; break;
default: rgbBkIndex = WADLG_ITEMBG; rgbFgIndex = WADLG_ITEMFG; break;
}
if (rgbBk) *rgbBk = WADlg_getColor(rgbBkIndex);
if (rgbFg) *rgbFg = WADlg_getColor(rgbFgIndex);
return TRUE;
}
static BOOL EnumerateTreeItems(HWND hwndTree, HTREEITEM hStart, TREEITEMCB pfnItemCallback, LPVOID user)
{
HTREEITEM hChild;
if (!pfnItemCallback) return FALSE;
if (NULL == hStart || TVI_ROOT == hStart)
hStart = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_ROOT, (LPARAM)0);
while(NULL != hStart)
{
if (!pfnItemCallback(hwndTree, hStart, user))
return FALSE;
hChild = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)hStart);
if (NULL != hChild)
{
if (!EnumerateTreeItems(hwndTree, hChild, pfnItemCallback, user))
return FALSE;
}
hStart = (HTREEITEM)SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)hStart);
}
return TRUE;
}
static BOOL CALLBACK FindTreeItemByIdCB(HWND hwndTree, HTREEITEM hItem, LPVOID user)
{
if (!user) return FALSE;
((TREEITEMSEARCH*)user)->item.hItem = hItem;
if ((BOOL)SendMessageW(hwndTree, TVM_GETITEMW, (WPARAM)0, (LPARAM)&((TREEITEMSEARCH*)user)->item))
{
if (((TREEITEMSEARCH*)user)->item.lParam &&
(INT)((TREEITEMSEARCH*)user)->itemData == ((NAVITM*)((TREEITEMSEARCH*)user)->item.lParam)->id)
{
((TREEITEMSEARCH*)user)->fFound = TRUE;
return FALSE;
}
}
return TRUE;
}
static INT CompareItemName(LCID Locale, UINT compFlags, LPCWSTR pszString, INT cchLength, HNAVITEM hItem)
{
INT result;
if (!hItem || !pszString) return 0; // error
if (NICF_INVARIANT_I & compFlags)
{
result = (((NAVITM*)hItem)->pszInvariant) ?
CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, ((NAVITM*)hItem)->pszInvariant, -1, pszString, cchLength) :
CSTR_LESS_THAN;
if (CSTR_EQUAL == result) return CSTR_EQUAL;
}
if (NICF_DISPLAY_I & compFlags || 0 == (compFlags & ~NICF_IGNORECASE_I))
{
result = (((NAVITM*)hItem)->pszText) ?
CompareStringW(Locale, (NICF_IGNORECASE_I & compFlags) ? NORM_IGNORECASE : 0, ((NAVITM*)hItem)->pszText, -1, pszString, cchLength) :
CSTR_LESS_THAN;
}
return result;
}
static BOOL CALLBACK FindTreeItemByNameCB(HWND hwndTree, HTREEITEM hItem, LPVOID user)
{
if (!user) return FALSE;
((TREEITEMSEARCH*)user)->item.hItem = hItem;
if ((BOOL)SendMessageW(hwndTree, TVM_GETITEMW, (WPARAM)0, (LPARAM)&((TREEITEMSEARCH*)user)->item))
{
if (CSTR_EQUAL == CompareItemName(((TREEITEMSEARCH*)user)->item.state, ((TREEITEMSEARCH*)user)->flags,
(LPCWSTR)((TREEITEMSEARCH*)user)->itemData, ((TREEITEMSEARCH*)user)->item.cchTextMax,
(NAVITM*)((TREEITEMSEARCH*)user)->item.lParam))
{
((TREEITEMSEARCH*)user)->fFound = TRUE;
return FALSE;
}
}
return TRUE;
}
static BOOL CALLBACK ItemSizedCB(HWND hwndTree, HTREEITEM hItem, LPVOID user)
{
((TVITEMW*)user)->hItem = hItem;
if (!SendMessageW(hwndTree, TVM_GETITEMW, (WPARAM)0, (LPARAM)user)) return FALSE;
if (((TVITEMW*)user)->lParam)
{
if (NIS_CUSTOMDRAW_I & ((NAVITM*)((TVITEMW*)user)->lParam)->style)
{
*(HTREEITEM*)((TVITEMW*)user)->pszText = hItem;
if (SendMessageW(hwndTree, TVM_GETITEMRECT, FALSE, (LPARAM)((TVITEMW*)user)->pszText))
{
InvalidateRect(hwndTree, (RECT*)((TVITEMW*)user)->pszText, TRUE);
}
}
}
return TRUE;
}
static HNAVITEM FindNavItemByNavIdEx(HWND hwndTree, INT itemId, HTREEITEM hStart)
{
TREEITEMSEARCH search;
search.fFound = FALSE;
search.itemData = (INT_PTR)itemId;
search.item.mask = TVIF_PARAM;
search.flags = 0;
EnumerateTreeItems(hwndTree, hStart, FindTreeItemByIdCB, &search);
return (search.fFound) ? (HNAVITEM)search.item.lParam : NULL;
}
static INT GetNextFreeItemId(HNAVCTRL hNav)
{
if (!hNav) return 0;
while (FindNavItemByNavIdEx(((NAVMNGR*)hNav)->hwndHost, ++((NAVMNGR*)hNav)->lastUsedId, TVI_ROOT));
return ((NAVMNGR*)hNav)->lastUsedId;
}
static INT GetRealImageIndex(HNAVCTRL hNav, HNAVITEM hItem, INT imageType, COLORREF rgbBk, COLORREF rgbFg)
{
INT mlilIndex;
if (!hNav) return -1;
mlilIndex = NavItemI_GetImageIndex(hItem, imageType);
if (-1 == mlilIndex )
{
if (((NAVMNGR*)hNav)->fnOnItemGetImageIndex) mlilIndex = ((NAVMNGR*)hNav)->fnOnItemGetImageIndex(hNav, hItem, imageType);
if (-1 == mlilIndex) return -1;
}
return MLImageListI_GetRealIndex(((NAVMNGR*)hNav)->hmlilImages, mlilIndex, rgbBk, rgbFg);
}
static BOOL CALLBACK EnumNavItemCB(HWND hwndTree, HTREEITEM hItem, LPVOID user)
{
NAVENUMSTRUCT *pData;
if (!user) return FALSE;
pData = (NAVENUMSTRUCT*)user;
pData->item.hItem = hItem;
return (BOOL)SendMessageW(hwndTree, TVM_GETITEMW, (WPARAM)0, (LPARAM)&(pData->item)) ?
pData->callback((HNAVITEM)pData->item.lParam, pData->lParam) : TRUE;
}
static BOOL CALLBACK SaveNavigationCB(HWND hwndTree, HTREEITEM hItem, LPVOID user)
{
if (!user) return FALSE; // very bad
((SAVEVIEWDATA*)user)->item.hItem = hItem;
if ((BOOL)SendMessageW(hwndTree, TVM_GETITEMW, (WPARAM)0, (LPARAM)&((SAVEVIEWDATA*)user)->item))
{
INT order;
BOOL bCollapsed = (SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)hItem) && !(TVIS_EXPANDED & ((SAVEVIEWDATA*)user)->item.state));
if (!SendMessageW(hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_PARENT, (LPARAM)hItem))
{
order = ++((SAVEVIEWDATA*)user)->counter_root;
}
else order = -1;
if (order != -1 || bCollapsed || (TVIS_SELECTED & ((SAVEVIEWDATA*)user)->item.state))
{
INT remain = NavItemI_GetFullName((HNAVITEM)((SAVEVIEWDATA*)user)->item.lParam, ((SAVEVIEWDATA*)user)->buffer, SAVEVIEW_BUFFER_MAX);
if (remain)
{
if ((order != -1 || bCollapsed) && remain < (SAVEVIEW_BUFFER_MAX - 8) )
{
if (S_OK == StringCchPrintfW(((SAVEVIEWDATA*)user)->buffer + remain, SAVEVIEW_BUFFER_MAX - remain, L",%d,%d", bCollapsed, order) &&
S_OK == StringCchPrintfW(((SAVEVIEWDATA*)user)->mlview, ML_VIEW_MAX, MLV_PREFIX_A L"%02d", (((SAVEVIEWDATA*)user)->counter_write + 1)))
{
((SAVEVIEWDATA*)user)->pConfig->WriteString(((SAVEVIEWDATA*)user)->mlview, ((SAVEVIEWDATA*)user)->buffer);
((SAVEVIEWDATA*)user)->counter_write++;
}
}
}
}
}
return TRUE;
}
static HNAVITEM GetNavItemFromTreeItem(HNAVCTRL hNav, HTREEITEM hTreeItem)
{
TVITEMW item;
item.mask = TVIF_PARAM;
item.hItem = hTreeItem;
if (!hNav) return NULL;
if (!SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETITEMW, (WPARAM)0, (LPARAM)&item)) return NULL;
return (HNAVITEM)item.lParam;
}
static HNAVITEM NavItemI_GetNextEx(HNAVITEM hItem, UINT flag) // use TVGN_ as flags
{
TVITEMW treeItem;
if (!hItem) return NULL;
treeItem.hItem = (HTREEITEM)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETNEXTITEM, (WPARAM)flag, (LPARAM)((NAVITM*)hItem)->hTreeItem);
if (!treeItem.hItem) return NULL;
treeItem.mask = TVIF_PARAM;
return (SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETITEMW, (WPARAM)0, (LPARAM)&treeItem)) ? (HNAVITEM)treeItem.lParam : NULL;
}
static void PerformCustomHitTest(HNAVCTRL hNav, POINT pt, UINT *pHitFlags, HNAVITEM *phItem) // returns nav hit test result
{
UINT flags, test;
flags = 0;
test = (pHitFlags) ? *pHitFlags : 1;
if (TVHT_NOWHERE & test) flags |= NAVHT_NOWHERE_I;
if (TVHT_ONITEMLABEL & test) flags |= NAVHT_ONITEM_I;
if (TVHT_ONITEMINDENT & test) flags |= NAVHT_ONITEMINDENT_I;
if (TVHT_ONITEMRIGHT & test) flags |= NAVHT_ONITEMRIGHT_I;
if (TVHT_ABOVE & test) flags |= NAVHT_ABOVE_I;
if (TVHT_BELOW & test) flags |= NAVHT_BELOW_I;
if (TVHT_TORIGHT & test) flags |= NAVHT_TORIGHT_I;
if (TVHT_TOLEFT & test) flags |= NAVHT_TOLEFT_I;
if (pHitFlags) *pHitFlags = flags;
if (hNav && phItem && *phItem && pHitFlags)
{
if (TVHT_ONITEMICON & test) *pHitFlags |= (SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM,
(WPARAM)TVGN_CHILD, (LPARAM)((NAVITM*)(*phItem))->hTreeItem)) ?
NAVHT_ONITEMBUTTON_I : NAVHT_ONITEM_I;
if ((NIS_WANTHITTEST_I & ((NAVITM*)(*phItem))->style) && ((NAVMNGR*)hNav)->fnOnHitTest)
{
((NAVMNGR*)hNav)->fnOnHitTest(hNav, pt, pHitFlags, phItem, ((NAVITM*)(*phItem))->lParam);
}
}
}
static HTREEITEM TreeItemFromCursor(HNAVCTRL hNav, HTREEITEM *phtiWantExpand)
{
HTREEITEM hTreeItem;
TVHITTESTINFO hit;
if (phtiWantExpand) *phtiWantExpand = NULL;
if(!GetCursorPos(&hit.pt)) return NULL;
MapWindowPoints(HWND_DESKTOP, ((NAVMNGR*)hNav)->hwndHost, &hit.pt, 1);
hTreeItem = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_HITTEST, (WPARAM)0, (LPARAM)&hit);
if (0 == (TVHT_ONITEM & hit.flags))
{
if ((TVHT_ONITEMRIGHT | TVHT_ONITEMINDENT) & hit.flags)
{
if (0 == (TVS_FULLROWSELECT & GetWindowLongPtrW(((NAVMNGR*)hNav)->hwndHost, GWL_STYLE))) hTreeItem = NULL;
}
}
if(hTreeItem)
{
HNAVITEM hItem;
hItem = GetNavItemFromTreeItem(hNav, hTreeItem);
PerformCustomHitTest(hNav, hit.pt, &hit.flags, &hItem);
hTreeItem = (hItem) ? ((NAVITM*)hItem)->hTreeItem : NULL;
if (NAVHT_ONITEMBUTTON_I & hit.flags)
{
if (phtiWantExpand) *phtiWantExpand = hTreeItem;
hTreeItem = NULL;
}
}
return hTreeItem;
}
static NAVITEMSTATEREC *NavCtrlI_FindItemStateRec(HNAVCTRL hNav, HNAVITEM hItem, BOOL fClearOnSuccess)
{
wchar_t name[1024] = {0};
if (!hNav || !hItem) return NULL;
if (NavItemI_GetFullName(hItem, name, 1024))
{
for (INT idx = 0; idx < ((NAVMNGR*)hNav)->statesCount; idx++)
{
if (((NAVMNGR*)hNav)->pStates[idx].pszFullName &&
CSTR_EQUAL == CompareStringW(LOCALE_USER_DEFAULT, 0, name, -1,
((NAVMNGR*)hNav)->pStates[idx].pszFullName, -1))
{
if (fClearOnSuccess)
{
free(((NAVMNGR*)hNav)->pStates[idx].pszFullName);
((NAVMNGR*)hNav)->pStates[idx].pszFullName = NULL;
}
return &((NAVMNGR*)hNav)->pStates[idx];
}
}
}
return NULL;
}
static LRESULT EditCtrlWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SCEDIT *pEdit;
pEdit = (SCEDIT*)GetPropW(hwnd, WNDPROP_SCCTRLW);
if (!pEdit) return (IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) : DefWindowProcA(hwnd, uMsg, wParam, lParam);
switch(uMsg)
{
case WM_NCDESTROY: // detach
RemovePropW(hwnd, WNDPROP_SCCTRLW);
if (pEdit->fUnicode)
{
CallWindowProcW(pEdit->fnOldProc, hwnd, uMsg, wParam, lParam);
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pEdit->fnOldProc);
}
else
{
CallWindowProcA(pEdit->fnOldProc, hwnd, uMsg, wParam, lParam);
SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pEdit->fnOldProc);
}
free(pEdit);
return 0;
case WM_ERASEBKGND: return 1;
case WM_NCPAINT:
{
HDC hdc;
hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_WINDOW | DCX_INTERSECTUPDATE | DCX_CLIPSIBLINGS);
if (hdc)
{
RECT rc;
GetClientRect(hwnd, &rc);
FrameRect(hdc, &rc, (HBRUSH)MlStockObjects_Get(ITEMTEXT_BRUSH));
ReleaseDC(hwnd, hdc);
}
return 0;
}
break;
case WM_PAINT:
{
RECT rc, rv;
GetClientRect(hwnd, &rc);
SetRect(&rv, 0, 0, rc.right, 1);
ValidateRect(hwnd, &rv);
SetRect(&rv, 0, rc.bottom - 1, rc.right, rc.bottom);
ValidateRect(hwnd, &rv);
SetRect(&rv, 0, 1, 1, rc.bottom);
ValidateRect(hwnd, &rv);
SetRect(&rv, rc.right-1, 1, rc.right, rc.bottom);
ValidateRect(hwnd, &rv);
break;
}
case WM_GETDLGCODE:
switch(wParam)
{
case VK_RETURN:
SendMessageW(GetParent(hwnd), TVM_ENDEDITLABELNOW, FALSE, 0L); return 0; // tell trew-view that we done and return 0
case VK_ESCAPE:
SendMessageW(GetParent(hwnd), TVM_ENDEDITLABELNOW, TRUE, 0L); return 0; // tell trew-view that we done and return 0
}
break;
case WM_SETCURSOR:
if (HTCLIENT == LOWORD(lParam))
{
SetCursor(LoadCursor(NULL, IDC_IBEAM));
return 0;
}
break;
}
return (pEdit->fUnicode) ? CallWindowProcW(pEdit->fnOldProc, hwnd, uMsg, wParam, lParam) :
CallWindowProcA(pEdit->fnOldProc, hwnd, uMsg, wParam, lParam);
}
static LRESULT TreeViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SCTREE *pTree;
pTree = (SCTREE*)GetPropW(hwnd, WNDPROP_SCCTRLW);
if (!pTree)
return (IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) : DefWindowProcA(hwnd, uMsg, wParam, lParam);
switch(uMsg)
{
case WM_NCDESTROY: // detach
RemovePropW(hwnd, WNDPROP_SCCTRLW);
if (pTree->fUnicode)
{
CallWindowProcW(pTree->fnOldProc, hwnd, uMsg, wParam, lParam);
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pTree->fnOldProc);
}
else
{
CallWindowProcA(pTree->fnOldProc, hwnd, uMsg, wParam, lParam);
SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pTree->fnOldProc);
}
free(pTree);
return 0;
case WM_ERASEBKGND:
if (wParam && (TVS_FULLROWSELECT & GetWindowLongPtrW(hwnd, GWL_STYLE)))
{
RECT rc;
HTREEITEM hItem;
GetClientRect(hwnd, &rc);
hItem = (HTREEITEM)SendMessageW(hwnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L);
if (hItem)
{
RECT ri;
*(HTREEITEM*)&ri = hItem;
if (SendMessageW(hwnd, TVM_GETITEMRECT, FALSE, (LPARAM)&ri)) rc.top = ri.bottom;
}
if (rc.top < rc.bottom)
{
SetBkColor((HDC)wParam, WADlg_getColor(WADLG_ITEMBG));
ExtTextOutW((HDC)wParam, 0, 0, ETO_OPAQUE, &rc, L"", 0, 0);
}
return 1;
}
return 0;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
{
TVHITTESTINFO hit;
HNAVITEM hItem;
NAVMNGR *pMngr;
hit.pt.x = GET_X_LPARAM(lParam);
hit.pt.y = GET_Y_LPARAM(lParam);
SendMessageW(hwnd, TVM_HITTEST, (WPARAM)0, (LPARAM)&hit);
pMngr = (NAVMNGR*)GetPropW(hwnd, NAVMGR_HWNDPROPW);
if (hit.hItem)
{
hItem = GetNavItemFromTreeItem(pMngr, hit.hItem);
PerformCustomHitTest(pMngr, hit.pt, &hit.flags, &hItem);
if (hItem && pMngr && (NAVSTYLE_MOUSEDOWNSELECT & pMngr->style))
{
SendMessageW(hwnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM)((NAVITM*)hItem)->hTreeItem);
}
}
else
hItem = NULL;
if (!hItem)
{
SendMessageW(hwnd, TVM_ENDEDITLABELNOW, (WPARAM)TRUE, 0L);
return 0;
}
else
{
HWND hEdit = FindWindowExW(hwnd, NULL, L"Edit", NULL);
if (NULL != hEdit && IsWindowVisible(hEdit))
{
PostMessageW(hwnd, uMsg, wParam, lParam);
}
else
{
pTree->supressEdit = FALSE;
if (0 != pTree->focused)
{
DWORD clicked = GetTickCount();
if (clicked >= pTree->focused && (clicked - pTree->focused) < 200)
pTree->supressEdit = TRUE;
pTree->focused = 0;
}
}
}
}
break;
case WM_LBUTTONDBLCLK:
if (TVS_FULLROWSELECT == (TVS_FULLROWSELECT & (UINT)GetWindowLongPtrW(hwnd, GWL_STYLE)))
{
TVHITTESTINFO test;
test.pt.x = GET_X_LPARAM(lParam);
test.pt.y = GET_Y_LPARAM(lParam);
if(SendMessageW(hwnd, TVM_HITTEST, 0, (LPARAM)&test) && (TVHT_ONITEMRIGHT & test.flags))
{
HWND hParent;
NMHDR hdr;
hdr.code = NM_DBLCLK;
hdr.hwndFrom = hwnd;
hdr.idFrom = GetDlgCtrlID(hwnd);
hParent = GetParent(hwnd);
if (hParent) SendMessageW(hParent, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr);
return 0;
}
}
break;
case WM_CTLCOLOREDIT:
SetTextColor((HDC)wParam, WADlg_getColor(WADLG_ITEMFG));
SetBkColor((HDC)wParam, WADlg_getColor(WADLG_ITEMBG));
return (LRESULT)MlStockObjects_Get(ITEMBCK_BRUSH);
case WM_SIZE:
{
TVITEMW item;
RECT ri;
item.mask = TVIF_PARAM;
item.pszText = (LPWSTR)&ri;
EnumerateTreeItems(hwnd, NULL, ItemSizedCB, &item);
}
break;
case WM_CHAR:
pTree->supressEdit = FALSE;
return (VK_RETURN == wParam) ? 0 :
((pTree->fUnicode) ? CallWindowProcW(pTree->fnOldProc, hwnd, uMsg, wParam, lParam) :
CallWindowProcA(pTree->fnOldProc, hwnd, uMsg, wParam, lParam));
case WM_GETDLGCODE:
{
LRESULT r = (pTree->fUnicode) ? CallWindowProcW(pTree->fnOldProc, hwnd, uMsg, wParam, lParam) :
CallWindowProcA(pTree->fnOldProc, hwnd, uMsg, wParam, lParam);
if (lParam)
{
MSG *pMsg = (LPMSG)lParam;
if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP)
{
switch(pMsg->wParam)
{
case VK_RETURN: r |= DLGC_WANTMESSAGE; break;
case VK_TAB:
case VK_ESCAPE: SendMessageW(hwnd, TVM_ENDEDITLABELNOW, TRUE, 0L); break;
}
}
}
return r;
}
case WM_SETFOCUS:
pTree->focused = GetTickCount();
break;
case WM_TIMER:
if (42 == wParam && FALSE != pTree->supressEdit)
{
KillTimer(hwnd, wParam);
pTree->supressEdit = FALSE;
return 0;
}
break;
}
return (pTree->fUnicode) ? CallWindowProcW(pTree->fnOldProc, hwnd, uMsg, wParam, lParam) :
CallWindowProcA(pTree->fnOldProc, hwnd, uMsg, wParam, lParam);
}
static BOOL SubclassEditControl(HWND hwndEdit)
{
if (!hwndEdit || !IsWindow(hwndEdit)) return FALSE;
SCEDIT *pEdit = (SCEDIT*)calloc(1, sizeof(SCEDIT));
if (!pEdit) return FALSE;
pEdit->fUnicode = IsWindowUnicode(hwndEdit);
pEdit->fnOldProc = (WNDPROC)(LONG_PTR)((pEdit->fUnicode) ? SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditCtrlWndProc) :
SetWindowLongPtrA(hwndEdit, GWLP_WNDPROC, (LONGX86)(LONG_PTR)EditCtrlWndProc));
if (!pEdit->fnOldProc || !SetPropW(hwndEdit, WNDPROP_SCCTRLW, pEdit))
{
if (pEdit->fnOldProc)
{
if (pEdit->fUnicode) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pEdit->fnOldProc);
else SetWindowLongPtrA(hwndEdit, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pEdit->fnOldProc);
}
free(pEdit);
return FALSE;
}
return TRUE;
}
static BOOL SubclassTreeView(HWND hwndTree)
{
if (!hwndTree || !IsWindow(hwndTree)) return FALSE;
SCTREE *pTree = (SCTREE*)calloc(1, sizeof(SCTREE));
if (!pTree) return FALSE;
pTree->fUnicode = IsWindowUnicode(hwndTree);
pTree->fnOldProc = (WNDPROC)(LONG_PTR)((pTree->fUnicode) ? SetWindowLongPtrW(hwndTree, GWLP_WNDPROC, (LONGX86)(LONG_PTR)TreeViewWndProc) :
SetWindowLongPtrA(hwndTree, GWLP_WNDPROC, (LONGX86)(LONG_PTR)TreeViewWndProc));
if (!pTree->fnOldProc || !SetPropW(hwndTree, WNDPROP_SCCTRLW, pTree))
{
if (pTree->fnOldProc)
{
if (pTree->fUnicode) SetWindowLongPtrW(hwndTree, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pTree->fnOldProc);
else SetWindowLongPtrA(hwndTree, GWLP_WNDPROC, (LONGX86)(LONG_PTR)pTree->fnOldProc);
}
free(pTree);
return FALSE;
}
return TRUE;
}
static BOOL NavCtrlI_SaveStates(HNAVCTRL hNav)
{
BOOL result;
SAVEVIEWDATA save;
if (!hNav || !((NAVMNGR*)hNav)->pConfig) return FALSE;
save.item.mask = TVIF_STATE | TVIF_PARAM;
save.item.stateMask = TVIS_EXPANDED | TVIS_SELECTED;
save.pConfig = ((NAVMNGR*)hNav)->pConfig;
save.counter_root = 0;
save.counter_write = 0;
result = EnumerateTreeItems(((NAVMNGR*)hNav)->hwndHost, TVI_ROOT, SaveNavigationCB, &save);
if (!result) save.counter_write = 0;
((NAVMNGR*)hNav)->pConfig->WriteInt(MLV_PREFIX_A L"count", save.counter_write);
return result;
}
static BOOL NavCtrlI_DeleteStates(HNAVCTRL hNav)
{
if (!hNav) return FALSE;
if (((NAVMNGR*)hNav)->pStates)
{
INT i;
for (i =0; i < ((NAVMNGR*)hNav)->statesCount; i++)
{
if (((NAVMNGR*)hNav)->pStates[i].pszFullName) free(((NAVMNGR*)hNav)->pStates[i].pszFullName);
}
free(((NAVMNGR*)hNav)->pStates);
((NAVMNGR*)hNav)->pStates = NULL;
}
((NAVMNGR*)hNav)->statesCount = 0;
return TRUE;
}
static BOOL NavCtrlI_LoadStates(HNAVCTRL hNav)
{
INT index, count, len;
wchar_t mlview[ML_VIEW_MAX] = {0};
const wchar_t *data;
if (!hNav || !((NAVMNGR*)hNav)->pConfig) return FALSE;
if (!NavCtrlI_DeleteStates(hNav)) return FALSE;
count = ((NAVMNGR*)hNav)->pConfig->ReadInt(MLV_PREFIX_A L"count", 0);
if (count < 1) return TRUE;
((NAVMNGR*)hNav)->pStates = (NAVITEMSTATEREC*)calloc(count, sizeof(NAVITEMSTATEREC));
if (!((NAVMNGR*)hNav)->pStates) return FALSE;
for (index = 0; index < count; index++)
{
StringCchPrintfW(mlview, ML_VIEW_MAX, MLV_PREFIX_A L"%02d", index + 1);
//AutoWide aw(((NAVMNGR*)hNav)->pConfig->ReadString(mlview, ""), CP_UTF8);
data = ((NAVMNGR*)hNav)->pConfig->ReadString(mlview, L"");//(LPCWSTR)aw;
if (data && *data)
{
len = lstrlenW(data);
if (len > 4 && len < 4096)
{
while (len > 0 && data[len-1] != L',') len--;
if (len)
{
((NAVMNGR*)hNav)->pStates[index].nOrder = _wtoi(&data[len]);
len--;
while (len > 0 && data[len-1] != L',')len--;
if (len) ((NAVMNGR*)hNav)->pStates[index].fCollapsed = ( 0 != _wtoi(&data[len]));
if (len > 1)
{
((NAVMNGR*)hNav)->pStates[index].pszFullName = (LPWSTR)calloc(len, sizeof(wchar_t));
if (!((NAVMNGR*)hNav)->pStates[index].pszFullName) continue;
if (S_OK == StringCchCopyNW(((NAVMNGR*)hNav)->pStates[index].pszFullName, len, data, len -1))
{
((NAVMNGR*)hNav)->statesCount++;
}
}
}
}
}
}
((NAVMNGR*)hNav)->lastOrderIndex = ((NAVMNGR*)hNav)->statesCount;
return (count == ((NAVMNGR*)hNav)->statesCount);
}
static BOOL OnNavTree_Click(HNAVCTRL hNav, INT actionId, LRESULT *pResult)
{
if (hNav && ((NAVMNGR*)hNav)->fnOnItemClick)
{
HTREEITEM hTreeItem, hTreeExpand = 0;
if (ACTION_ENTER_I == actionId)
{
hTreeExpand = hTreeItem = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, (LPARAM)0L);
}
else
{
hTreeItem = TreeItemFromCursor(hNav, &hTreeExpand);
}
if (hTreeExpand || ((ACTION_DBLCLICKL_I == actionId) && hTreeItem && !hTreeExpand))
{
if (ACTION_CLICKL_I == actionId || (ACTION_DBLCLICKL_I == actionId && hTreeItem && !hTreeExpand))
{
if (ACTION_DBLCLICKL_I == actionId) hTreeExpand = hTreeItem;
hTreeItem = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, (LPARAM)0L);
while (hTreeItem)
{
hTreeItem = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_PARENT, (LPARAM)hTreeItem);
if (hTreeItem == hTreeExpand) break;
}
if (hTreeItem == hTreeExpand &&
(TVIS_EXPANDED == (TVIS_EXPANDED & SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETITEMSTATE, (WPARAM)hTreeExpand, (LPARAM)TVIS_EXPANDED))))
{
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SELECTITEM, (WPARAM)TVGN_CARET, (LPARAM)hTreeExpand);
}
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_EXPAND, (WPARAM)TVE_TOGGLE, (LPARAM)hTreeExpand);
InvalidateRect(((NAVMNGR*)hNav)->hwndHost, NULL, TRUE);
if (ACTION_DBLCLICKL_I == actionId)
{
HNAVITEM hItem;
hItem = GetNavItemFromTreeItem(hNav, hTreeExpand);
if (hItem) ((NAVMNGR*)hNav)->fnOnItemClick(hNav, hItem, actionId);
}
*pResult = TRUE;
return (NULL == hTreeItem);
}
else if (ACTION_DBLCLICKL_I != actionId) hTreeItem = hTreeExpand;
}
if (hTreeItem)
{
HNAVITEM hItem;
hItem = GetNavItemFromTreeItem(hNav, hTreeItem);
if (hItem)
{
*pResult = ((NAVMNGR*)hNav)->fnOnItemClick(hNav, hItem, actionId);
return (BOOL)*pResult;
}
return FALSE;
}
}
return FALSE;
}
static BOOL OnTV_DeleteItem(HNAVCTRL hNav, TVITEMW *pItem)
{
if (pItem->lParam)
{
if (((NAVMNGR*)hNav)->fnOnItemDelete) ((NAVMNGR*)hNav)->fnOnItemDelete(hNav, (HNAVITEM)pItem->lParam);
NavItemI_SetText((HNAVITEM)pItem->lParam, NULL);
NavItemI_SetInvariantText((HNAVITEM)pItem->lParam, NULL);
free((NAVITM*)pItem->lParam);
}
return FALSE;
}
static BOOL OnTV_CustomDraw(HNAVCTRL hNav, NMTVCUSTOMDRAW *cd, LRESULT *pResult)
{
NAVMNGR *manager;
manager = (NAVMNGR*)hNav;
*pResult = CDRF_DODEFAULT;
switch (cd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
manager->drawStruct.hdc = cd->nmcd.hdc;
manager->drawInternal = 0;
if ((TVS_FULLROWSELECT & GetWindowLongPtrW(manager->hwndHost, GWL_STYLE))) manager->drawInternal |= 0x0001;
if (0x8000 & GetAsyncKeyState( GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON)) manager->drawInternal |= 0x0010;
*pResult = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
manager->drawStruct.drawStage = NIDS_PREPAINT_I;
manager->drawStruct.prc = &cd->nmcd.rc;
manager->drawStruct.iLevel = cd->iLevel;
if (CDIS_SELECTED & cd->nmcd.uItemState)
{
manager->drawStruct.itemState = NIS_SELECTED_I;
if (0 != (CDIS_FOCUS & cd->nmcd.uItemState) ||
0 != (NAVSTYLE_FOCUSED & manager->style))
{
manager->drawStruct.itemState |= NIS_FOCUSED_I;
}
}
else
{
HTREEITEM hTreeItem;
manager->drawStruct.itemState = NIS_NORMAL_I;
if (0x0010 & manager->drawInternal) TreeItemFromCursor(hNav, &hTreeItem);
else hTreeItem = NULL;
if (!hTreeItem)
{
UINT state;
state = (UINT)SendMessageW(cd->nmcd.hdr.hwndFrom, TVM_GETITEMSTATE,
(WPARAM)cd->nmcd.dwItemSpec, TVIS_DROPHILITED);
if (TVIS_DROPHILITED & state)
manager->drawStruct.itemState = NIS_DROPHILITED_I;
}
}
GetItemColors(hNav, manager->drawStruct.itemState, &cd->clrTextBk, &cd->clrText);
if (0 == (0x0001 & manager->drawInternal))
{
COLORREF rgbBk, rgbFg;
GetItemColors(hNav, NIS_NORMAL_I, &rgbBk, &rgbFg);
SetBkColor(cd->nmcd.hdc, rgbBk);
SetTextColor(cd->nmcd.hdc, rgbFg);
}
else
{
SetBkColor(cd->nmcd.hdc, cd->clrTextBk);
SetTextColor(cd->nmcd.hdc, cd->clrText);
}
if (cd->nmcd.lItemlParam)
{
NAVITM *pItem;
pItem = ((NAVITM*)cd->nmcd.lItemlParam);
if (pItem->hFont) manager->drawStruct.hFont = pItem->hFont;
else if ((NIS_BOLD_I | NIS_ITALIC_I | NIS_UNDERLINE_I) & pItem->style)
{
LOGFONTW lf = { 0 };
manager->drawStruct.hFont = (HFONT)::SendMessageW(cd->nmcd.hdr.hwndFrom, WM_GETFONT, 0, 0);
GetObjectW(manager->drawStruct.hFont, sizeof(LOGFONTW), &lf);
if (NIS_BOLD_I & pItem->style) lf.lfWeight = FW_BOLD;
if (NIS_ITALIC_I & pItem->style) lf.lfItalic = TRUE;
if (NIS_UNDERLINE_I & pItem->style) lf.lfUnderline = TRUE;
manager->drawStruct.hFont = CreateFontIndirectW(&lf);
}
else manager->drawStruct.hFont = NULL;
if (manager->drawStruct.hFont)
{
manager->hfontOld = (HFONT)SelectObject(cd->nmcd.hdc, manager->drawStruct.hFont);
*pResult |= CDRF_NEWFONT;
if (pItem->hFont != manager->drawStruct.hFont) *pResult |= CDRF_NOTIFYPOSTPAINT;
}
if((NIS_CUSTOMDRAW_I & pItem->style) && manager->fnOnCustomDraw)
{
INT result;
manager->drawStruct.clrTextBk = cd->clrTextBk;
manager->drawStruct.clrText = cd->clrText;
result = manager->fnOnCustomDraw(hNav, pItem, &manager->drawStruct, pItem->lParam);
if (NICDRF_SKIPDEFAULT_I & result)
{
SelectObject(cd->nmcd.hdc, manager->hfontOld);
DeleteObject(manager->drawStruct.hFont);
manager->drawStruct.hFont = NULL;
*pResult |= CDRF_SKIPDEFAULT;
}
if (NICDRF_NEWFONT_I & result) *pResult |= CDRF_NEWFONT;
if (NICDRF_NOTIFYPOSTPAINT_I & result)
{
pItem->style |= NIS_WANTPOSTPAINT_I;
*pResult |= CDRF_NOTIFYPOSTPAINT;
}
else pItem->style &= ~NIS_WANTPOSTPAINT_I;
}
}
break;
case CDDS_ITEMPOSTPAINT:
if(NIS_WANTPOSTPAINT_I & ((NAVITM*)cd->nmcd.lItemlParam)->style)
{
INT result;
manager->drawStruct.drawStage = NIDS_POSTPAINT_I;
result = manager->fnOnCustomDraw(hNav, (HNAVITEM)cd->nmcd.lItemlParam, &manager->drawStruct, ((NAVITM*)cd->nmcd.lItemlParam)->lParam);
if (NICDRF_SKIPDEFAULT_I & result) *pResult |= CDRF_SKIPDEFAULT;
}
if (manager->drawStruct.hFont && manager->drawStruct.hFont != ((NAVITM*)cd->nmcd.lItemlParam)->hFont)
{
SelectObject(cd->nmcd.hdc, manager->hfontOld);
DeleteObject(manager->drawStruct.hFont);
manager->drawStruct.hFont = NULL;
}
break;
}
return TRUE;
}
static BOOL OnTV_GetDispInfo(HNAVCTRL hNav, NMTVDISPINFOW *di, LRESULT *pResult)
{
BOOL handled;
NAVMNGR *manager;
manager = (NAVMNGR*)hNav;
handled = FALSE;
if((TVIF_IMAGE | TVIF_SELECTEDIMAGE) & di->item.mask)
{
if (di->item.lParam)
{
INT itemState;
COLORREF rgbBk, rgbFg;
itemState = NIS_NORMAL_I;
if (TVS_FULLROWSELECT == (TVS_FULLROWSELECT & (UINT)GetWindowLongPtrW(manager->hwndHost, GWL_STYLE)))
{
itemState = di->item.state;
if (TVIS_DROPHILITED & di->item.state)
{
if (0x8000 & GetAsyncKeyState( GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON))
{
HTREEITEM hTreeItem;
TreeItemFromCursor(hNav, &hTreeItem);
itemState = (hTreeItem) ? NIS_NORMAL_I : NIS_DROPHILITED_I;
}
else
itemState = NIS_DROPHILITED_I;
}
else if (TVIS_SELECTED & di->item.state)
{
itemState = NIS_SELECTED_I;
if (0 != ((NAVSTYLE_FOCUSED | NAVSTYLE_EDITMODE) & manager->style))
itemState |= NIS_FOCUSED_I;
}
}
GetItemColors(hNav, itemState, &rgbBk, &rgbFg);
if (TVIF_IMAGE & di->item.mask)
{
di->item.iImage = GetRealImageIndex(hNav, (NAVITM*)di->item.lParam, IMAGE_NORMAL_I, rgbBk, rgbFg);
}
if (TVIF_SELECTEDIMAGE & di->item.mask)
{
di->item.iSelectedImage = ((TVIF_IMAGE & di->item.mask) &&
((NAVITM*)(di->item.lParam))->iImage == ((NAVITM*)(di->item.lParam))->iSelectedImage) ?
di->item.iImage :
GetRealImageIndex(hNav, (NAVITM*)di->item.lParam, IMAGE_SELECTED_I, rgbBk, rgbFg);
}
handled = TRUE;
}
}
if (TVIF_CHILDREN & di->item.mask)
{
di->item.cChildren = (di->item.lParam) ? (NIS_HASCHILDREN_I & ((NAVITM*)di->item.lParam)->style) : 0;
handled = TRUE;
}
if (TVIF_TEXT & di->item.mask)
{
di->item.pszText = (di->item.lParam) ?
((NAVITM*)di->item.lParam)->pszText : WASABI_API_LNGSTRINGW(IDS_BAD_ITEM);
handled = TRUE;
}
return handled;
}
static BOOL OnTV_Click(HNAVCTRL hNav, NMHDR *pnmh, LRESULT *pResult)
{
return OnNavTree_Click(hNav, ACTION_CLICKL_I, pResult);
}
static BOOL OnTV_BeginDrag(HNAVCTRL hNav, NMTREEVIEWW *pnmtv)
{
if (hNav && ((NAVMNGR*)hNav)->fnOnBeginDrag)
{
((NAVMNGR*)hNav)->fnOnBeginDrag(hNav, (HNAVITEM)pnmtv->itemNew.lParam, pnmtv->ptDrag);
}
return FALSE;
}
static BOOL OnTV_SelectionChanged(HNAVCTRL hNav, NMTREEVIEWW *pnmtv)
{
if (hNav && ((NAVMNGR*)hNav)->fnOnItemSelected)
{
((NAVMNGR*)hNav)->fnOnItemSelected(hNav, (HNAVITEM)pnmtv->itemOld.lParam, (HNAVITEM)pnmtv->itemNew.lParam);
MLSkinnedScrollWnd_UpdateBars(((NAVMNGR*)hNav)->hwndHost, TRUE);
}
return FALSE;
}
static BOOL OnTV_RightClick(HNAVCTRL hNav, NMHDR *pnmh, LRESULT *pResult)
{
return OnNavTree_Click(hNav, ACTION_CLICKR_I, pResult);
}
static BOOL OnTV_DoubleClick(HNAVCTRL hNav, NMHDR *pnmh, LRESULT *pResult)
{
return OnNavTree_Click(hNav, ACTION_DBLCLICKL_I, pResult);
}
static BOOL OnTV_KeyDown(HNAVCTRL hNav, NMTVKEYDOWN *ptvkd, LRESULT *pResult)
{
if (VK_RETURN == ptvkd->wVKey) return OnNavTree_Click(hNav, ACTION_ENTER_I, pResult);
if (hNav && ((NAVMNGR*)hNav)->fnOnKeyDown)
{
HNAVITEM hItem;
hItem = NavCtrlI_GetSelection(hNav);
if (hItem)
{
*pResult = ((NAVMNGR*)hNav)->fnOnKeyDown(hNav, hItem, ptvkd);
return (BOOL)*pResult;
}
}
return FALSE;
}
static BOOL OnTV_BeginLabelEdit(HNAVCTRL hNav, NMTVDISPINFOW *di, LRESULT *pResult)
{
NAVMNGR *manager;
NAVITM *item;
manager = (NAVMNGR*)hNav;
if (NULL == di)
return FALSE;
item = (NAVITM*)di->item.lParam;
*pResult = TRUE;
if (NULL != item &&
0 != (NIS_ALLOWEDIT_I & item->style))
{
if (NULL == manager->fnOnBeginTitleEdit ||
FALSE != manager->fnOnBeginTitleEdit(hNav, (HNAVITEM)item))
{
HWND treeWindow, editWindow;
treeWindow = manager->hwndHost;
editWindow = (HWND)SendMessageW(treeWindow, TVM_GETEDITCONTROL, 0, 0);
if (NULL != editWindow)
SubclassEditControl(editWindow);
manager->style |= NAVSTYLE_EDITMODE;
*pResult = FALSE;
}
}
return TRUE;
}
static BOOL OnTV_EndLabelEdit(HNAVCTRL hNav, NMTVDISPINFOW *di, LRESULT *pResult)
{
NAVMNGR *manager;
manager = (NAVMNGR*)hNav;
manager->style &= ~NAVSTYLE_EDITMODE;
if (NULL != manager->fnOnEndTitleEdit &&
FALSE == manager->fnOnEndTitleEdit(hNav, (HNAVITEM)di->item.lParam, di->item.pszText))
{
*pResult = FALSE;
}
else
{
*pResult = (NULL != di->item.pszText) ?
NavItemI_SetText((HNAVITEM)di->item.lParam, di->item.pszText) :
FALSE;
}
return TRUE;
}
static BOOL OnTV_SetCursor(HNAVCTRL hNav, NMMOUSE *pm, LRESULT *pResult)
{
if (!pm->dwItemData)
{
TVHITTESTINFO hit;
if(GetCursorPos(&hit.pt))
{
HTREEITEM hTreeItem;
MapWindowPoints(HWND_DESKTOP, ((NAVMNGR*)hNav)->hwndHost, &hit.pt, 1);
hTreeItem = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_HITTEST, (WPARAM)0, (LPARAM)&hit);
if (hTreeItem) pm->dwItemData = (DWORD_PTR)GetNavItemFromTreeItem(hNav, hTreeItem);
}
}
if (pm->dwItemData)
{
if ((NIS_WANTSETCURSOR_I & ((NAVITM*)pm->dwItemData)->style) && ((NAVMNGR*)hNav)->fnOnSetCursor)
{
*pResult = ((NAVMNGR*)hNav)->fnOnSetCursor(hNav, (HNAVITEM)pm->dwItemData, ((NAVITM*)pm->dwItemData)->lParam);
}
}
return TRUE;
}
static BOOL OnTV_SetFocus(HNAVCTRL hNav, NMHDR *pnmh)
{
NAVMNGR *manager = (NAVMNGR*)hNav;
if (NULL == manager)
return FALSE;
if (0 == (NAVSTYLE_FOCUSED & manager->style))
{
manager->style |= NAVSTYLE_FOCUSED;
HNAVITEM selectedItem = NavCtrlI_GetSelection(hNav);
if (NULL != selectedItem)
NavItemI_Invalidate(selectedItem, NULL, FALSE);
}
return TRUE;
}
static BOOL OnTV_KillFocus(HNAVCTRL hNav, NMHDR *pnmh)
{
NAVMNGR *manager = (NAVMNGR*)hNav;
if (NULL == manager)
return FALSE;
if (0 != (NAVSTYLE_FOCUSED & manager->style))
{
manager->style &= ~NAVSTYLE_FOCUSED;
HNAVITEM selectedItem = NavCtrlI_GetSelection(hNav);
if (NULL != selectedItem)
NavItemI_Invalidate(selectedItem, NULL, FALSE);
}
return TRUE;
}
// manager
HNAVCTRL NavCtrlI_Create(HWND hwndParent)
{
PNAVMNGR pMngr = (PNAVMNGR)calloc(1, sizeof(NAVMNGR));
if (!pMngr) return NULL;
pMngr->hwndHost = CreateWindowExW(WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
WC_TREEVIEWW, L"",
WS_CHILD | WS_TABSTOP | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | TVS_NOHSCROLL | TVS_EDITLABELS,
0, 0, 1, 1, hwndParent, NULL, NULL, NULL);
if (!IsWindow(pMngr->hwndHost) || !SetPropW(pMngr->hwndHost, NAVMGR_HWNDPROPW, pMngr))
{
NavCtrlI_Destroy(pMngr);
return NULL;
}
pMngr->lastUsedId = NAVITEM_RANGE_MIN;
pMngr->style = NAVSTYLE_DEFAULT;
SubclassTreeView(pMngr->hwndHost); // need to be before Skinning
if (SkinWindowEx(pMngr->hwndHost, SKINNEDWND_TYPE_SCROLLWND, SWS_USESKINFONT | SWS_USESKINCOLORS))
{
MLSkinnedScrollWnd_SetMode(pMngr->hwndHost, SCROLLMODE_TREEVIEW);
HWND hTooltip = (HWND)SendMessageW(pMngr->hwndHost, TVM_GETTOOLTIPS, 0, 0L);
if (NULL != hTooltip)
{
SkinWindowEx(hTooltip, SKINNEDWND_TYPE_TOOLTIP, SWS_USESKINFONT | SWS_USESKINCOLORS);
}
}
SendMessageW(pMngr->hwndHost, (TV_FIRST + 44)/*TVM_SETEXTENDEDSTYLE*/,
(WPARAM)pMngr->hwndHost, (LPARAM)0x0004/*TVS_EX_DOUBLEBUFFER*/);
SendMessageW(pMngr->hwndHost, CCM_SETVERSION, 6, 0);
SendMessageW(pMngr->hwndHost, TVM_SETSCROLLTIME, 200, 0);
return (HNAVCTRL)pMngr;
}
BOOL NavCtrlI_SetRect(HNAVCTRL hNav, RECT *prc)
{
return (hNav && prc) ? SetWindowPos(((NAVMNGR*)hNav)->hwndHost, NULL,
prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top,
SWP_NOACTIVATE | SWP_NOZORDER) : FALSE;
}
BOOL NavCtrlI_Show(HNAVCTRL hNav, INT nCmdShow)
{
return (hNav) ? ShowWindow(((NAVMNGR*)hNav)->hwndHost, nCmdShow) : FALSE;
}
BOOL NavCtrlI_Enable(HNAVCTRL hNav, BOOL fEnable)
{
return (hNav) ? EnableWindow(((NAVMNGR*)hNav)->hwndHost, fEnable) : FALSE;
}
BOOL NavCtrlI_Destroy(HNAVCTRL hNav)
{
if (!hNav) return FALSE;
if (NULL != ((NAVMNGR*)hNav)->fnOnDestroy)
{
((NAVMNGR*)hNav)->fnOnDestroy(hNav);
}
NavCtrlI_SaveStates(hNav);
if (((NAVMNGR*)hNav)->hwndHost)
{
RemovePropW(((NAVMNGR*)hNav)->hwndHost, NAVMGR_HWNDPROPW);
DestroyWindow(((NAVMNGR*)hNav)->hwndHost);
}
NavCtrlI_DeleteStates(hNav);
free(hNav);
return TRUE;
}
BOOL NavCtrlI_Update(HNAVCTRL hNav)
{
return (hNav) ? UpdateWindow(((NAVMNGR*)hNav)->hwndHost) : FALSE;
}
C_Config *NavCtrlI_SetConfig(HNAVCTRL hNav, C_Config *pConfig)
{
C_Config *pTemp;
if (!hNav) return NULL;
pTemp = ((NAVMNGR*)hNav)->pConfig;
((NAVMNGR*)hNav)->pConfig = pConfig;
if (pConfig) NavCtrlI_LoadStates(hNav);
return pTemp;
}
HWND NavCtrlI_GetHWND(HNAVCTRL hNav)
{
return (hNav) ? ((NAVMNGR*)hNav)->hwndHost : NULL;
}
BOOL NavCtrlI_ProcessNotifications(HNAVCTRL hNav, LPNMHDR pnmh, LRESULT *pResult)
{
if (!hNav || pnmh->hwndFrom != ((PNAVMNGR)hNav)->hwndHost) return FALSE;
switch(pnmh->code)
{
case TVN_KEYDOWN: return OnTV_KeyDown(hNav, (NMTVKEYDOWN*)pnmh, pResult);
case TVN_SELCHANGEDW: return OnTV_SelectionChanged(hNav, (NMTREEVIEWW*)pnmh);
case NM_RCLICK: return OnTV_RightClick(hNav, pnmh, pResult);
case NM_DBLCLK: return OnTV_DoubleClick(hNav, pnmh, pResult);
case TVN_BEGINDRAGW: return OnTV_BeginDrag(hNav, (NMTREEVIEWW*)pnmh);
case NM_CLICK: return OnTV_Click(hNav, pnmh, pResult);
case TVN_GETDISPINFOW: return OnTV_GetDispInfo(hNav, (NMTVDISPINFOW*)pnmh, pResult);
case NM_CUSTOMDRAW: return OnTV_CustomDraw(hNav, (NMTVCUSTOMDRAW*)pnmh, pResult);
case TVN_DELETEITEMW: return OnTV_DeleteItem(hNav, &((NMTREEVIEWW*)pnmh)->itemOld);
case TVN_BEGINLABELEDITW: return OnTV_BeginLabelEdit(hNav, (NMTVDISPINFOW*)pnmh, pResult);
case TVN_ENDLABELEDITW: return OnTV_EndLabelEdit(hNav, (NMTVDISPINFOW*)pnmh, pResult);
case NM_SETCURSOR: return OnTV_SetCursor(hNav, (NMMOUSE*)pnmh, pResult);
case NM_SETFOCUS: return OnTV_SetFocus(hNav, pnmh);
case NM_KILLFOCUS: return OnTV_KillFocus(hNav, pnmh);
}
return FALSE;
}
LPVOID NavCtrlI_RegisterCallback(HNAVCTRL hNav, LPVOID fnCallback, INT cbType)
{
LPVOID temp;
if (!hNav) return NULL;
switch(cbType)
{
case CALLBACK_ONCLICK_I:
temp = ((NAVMNGR*)hNav)->fnOnItemClick;
((NAVMNGR*)hNav)->fnOnItemClick = (ONNAVITEMCLICK_I)fnCallback;
return temp;
case CALLBACK_ONSELECTED_I:
temp = ((NAVMNGR*)hNav)->fnOnItemSelected;
((NAVMNGR*)hNav)->fnOnItemSelected = (ONNAVITEMSELECTED_I)fnCallback;
return temp;
case CALLBACK_ONKEYDOWN_I:
temp = ((NAVMNGR*)hNav)->fnOnKeyDown;
((NAVMNGR*)hNav)->fnOnKeyDown = (ONNAVCTRLKEYDOWN_I)fnCallback;
return temp;
case CALLBACK_ONBEGINDRAG_I:
temp = ((NAVMNGR*)hNav)->fnOnBeginDrag;
((NAVMNGR*)hNav)->fnOnBeginDrag = (ONNAVCTRLBEGINDRAG_I)fnCallback;
return temp;
case CALLBACK_ONDESTROY_I:
temp = ((NAVMNGR*)hNav)->fnOnDestroy;
((NAVMNGR*)hNav)->fnOnDestroy = (ONNAVCTRLDESTROY_I)fnCallback;
return temp;
case CALLBACK_ONGETIMAGEINDEX_I:
temp = ((NAVMNGR*)hNav)->fnOnItemGetImageIndex;
((NAVMNGR*)hNav)->fnOnItemGetImageIndex = (ONNAVITEMGETIMAGEINDEX_I)fnCallback;
return temp;
case CALLBACK_ONBEGINTITLEEDIT_I:
temp = ((NAVMNGR*)hNav)->fnOnBeginTitleEdit;
((NAVMNGR*)hNav)->fnOnBeginTitleEdit = (ONNAVITEMBEGINTITLEEDIT_I)fnCallback;
return temp;
case CALLBACK_ONENDTITLEEDIT_I:
temp = ((NAVMNGR*)hNav)->fnOnEndTitleEdit;
((NAVMNGR*)hNav)->fnOnEndTitleEdit = (ONNAVCTRLENDTITLEEDIT_I)fnCallback;
return temp;
case CALLBACK_ONITEMDELETE_I:
temp = ((NAVMNGR*)hNav)->fnOnItemDelete;
((NAVMNGR*)hNav)->fnOnItemDelete = (ONNAVITEMDELETE_I)fnCallback;
return temp;
case CALLBACK_ONITEMDRAW_I:
temp = ((NAVMNGR*)hNav)->fnOnCustomDraw;
((NAVMNGR*)hNav)->fnOnCustomDraw = (ONNAVITEMDRAW_I)fnCallback;
return temp;
case CALLBACK_ONSETCURSOR_I:
temp = ((NAVMNGR*)hNav)->fnOnSetCursor;
((NAVMNGR*)hNav)->fnOnSetCursor = (ONNAVITEMSETCURSOR_I)fnCallback;
return temp;
case CALLBACK_ONHITTEST_I:
temp = ((NAVMNGR*)hNav)->fnOnHitTest;
((NAVMNGR*)hNav)->fnOnHitTest = (ONNAVITEMHITTEST_I)fnCallback;
return temp;
}
return NULL;
}
BOOL NavCtrlI_UpdateLook(HNAVCTRL hNav)
{
INT minHeight;
if (!hNav || !((NAVMNGR*)hNav)->hwndHost) return FALSE;
minHeight = -1;
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SETBKCOLOR, (WPARAM)0, (LPARAM)WADlg_getColor(WADLG_ITEMBG));
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SETTEXTCOLOR, (WPARAM)0, (LPARAM)WADlg_getColor(WADLG_ITEMFG));
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SETINSERTMARKCOLOR, (WPARAM)0, (LPARAM)WADlg_getColor(WADLG_ITEMFG));
MLSkinnedWnd_SkinChanged(((NAVMNGR*)hNav)->hwndHost, FALSE, FALSE);
HFONT hFont = (HFONT)SendMessageW(((NAVMNGR*)hNav)->hwndHost, WM_GETFONT, 0, 0L);
HDC hdc;
hdc = GetDCEx(((NAVMNGR*)hNav)->hwndHost, NULL, DCX_CACHE);
if (hdc)
{
if (NULL == hFont)
hFont = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
TEXTMETRICW tm;
if (hFont)
{
HFONT hfntOld = (HFONT)SelectObject(hdc, hFont);
if (GetTextMetricsW(hdc, &tm)) minHeight = tm.tmHeight + 2/*Borders*/;
SelectObject(hdc, hfntOld);
}
ReleaseDC(((NAVMNGR*)hNav)->hwndHost, hdc);
}
if (((NAVMNGR*)hNav)->pConfig)
{
BOOL fFullRowSelect;
DWORD dwWndStyle;
INT height;
height = ((NAVMNGR*)hNav)->pConfig->ReadInt(L"Navigation_ItemHeight", 18);
if (minHeight > 0 && height < minHeight) height = minHeight;
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SETITEMHEIGHT, (WPARAM)height, (LPARAM)0);
((NAVMNGR*)hNav)->style = (((NAVMNGR*)hNav)->style & ~NAVSTYLE_MOUSEDOWNSELECT) | ((0 != ((NAVMNGR*)hNav)->pConfig->ReadInt(L"Navigation_MouseDownSel", 0)) ? NAVSTYLE_MOUSEDOWNSELECT : 0);
fFullRowSelect = (((NAVMNGR*)hNav)->pConfig->ReadInt(L"Navigation_FullRowSel", 1) != 0);
dwWndStyle = (DWORD)GetWindowLongPtrW(((NAVMNGR*)hNav)->hwndHost, GWL_STYLE);
if (fFullRowSelect != (TVS_FULLROWSELECT == (TVS_FULLROWSELECT & dwWndStyle)))
{
SetWindowLongPtrW(((NAVMNGR*)hNav)->hwndHost, GWL_STYLE,
(dwWndStyle & ~TVS_FULLROWSELECT) | ((fFullRowSelect) ? TVS_FULLROWSELECT : 0));
}
NavCtrlI_SetImageList(hNav, ((NAVMNGR*)hNav)->hmlilImages);
}
return TRUE;
}
HMLIMGLST NavCtrlI_SetImageList(HNAVCTRL hNav, HMLIMGLST hmlil)
{
HMLIMGLST hmlilOld;
HIMAGELIST hilTree, hilNew;
if (!hNav) return NULL;
hmlilOld = ((NAVMNGR*)hNav)->hmlilImages;
((NAVMNGR*)hNav)->hmlilImages = hmlil;
hilNew = MLImageListI_GetRealList(hmlil);
hilTree = (HIMAGELIST)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)0);
if (!((NAVMNGR*)hNav)->pConfig || ((NAVMNGR*)hNav)->pConfig->ReadInt(L"Navigation_ShowIcons", 1))
{
if (hilTree != hilNew) SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)hilNew);
}
else if (hilTree) SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)NULL);
return hmlilOld;
}
HMLIMGLST NavCtrlI_GetImageList(HNAVCTRL hNav)
{
return (hNav) ? ((NAVMNGR*)hNav)->hmlilImages : NULL;
}
HNAVITEM NavCtrlI_FindItem(HNAVCTRL hNav, INT itemId)
{
return (hNav) ? FindNavItemByNavIdEx(((NAVMNGR*)hNav)->hwndHost, itemId, TVI_ROOT) : NULL;
}
HNAVITEM NavCtrlI_FindItemByName(HNAVCTRL hNav, LCID Locale, UINT compFlags, LPCWSTR pszName, INT cchLength)
{
TREEITEMSEARCH search;
if (!hNav || !pszName || !((NAVMNGR*)hNav)->hwndHost) return NULL;
search.fFound = FALSE;
search.itemData = (INT_PTR)pszName;
search.item.mask = TVIF_PARAM;
search.flags = compFlags;
// pack extra info
search.item.cchTextMax = cchLength;
search.item.state = Locale;
EnumerateTreeItems(((NAVMNGR*)hNav)->hwndHost, TVI_ROOT, FindTreeItemByNameCB, &search);
return (search.fFound) ? (HNAVITEM)search.item.lParam : NULL;
}
HNAVITEM NavCtrlI_FindItemByFullName(HNAVCTRL hNav, LCID Locale, UINT compFlags, LPCWSTR pszFullName, INT cchLength, BOOL fAncestorOk)
{
INT len, separatorCount;
WCHAR shortname[ITEM_SHORTNAME_MAX] = {0};
LPCWSTR end;
TVITEMW treeItem;
HNAVITEM hNavParent;
if (!hNav || !pszFullName || !((NAVMNGR*)hNav)->hwndHost) return NULL;
hNavParent = NULL;
len = (cchLength < 0)? lstrlenW(pszFullName) : cchLength;
if (!len) return NULL;
end = pszFullName + len;
ZeroMemory(&treeItem, sizeof(TVITEMW));
treeItem.mask = TVIF_PARAM;
len = 0;
separatorCount = 0;
while (pszFullName != end + 1)
{
if (pszFullName == end) { separatorCount++; }
if (SEPARATOR == *pszFullName) separatorCount++;
else
{
if (separatorCount)
{
INT i;
for (i = separatorCount/2; i > 0; i--)
{
if (len == ITEM_SHORTNAME_MAX -1) return NULL; // ugh...
shortname[len++] = SEPARATOR;
}
if (separatorCount%2 && len)
{
if (CSTR_EQUAL != CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, EMPTY_ITEM_NAME, -1, shortname, len))
{
treeItem.hItem = (HTREEITEM)((NULL == hNavParent) ?
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_ROOT, (LPARAM)0) :
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)((NAVITM*)hNavParent)->hTreeItem));
while(treeItem.hItem)
{
if (SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETITEMW, (WPARAM)0, (LPARAM)&treeItem))
{
if (CSTR_EQUAL == CompareItemName(Locale, compFlags, shortname, len, (HNAVITEM)treeItem.lParam))
{ // found!!!
if (pszFullName == end) return (HNAVITEM)treeItem.lParam;
break;
}
}
treeItem.hItem = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)treeItem.hItem);
}
if (treeItem.hItem)
{
hNavParent = (HNAVITEM)treeItem.lParam;
if (!hNavParent) return NULL; // thats bad
}
else return (fAncestorOk) ? hNavParent : NULL;
}
len = 0;
}
separatorCount = 0;
}
if (len == ITEM_SHORTNAME_MAX -1) return NULL; // ugh...
shortname[len++] = *pszFullName;
}
pszFullName++;
}
return NULL;
}
HNAVITEM NavCtrlI_InsertItem(HNAVCTRL hNav, HNAVITEM hInsertAfter, HNAVITEM hParent, NAVITEM_I *pnis)
{
TVINSERTSTRUCTW is = {0};
NAVITM *pNavItem = 0;
HTREEITEM hItem = 0;
if (!pnis) return NULL;
if (NIMF_ITEMID_I & pnis->mask) { if (NavCtrlI_FindItem(hNav, pnis->id)) return NULL; }
else pnis->id = GetNextFreeItemId(hNav);
if (!pnis->id) return NULL;
pNavItem = (NAVITM*)calloc(1, sizeof(NAVITM));
if (!pNavItem) return NULL;
is.hParent = (hParent) ? ((NAVITM*)hParent)->hTreeItem : TVI_ROOT;
is.hInsertAfter = TVI_LAST;
if (NCI_LAST_I == hInsertAfter) is.hInsertAfter = TVI_LAST;
else if (NCI_FIRST_I == hInsertAfter) is.hInsertAfter = TVI_FIRST;
else if (hInsertAfter && !IS_NAVITEMSORTORDER(hInsertAfter)) is.hInsertAfter = ((NAVITM*)hInsertAfter)->hTreeItem;
if (is.hInsertAfter == is.hParent) is.hInsertAfter = TVI_FIRST;
pNavItem->id = pnis->id;
pNavItem->hwndTree = ((NAVMNGR*)hNav)->hwndHost;
is.item.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_TEXT;
is.item.lParam = (LPARAM)pNavItem;
is.item.pszText = LPSTR_TEXTCALLBACKW;
is.item.iImage = I_IMAGECALLBACK;
is.item.iSelectedImage = I_IMAGECALLBACK;
is.item.cChildren = I_CHILDRENCALLBACK;
if (NIMF_STYLE_I & pnis->mask) NavItemI_SetStyle(pNavItem, pnis->style, pnis->styleMask);
if (NIMF_TEXT_I & pnis->mask) NavItemI_SetText(pNavItem, pnis->pszText);
if (NIMF_TEXTINVARIANT_I & pnis->mask) NavItemI_SetInvariantText(pNavItem, pnis->pszInvariant);
if (NIMF_FONT_I & pnis->mask) NavItemI_SetFont(pNavItem, pnis->hFont);
if (NIMF_PARAM_I & pnis->mask) pNavItem->lParam = pnis->lParam;
NavItemI_SetImageIndex(pNavItem, (NIMF_IMAGE_I & pnis->mask) ? pnis->iImage : -1, IMAGE_NORMAL_I);
NavItemI_SetImageIndex(pNavItem, (NIMF_IMAGESEL_I & pnis->mask) ? pnis->iSelectedImage : -1, IMAGE_SELECTED_I);
NavCtrlI_BeginUpdate(hNav, NUF_LOCK_SELECTED_I);
hItem = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_INSERTITEMW, (WPARAM)0, (LPARAM)&is);
if (hItem)
{
UINT state, stateMask;
NAVITEMSTATEREC *pRec;
BOOL itemRecSearched;
WORD order;
UINT flags;
pNavItem->hTreeItem = hItem;
itemRecSearched = FALSE;
order = (WORD)-1;
flags = NOF_MOVEAFTER_I;
if (hInsertAfter)
{
if (IS_NAVITEMSORTORDER(hInsertAfter)) { order = (WORD)hInsertAfter; flags = NOF_MOVEONEAFTER_I; }
else
{
HTREEITEM hTreePrev;
hTreePrev = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_PREVIOUS, (LPARAM)hItem);
if (!hTreePrev) { order = 1; flags = NOF_MOVEONEBEFORE_I; }
else
{
HNAVITEM hPrev;
hPrev = GetNavItemFromTreeItem(hNav, hTreePrev);
order = (hPrev) ? ((NAVITM*)hPrev)->sortOrder : (WORD)-1;
flags = NOF_MOVEONEAFTER_I;
}
}
}
else
{
if (TVI_ROOT == is.hParent || !is.hParent)
{
pRec = NavCtrlI_FindItemStateRec(hNav, pNavItem, TRUE);
order = (pRec) ? pRec->nOrder : ++((NAVMNGR*)hNav)->lastOrderIndex;
flags = NOF_MOVEAFTER_I;
itemRecSearched = TRUE;
}
}
NavItemI_SetOrder(pNavItem, order, flags);
if (NIMF_STATE_I & pnis->mask)
{
state = pnis->state;
stateMask = pnis->stateMask;
}
else
{
state = 0;
stateMask = 0;
}
if (0 == (NIS_EXPANDED_I & stateMask))
{
if (!itemRecSearched) pRec = NavCtrlI_FindItemStateRec(hNav, pNavItem, TRUE);
state |= (pRec && pRec->fCollapsed) ? 0 : NIS_EXPANDED_I;
stateMask |= NIS_EXPANDED_I;
}
NavItemI_SetState(pNavItem, state, stateMask);
}
else
{
NavItemI_SetText(pNavItem, NULL);
NavItemI_SetInvariantText(pNavItem, NULL);
free(pNavItem);
pNavItem = NULL;
}
NavCtrlI_EndUpdate(hNav);
return (HNAVITEM)pNavItem;
}
BOOL NavCtrlI_DeleteItem(HNAVCTRL hNav, HNAVITEM hItem)
{
return (hNav && hItem) ? (BOOL)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_DELETEITEM, 0, (LPARAM)((NAVITM*)hItem)->hTreeItem) : FALSE;
}
BOOL NavCtrlI_DeleteAll(HNAVCTRL hNav)
{
return (hNav) ? (BOOL)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT) : FALSE;
}
HNAVITEM NavCtrlI_GetRoot(HNAVCTRL hNav)
{
HTREEITEM hTreeChild;
if (!hNav) return NULL;
hTreeChild = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_ROOT, (LPARAM)0L);
return (hTreeChild) ? GetNavItemFromTreeItem(hNav, hTreeChild) : NULL;
}
HNAVITEM NavCtrlI_GetSelection(HNAVCTRL hNav)
{
HTREEITEM hTreeChild;
if (!hNav) return NULL;
hTreeChild = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_CARET, (LPARAM)0L);
return (hTreeChild) ? GetNavItemFromTreeItem(hNav, hTreeChild) : NULL;
}
HNAVITEM NavCtrlI_GetFirstVisible(HNAVCTRL hNav)
{
HTREEITEM hTreeChild;
if (!hNav) return NULL;
hTreeChild = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_FIRSTVISIBLE, (LPARAM)0L);
return (hTreeChild) ? GetNavItemFromTreeItem(hNav, hTreeChild) : NULL;
}
HNAVITEM NavCtrlI_GetLastVisible(HNAVCTRL hNav)
{
HTREEITEM hTreeChild;
if (!hNav) return NULL;
hTreeChild = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, (WPARAM)TVGN_LASTVISIBLE, (LPARAM)0L);
return (hTreeChild) ? GetNavItemFromTreeItem(hNav, hTreeChild) : NULL;
}
HNAVITEM NavCtrlI_HitTest(HNAVCTRL hNav, POINT *ppt, UINT *pFlags)
{
TVHITTESTINFO tvhi;
HNAVITEM hItem;
if (!hNav || !((NAVMNGR*)hNav)->hwndHost || !ppt)
{
if (pFlags) *pFlags = NAVHT_NOWHERE_I;
return NULL;
}
tvhi.pt = *ppt;
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_HITTEST, (WPARAM)0, (LPARAM)&tvhi);
hItem = (tvhi.hItem) ? GetNavItemFromTreeItem(hNav, tvhi.hItem) : NULL;
PerformCustomHitTest(hNav, tvhi.pt, &tvhi.flags, (hItem) ? &hItem : NULL);
if (pFlags) *pFlags = tvhi.flags;
return hItem;
}
BOOL NavCtrlI_SetInsertMark(HNAVCTRL hNav, HNAVITEM hItem, BOOL fAfter)
{
return (hNav) ? (BOOL)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SETINSERTMARK,
(WPARAM)fAfter,
(hItem) ? (LPARAM)((NAVITM*)hItem)->hTreeItem : NULL) : FALSE;
}
BOOL NavCtrlI_EnumItems(HNAVCTRL hNav, NAVENUMPROC_I pEnumFunc, HNAVITEM hItemStart, LPARAM lParam)
{
NAVENUMSTRUCT navenum;
if (!hNav || !pEnumFunc) return FALSE;
navenum.hNav = hNav;
navenum.callback = pEnumFunc;
navenum.lParam = lParam;
navenum.item.mask = TVIF_PARAM;
return EnumerateTreeItems(((NAVMNGR*)hNav)->hwndHost, (hItemStart) ? ((NAVITM*)hItemStart)->hTreeItem : TVI_ROOT, EnumNavItemCB, &navenum);
}
INT NavCtrlI_BeginUpdate(HNAVCTRL hNav, UINT fRememberPos)
{
if (!hNav || !((NAVMNGR*)hNav)->hwndHost || !IsWindow(((NAVMNGR*)hNav)->hwndHost)) return -1;
if (!((NAVMNGR*)hNav)->lockUpdate)
{
((NAVMNGR*)hNav)->lockFirst = NULL;
((NAVMNGR*)hNav)->lockSelected = NULL;
if (fRememberPos)
{
((NAVMNGR*)hNav)->lockFirst = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, (LPARAM)TVI_ROOT);
if (NUF_LOCK_SELECTED_I & fRememberPos)
{
((NAVMNGR*)hNav)->lockSelected = (HTREEITEM)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETNEXTITEM, TVGN_CARET, (LPARAM)TVI_ROOT);
if (((NAVMNGR*)hNav)->lockSelected)
{
RECT rc;
*(HTREEITEM*)&rc = ((NAVMNGR*)hNav)->lockSelected;
if (!SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETITEMRECT, FALSE, (LPARAM)&rc)) ((NAVMNGR*)hNav)->lockSelected = NULL;
else ((NAVMNGR*)hNav)->lockSelPos = rc.top;
}
}
}
UpdateWindow(((NAVMNGR*)hNav)->hwndHost);
SendMessageW(((NAVMNGR*)hNav)->hwndHost, WM_SETREDRAW, (WPARAM)FALSE, 0L);
}
return ++((NAVMNGR*)hNav)->lockUpdate;
}
INT NavCtrlI_EndUpdate(HNAVCTRL hNav)
{
if (!hNav || !((NAVMNGR*)hNav)->hwndHost || !IsWindow(((NAVMNGR*)hNav)->hwndHost)) return -1;
if (((NAVMNGR*)hNav)->lockUpdate)
{
((NAVMNGR*)hNav)->lockUpdate--;
if (!((NAVMNGR*)hNav)->lockUpdate)
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS | SIF_RANGE;
if (((NAVMNGR*)hNav)->lockSelected)
{
RECT rc;
*(HTREEITEM*)&rc = ((NAVMNGR*)hNav)->lockSelected;
if (!SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETITEMRECT, FALSE, (LPARAM)&rc))
{
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_SELECTITEM, (WPARAM)TVGN_FIRSTVISIBLE, (LPARAM)((NAVMNGR*)hNav)->lockSelected);
}
else if (((NAVMNGR*)hNav)->lockSelPos != rc.top)
{
INT iHeight = (INT)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETITEMHEIGHT , 0, 0L);
if (iHeight)
{
INT pos, oldPos;
if (((NAVMNGR*)hNav)->lockSelPos > rc.top) iHeight = 0 - iHeight;
WPARAM wCmd = MAKEWPARAM((((NAVMNGR*)hNav)->lockSelPos > rc.top) ? SB_LINEUP : SB_LINEDOWN, 0);
oldPos = 0xFFFFFF;
for(pos = ((NAVMNGR*)hNav)->lockSelPos; pos != rc.top; pos += iHeight)
{
if (ABS((oldPos - rc.top)) <= ABS((pos - rc.top))) break;
oldPos = pos;
SendMessageW(((NAVMNGR*)hNav)->hwndHost, WM_VSCROLL, wCmd, 0L);
SendMessageW(((NAVMNGR*)hNav)->hwndHost, WM_VSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0), 0L);
}
}
}
}
else if (((NAVMNGR*)hNav)->lockFirst)
{
SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_ENSUREVISIBLE, (WPARAM)0, (LPARAM)((NAVMNGR*)hNav)->lockFirst);
}
((NAVMNGR*)hNav)->lockFirst = NULL;
((NAVMNGR*)hNav)->lockSelected = NULL;
if(GetScrollInfo(((NAVMNGR*)hNav)->hwndHost, SB_HORZ, &si) && (si.nMin != si.nPos))
{
SendMessageW(((NAVMNGR*)hNav)->hwndHost, WM_HSCROLL, MAKEWPARAM(SB_LEFT, 0), NULL);
SendMessageW(((NAVMNGR*)hNav)->hwndHost, WM_HSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0), NULL);
}
SendMessageW(((NAVMNGR*)hNav)->hwndHost, WM_SETREDRAW, (WPARAM)TRUE, 0L);
}
}
return ((NAVMNGR*)hNav)->lockUpdate;
}
INT NavCtrlI_MapPointsTo(HNAVCTRL hNav, HWND hwndTo, POINT *ppt, UINT cPoints)
{
return (hNav) ? MapWindowPoints(((NAVMNGR*)hNav)->hwndHost, hwndTo, ppt, cPoints) : 0;
}
INT NavCtrlI_MapPointsFrom(HNAVCTRL hNav, HWND hwndFrom, POINT *ppt, UINT cPoints)
{
return (hNav) ? MapWindowPoints(hwndFrom, ((NAVMNGR*)hNav)->hwndHost, ppt, cPoints) : 0;
}
BOOL NavCtrlI_EndEditTitle(HNAVCTRL hNav, BOOL fCancel)
{
return (hNav) ? (BOOL)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_ENDEDITLABELNOW, (WPARAM)fCancel, 0L) : FALSE;
}
INT NavCtrlI_GetIndent(HNAVCTRL hNav)
{
return (hNav) ? (BOOL)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETINDENT, (WPARAM)0, 0L) : 0;
}
DWORD NavCtrlI_GetStyle(HNAVCTRL hNav)
{
DWORD style;
style = NCS_NORMAL_I;
if (hNav)
{
if (TVS_FULLROWSELECT == (TVS_FULLROWSELECT & (DWORD)GetWindowLongPtrW(((NAVMNGR*)hNav)->hwndHost, GWL_STYLE)))
style |= NCS_FULLROWSELECT_I;
if (NULL != (HIMAGELIST)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)0))
style |= NCS_SHOWICONS_I;
}
return style;
}
BOOL NavItemI_EditTitle(HNAVITEM hItem)
{
NAVITM *item;
HWND editWindow;
if (NULL == hItem)
return FALSE;
item = (NAVITM*)hItem;
if (0 == (NIS_ALLOWEDIT_I & item->style))
return FALSE;
SendMessageW(item->hwndTree, TVM_ENSUREVISIBLE, 0, (LPARAM)item->hTreeItem);
editWindow = (HWND)SendMessageW(item->hwndTree, TVM_EDITLABELW, 0, (LPARAM)item->hTreeItem);
return (NULL != editWindow);
}
INT NavItemI_GetId(HNAVITEM hItem)
{
return (hItem) ? ((NAVITM*)hItem)->id : 0;
}
HNAVITEM NavItemI_GetChild(HNAVITEM hItem)
{
return NavItemI_GetNextEx(hItem, TVGN_CHILD);
}
HNAVITEM NavItemI_GetNext(HNAVITEM hItem)
{
return NavItemI_GetNextEx(hItem, TVGN_NEXT);
}
HNAVITEM NavItemI_GetRoot(HNAVITEM hItem)
{
return NavItemI_GetNextEx(hItem, TVGN_ROOT);
}
HNAVITEM NavItemI_GetParent(HNAVITEM hItem)
{
return NavItemI_GetNextEx(hItem, TVGN_PARENT);
}
HNAVITEM NavItemI_GetPrevious(HNAVITEM hItem)
{
return NavItemI_GetNextEx(hItem, TVGN_PREVIOUS);
}
INT NavItemI_GetChildrenCount(HNAVITEM hItem)
{
HTREEITEM hChild;
int counter;
if (!hItem) return -1;
hChild = (HTREEITEM)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)((NAVITM*)hItem)->hTreeItem);
if (!hChild) return 0;
counter = 1;
while(NULL != (hChild = (HTREEITEM)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)hChild))) counter++;
return counter;
}
BOOL NavItemI_IsExpanded(HNAVITEM hItem)
{
return (hItem && (TVIS_EXPANDED == (TVIS_EXPANDED & (UINT)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETITEMSTATE,
(WPARAM)((NAVITM*)hItem)->hTreeItem, (LPARAM)TVIS_EXPANDED))));
}
INT NavItemI_GetImageIndex(HNAVITEM hItem, INT imageType)
{
NAVITM *item;
item = (NAVITM*)hItem;
if (NULL == item)
return -1;
if (0 != (NIS_DEFAULTIMAGE & item->style))
return -1;
switch(imageType)
{
case IMAGE_NORMAL_I: return ((NAVITM*)hItem)->iImage;
case IMAGE_SELECTED_I: return ((NAVITM*)hItem)->iSelectedImage;
}
return -1;
}
BOOL NavItemI_GetIndirect(HNAVITEM hItem, NAVITEM_I *pnis)
{
NAVITM *pItem;
if (!hItem || !pnis) return FALSE;
pItem = (NAVITM*)hItem;
if (NIMF_ITEMID_I & pnis->mask) pnis->id = pItem->id;
if (NIMF_IMAGE_I & pnis->mask) pnis->iImage = pItem->iImage;
if (NIMF_IMAGESEL_I & pnis->mask) pnis->iSelectedImage = pItem->iSelectedImage;
if (NIMF_STYLE_I & pnis->mask) pnis->style = (pnis->styleMask & pItem->style);
if (NIMF_TEXT_I & pnis->mask && !NavItemI_GetText(pItem, pnis->pszText, pnis->cchTextMax)) return FALSE;
if (NIMF_TEXTINVARIANT_I & pnis->mask && !NavItemI_GetInvariantText(pItem, pnis->pszInvariant, pnis->cchInvariantMax)) return FALSE;
if (NIMF_STATE_I & pnis->mask) pnis->state = NavItemI_GetState(pItem, 0xFFFFFFFF);
if (NIMF_FONT_I & pnis->mask) pnis->hFont = NavItemI_GetFont(pItem);
if (NIMF_PARAM_I & pnis->mask) pnis->lParam = pItem->lParam;
return TRUE;
}
BOOL NavItemI_GetText(HNAVITEM hItem, LPWSTR pszText, INT cchMaxLen)
{
if (!hItem || !pszText) return FALSE;
return (S_OK == StringCchCopyW(pszText, cchMaxLen, (((NAVITM*)hItem)->pszText) ? ((NAVITM*)hItem)->pszText : L""));
}
BOOL NavItemI_GetInvariantText(HNAVITEM hItem, LPWSTR pszText, INT cchMaxLen)
{
if (!hItem || !pszText) return FALSE;
return (S_OK == StringCchCopyW(pszText, cchMaxLen, (((NAVITM*)hItem)->pszInvariant) ? ((NAVITM*)hItem)->pszInvariant : L""));
}
BOOL NavItemI_HasChildren(HNAVITEM hItem)
{
return (hItem && (0 != (NIS_HASCHILDREN_I & ((NAVITM*)hItem)->style)));
}
BOOL NavItemI_HasChildrenReal(HNAVITEM hItem)
{
return (hItem && SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)((NAVITM*)hItem)->hTreeItem));
}
BOOL NavItemI_IsSelected(HNAVITEM hItem)
{
return (NIS_SELECTED_I == NavItemI_GetState(hItem, NIS_SELECTED_I));
}
BOOL NavItemI_SetId(HNAVITEM hItem, INT itemId)
{
if (!hItem || itemId < 0) return FALSE;
if (((NAVITM*)hItem)->id == itemId) return TRUE;
if (FindNavItemByNavIdEx(((NAVITM*)hItem)->hwndTree, itemId, TVI_ROOT)) return FALSE;
((NAVITM*)hItem)->id = itemId;
return TRUE;
}
BOOL NavItemI_SetImageIndex(HNAVITEM hItem, INT mlilIndex, INT imageType)
{
if (!hItem) return FALSE;
switch(imageType)
{
case IMAGE_NORMAL_I: ((NAVITM*)hItem)->iImage = mlilIndex; break;
case IMAGE_SELECTED_I: ((NAVITM*)hItem)->iSelectedImage = mlilIndex; break;
default: return FALSE;
}
NavItemI_Invalidate(hItem, NULL, FALSE);
return TRUE;
}
BOOL NavItemI_SetStyle(HNAVITEM hItem, UINT style, UINT mask)
{
UINT newStyle;
if (!hItem) return FALSE;
newStyle = (((NAVITM*)hItem)->style & ~mask) | style;
if (((NAVITM*)hItem)->style != newStyle)
{
((NAVITM*)hItem)->style = newStyle;
NavItemI_Invalidate(hItem, NULL, FALSE);
}
return TRUE;
}
BOOL NavItemI_SetText(HNAVITEM hItem, LPCWSTR pszText)
{
if (!hItem) return FALSE;
if (!pszText)
{
free(((NAVITM*)hItem)->pszText);
((NAVITM*)hItem)->pszText = NULL;
((NAVITM*)hItem)->cchTextMax = 0;
}
else
{
INT len = lstrlenW(pszText);
if (len >= ((NAVITM*)hItem)->cchTextMax)
{
LPVOID data;
data = realloc(((NAVITM*)hItem)->pszText, sizeof(WCHAR)*(len + 4));
if (!data) return FALSE;
((NAVITM*)hItem)->pszText = (LPWSTR)data;
((NAVITM*)hItem)->cchTextMax = len + 4;
}
if (S_OK != StringCchCopyW(((NAVITM*)hItem)->pszText, ((NAVITM*)hItem)->cchTextMax, pszText)) return FALSE;
}
NavItemI_Invalidate(hItem, NULL, FALSE);
return TRUE;
}
BOOL NavItemI_SetInvariantText(HNAVITEM hItem, LPCWSTR pszText)
{
if (!hItem) return FALSE;
if (!pszText)
{
free(((NAVITM*)hItem)->pszInvariant);
((NAVITM*)hItem)->pszInvariant = NULL;
((NAVITM*)hItem)->cchInvariantMax = 0;
}
else
{
INT len = lstrlenW(pszText);
if (len >= ((NAVITM*)hItem)->cchInvariantMax)
{
LPVOID data;
data = realloc(((NAVITM*)hItem)->pszInvariant, sizeof(WCHAR)*(len + 4));
if (!data) return FALSE;
((NAVITM*)hItem)->pszInvariant = (LPWSTR)data;
((NAVITM*)hItem)->cchInvariantMax = len + 4;
}
if (S_OK != StringCchCopyW(((NAVITM*)hItem)->pszInvariant, ((NAVITM*)hItem)->cchInvariantMax, pszText)) return FALSE;
}
return TRUE;
}
BOOL NavItemI_SetState(HNAVITEM hItem, UINT state, UINT stateMask)
{
TVITEMW item;
if (!hItem) return FALSE;
item.hItem = ((NAVITM*)hItem)->hTreeItem;
item.mask = TVIF_STATE;
item.state = 0;
item.stateMask = 0;
switch(state)
{
case NIS_SELECTED_I: item.state |= TVIS_SELECTED; break;
case NIS_EXPANDED_I: item.state |= TVIS_EXPANDED; break;
case NIS_DROPHILITED_I: item.state |= TVIS_DROPHILITED; break;
}
switch(stateMask)
{
case NIS_SELECTED_I: item.stateMask |= TVIS_SELECTED; break;
case NIS_EXPANDED_I: item.stateMask |= TVIS_EXPANDED; break;
case NIS_DROPHILITED_I: item.stateMask |= TVIS_DROPHILITED; break;
}
return (BOOL)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_SETITEMW, (WPARAM)0, (LPARAM)&item);
}
UINT NavItemI_GetState(HNAVITEM hItem, UINT stateMask)
{
UINT treeState, navState;
if (!hItem) return 0;
treeState = (UINT)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETITEMSTATE, (WPARAM)((NAVITM*)hItem)->hTreeItem, (LPARAM)0xFFFFFFFF);
navState = 0;
if (TVIS_SELECTED & treeState) navState |= NIS_SELECTED_I;
if (TVIS_EXPANDED & treeState) navState |= NIS_EXPANDED_I;
if (TVIS_DROPHILITED & treeState) navState |= NIS_DROPHILITED_I;
return (navState & stateMask);
}
UINT NavItemI_GetStyle(HNAVITEM hItem, UINT styleMask)
{
return (hItem) ? (((NAVITM*)hItem)->style & styleMask) : 0;
}
BOOL NavItemI_SetIndirect(HNAVITEM hItem, NAVITEM_I *pnis)
{
if (!hItem || !pnis) return FALSE;
BOOL fResult = TRUE;
((NAVITM*)hItem)->fBlockInvalid = TRUE;
if (NIMF_ITEMID_I & pnis->mask && !NavItemI_SetId(hItem, pnis->id)) fResult = FALSE;
if (NIMF_IMAGE_I & pnis->mask && !NavItemI_SetImageIndex(hItem, pnis->iImage, IMAGE_NORMAL_I)) fResult = FALSE;
if (NIMF_IMAGESEL_I & pnis->mask && !NavItemI_SetImageIndex(hItem, pnis->iSelectedImage, IMAGE_SELECTED_I)) fResult = FALSE;
if (NIMF_STYLE_I & pnis->mask && !NavItemI_SetStyle(hItem, pnis->style, pnis->styleMask)) fResult = FALSE;
if (NIMF_TEXT_I & pnis->mask && !NavItemI_SetText(hItem, pnis->pszText)) fResult = FALSE;
if (NIMF_TEXTINVARIANT_I & pnis->mask && !NavItemI_SetText(hItem, pnis->pszInvariant)) fResult = FALSE;
if (NIMF_STATE_I & pnis->mask && !NavItemI_SetState(hItem, pnis->state, pnis->stateMask)) fResult = FALSE;
if (NIMF_FONT_I & pnis->mask && !NavItemI_SetFont(hItem, pnis->hFont)) fResult = FALSE;
if (NIMF_PARAM_I & pnis->mask) ((NAVITM*)hItem)->lParam = pnis->lParam;
((NAVITM*)hItem)->fBlockInvalid = FALSE;
if (!NavItemI_Invalidate(hItem, NULL, FALSE)) fResult = FALSE;
return fResult;
}
BOOL NavItemI_GetRect(HNAVITEM hItem, RECT *prc, BOOL fItemRect)
{
if (!hItem || !prc) return FALSE;
*((HTREEITEM*)prc) = ((NAVITM*)hItem)->hTreeItem;
return (BOOL)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETITEMRECT, (WPARAM)fItemRect, (LPARAM)prc);
}
BOOL NavItemI_Invalidate(HNAVITEM hItem, RECT *prc, BOOL fErase)
{
if (!hItem) return FALSE;
if (!((NAVITM*)hItem)->fBlockInvalid)
{
RECT rc;
if (NavItemI_GetRect(hItem, &rc, FALSE))
{
if (prc) IntersectRect(&rc, &rc, prc);
InvalidateRect(((NAVITM*)hItem)->hwndTree, &rc, fErase);
return TRUE;
}
}
return TRUE;
}
BOOL NavItemI_Expand(HNAVITEM hItem, UINT flag)
{
UINT tiFlag;
if (!hItem) return FALSE;
switch(flag)
{
case NAVITEM_TOGGLE_I: tiFlag = TVE_TOGGLE; break;
case NAVITEM_EXPAND_I: tiFlag = TVE_EXPAND; break;
case NAVITEM_COLLAPSE_I: tiFlag = TVE_COLLAPSE; break;
default: return FALSE;
}
return (BOOL)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_EXPAND, (WPARAM)tiFlag, (LPARAM)((NAVITM*)hItem)->hTreeItem);
}
INT NavItemI_GetFullName(HNAVITEM hItem, LPWSTR pszFullName, INT cchMaxLen)
{
wchar_t *current, *scanner, *text;
INT remaining;
if (!pszFullName || !hItem) return 0;
pszFullName[0] = 0x00;
remaining = cchMaxLen;
current = pszFullName;
while(hItem && remaining)
{
text = (((NAVITM*)hItem)->pszInvariant) ? ((NAVITM*)hItem)->pszInvariant : ((NAVITM*)hItem)->pszText;
if (!text) text = EMPTY_ITEM_NAME;
if (current != pszFullName)
{
*current = SEPARATOR;
current++;
remaining--;
}
scanner = text + lstrlenW(text) - 1;
BOOL second = FALSE;
while (scanner >= text && remaining)
{
*current = *scanner;
current++;
remaining--;
if (SEPARATOR == *scanner && !second) { second = TRUE; continue; }
second = FALSE;
scanner--;
}
hItem = NavItemI_GetParent(hItem);
}
if (remaining)
{
*current = 0x00;
current--;
scanner = pszFullName;
while (scanner < current)
{
wchar_t tmp = *scanner;
*scanner = *current;
*current = tmp;
scanner++;
current--;
}
}
else
{
*pszFullName = 0x00;
return 0;
}
return cchMaxLen - remaining;
}
BOOL NavItemI_Move(HNAVITEM hItem, HNAVITEM hItemDest, BOOL fAfter)
{
WORD order;
UINT flags;
HNAVCTRL hNav;
if (!hItem) return FALSE;
if (hItemDest)
{
order = ((NAVITM*)hItemDest)->sortOrder;
flags = (fAfter) ? NOF_MOVEONEAFTER_I : NOF_MOVEONEBEFORE_I;
}
else
{
order = 1;
flags = NOF_MOVEONEBEFORE_I;
}
hNav = (HNAVCTRL)GetPropW(((NAVITM*)hItem)->hwndTree, NAVMGR_HWNDPROPW);
NavCtrlI_BeginUpdate(hNav, NUF_LOCK_NONE_I);
order = NavItemI_SetOrder(hItem, order, flags);
NavItemI_EnsureVisible(hItem);
NavCtrlI_EndUpdate(hNav);
return ((WORD)-1 != order);
}
static INT CALLBACK CommpareByOrderCB(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
if (lParam1 == lParam2) return 0;
if (NULL == lParam1) return 1;
return (((NAVITM*)lParam1)->sortOrder - ((NAVITM*)lParam2)->sortOrder);
}
static BOOL NavItemI_SetOrderWorker(HNAVITEM hItem, HTREEITEM hTreeFirst, WORD order, UINT flags)
{
bool bRecurse;
if (!hItem) return FALSE;
bRecurse = false;
if (0 == order)
{
order = 1;
flags = NOF_MOVEONEBEFORE_I;
}
if (((WORD)-1) == order || ((NAVITM*)hItem)->sortOrder != order)
{
TVITEMW treeItem; // keep it here so it will be released prior to recurtion
((NAVITM*)hItem)->sortOrder = (((WORD)-1) == order) ? 1 : order;
treeItem.mask = TVIF_HANDLE | TVIF_PARAM;
treeItem.hItem = hTreeFirst;
while (treeItem.hItem)
{
if (treeItem.hItem != ((NAVITM*)hItem)->hTreeItem)
{
if (!SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETITEMW, (WPARAM)0, (LPARAM)&treeItem)) return FALSE;
if (((WORD)-1) == order)
{
if (treeItem.lParam && ((NAVITM*)hItem)->sortOrder <= ((NAVITM*)treeItem.lParam)->sortOrder)
((NAVITM*)hItem)->sortOrder = ((NAVITM*)treeItem.lParam)->sortOrder + 1;
}
else
{
if (treeItem.lParam && ((NAVITM*)treeItem.lParam)->sortOrder == order)
{
switch(flags)
{
case NOF_MOVEONEBEFORE_I:
hItem = (HNAVITEM)treeItem.lParam;
order = ((NAVITM*)hItem)->sortOrder + 1;
break;
case NOF_MOVEONEAFTER_I:
order++;
flags = NOF_MOVEONEBEFORE_I;
break;
case NOF_MOVEBEFORE_I:
if (1 == order)
{
hItem = (HNAVITEM)treeItem.lParam;
order = ((NAVITM*)hItem)->sortOrder + 1;
flags = NOF_MOVEONEBEFORE_I;
}
else order--;
break;
case NOF_MOVEAFTER_I:
order++;
break;
default: return FALSE;
}
bRecurse = true;
break;
}
}
}
treeItem.hItem = (HTREEITEM)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)treeItem.hItem);
}
}
return (bRecurse) ? NavItemI_SetOrderWorker(hItem, hTreeFirst, order, flags) : TRUE;
}
WORD NavItemI_SetOrder(HNAVITEM hItem, WORD order, UINT flags)
{
HTREEITEM hTreeParent;
if (!hItem) return (WORD)-1;
hTreeParent = (HTREEITEM)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETNEXTITEM, (WPARAM)TVGN_PARENT, (LPARAM)((NAVITM*)hItem)->hTreeItem);
if (NavItemI_SetOrderWorker(hItem,
(HTREEITEM)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETNEXTITEM,
(WPARAM)((hTreeParent) ? TVGN_CHILD : TVGN_ROOT), (LPARAM)hTreeParent),
order, flags))
{
HNAVCTRL hNav;
TVSORTCB sort;
sort.hParent = hTreeParent;
sort.lpfnCompare = CommpareByOrderCB;
sort.lParam = 0;
hNav = (HNAVCTRL)GetPropW(((NAVITM*)hItem)->hwndTree, NAVMGR_HWNDPROPW);
NavCtrlI_BeginUpdate(hNav, NUF_LOCK_NONE_I);
SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_SORTCHILDRENCB, (WPARAM)FALSE, (LPARAM)&sort);
NavCtrlI_EndUpdate(hNav);
}
return ((NAVITM*)hItem)->sortOrder;
}
WORD NavItemI_GetOrder(HNAVITEM hItem)
{
return (hItem) ? ((NAVITM*)hItem)->sortOrder : 0xFFFF;
}
BOOL NavItemI_Select(HNAVITEM hItem)
{
BOOL fResult;
if (!hItem) return FALSE;
fResult = (BOOL)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_SELECTITEM, (WPARAM)TVGN_CARET, (LPARAM)((NAVITM*)hItem)->hTreeItem);
SendMessageW(((NAVITM*)hItem)->hwndTree, WM_HSCROLL, MAKEWPARAM(SB_LEFT, 0), NULL);
SendMessageW(((NAVITM*)hItem)->hwndTree, WM_HSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0), NULL);
return fResult;
}
BOOL NavItemI_EnsureVisible(HNAVITEM hItem)
{
BOOL fResult;
if (!hItem) return FALSE;
fResult = (BOOL)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_ENSUREVISIBLE, (WPARAM)0, (LPARAM)((NAVITM*)hItem)->hTreeItem);
if (fResult)
{
SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS | SIF_RANGE;
if(GetScrollInfo(((NAVITM*)hItem)->hwndTree, SB_HORZ, &si) && (si.nMin != si.nPos))
{
SendMessageW(((NAVITM*)hItem)->hwndTree, WM_HSCROLL, MAKEWPARAM(SB_LEFT, 0), NULL);
SendMessageW(((NAVITM*)hItem)->hwndTree, WM_HSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0), NULL);
}
}
return fResult;
}
HFONT NavItemI_GetFont(HNAVITEM hItem)
{
return (hItem) ? ((NAVITM*)hItem)->hFont : NULL;
}
HFONT NavItemI_SetFont(HNAVITEM hItem, HFONT hFont)
{
HFONT hFontOld;
if (!hItem) return NULL;
hFontOld = ((NAVITM*)hItem)->hFont;
((NAVITM*)hItem)->hFont = hFont;
NavItemI_Invalidate(hItem, NULL, FALSE);
return hFontOld;
}
HIMAGELIST NavItemI_CreateDragImage(HNAVITEM hItem, LPCWSTR pszTipText)
{
HIMAGELIST hIL;
HNAVCTRL hNav;
HBITMAP hbmp;
INT cy, cx, ilIndex;
RECT rcImage, rcText, rcTip;
HDC hdcMem, hdcScreen;
HFONT hFont, hFontOld, hFontTip;
BOOL fDestroyFont;
fDestroyFont = FALSE;
hFont = NULL;
hFontTip = NULL;
if (!hItem) return NULL;
hNav = (HNAVCTRL)GetPropW(((NAVITM*)hItem)->hwndTree, NAVMGR_HWNDPROPW);
if (!hNav) return NULL;
cx = DRAGIMAGE_OFFSET_X;
cy = (INT)SendMessageW(((NAVITM*)hItem)->hwndTree, TVM_GETITEMHEIGHT, (WPARAM)0, (LPARAM)0L) + 2*DRAGIMAGE_OFFSET_Y;
if (!cy) return NULL;
hdcScreen = GetDCEx(((NAVITM*)hItem)->hwndTree, NULL, DCX_WINDOW | DCX_CACHE);
hdcMem = (hdcScreen) ? CreateCompatibleDC(NULL) : NULL;
if (!hdcMem)
{
if (hdcScreen) ReleaseDC(((NAVITM*)hItem)->hwndTree, hdcScreen);
return NULL;
}
SetRect(&rcText, 0,0,0,0);
SetRect(&rcTip, 0,0,0,0);
if (((NAVITM*)hItem)->pszText)
{
if (((NAVITM*)hItem)->hFont) hFont = ((NAVITM*)hItem)->hFont;
else
{
hFont = (HFONT)::SendMessageW(((NAVITM*)hItem)->hwndTree, WM_GETFONT, 0, 0);
if (NULL == hFont)
hFont = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
if ((NIS_BOLD_I | NIS_ITALIC_I | NIS_UNDERLINE_I) & ((NAVITM*)hItem)->style)
{
LOGFONTW lf = { 0 };
GetObjectW(hFont, sizeof(LOGFONTW), &lf);
if (NIS_BOLD_I & ((NAVITM*)hItem)->style) lf.lfWeight = FW_BOLD;
if (NIS_ITALIC_I & ((NAVITM*)hItem)->style) lf.lfItalic = TRUE;
if (NIS_UNDERLINE_I & ((NAVITM*)hItem)->style) lf.lfUnderline = TRUE;
hFont = CreateFontIndirectW(&lf);
fDestroyFont = TRUE;
}
}
if (hFont) hFontOld = (HFONT)SelectObject(hdcMem, hFont);
DrawTextW(hdcMem, ((NAVITM*)hItem)->pszText, -1, &rcText, DT_CALCRECT | DT_NOPREFIX);
if(rcText.bottom - rcText.top > cy) cy = (rcText.bottom - rcText.top) + 2;
cx += ((rcText.right - rcText.left) + DRAGIMAGE_OFFSET_X);
}
ilIndex = -1;
if (((NAVMNGR*)hNav)->hmlilImages)
{
hIL = (HIMAGELIST)SendMessageW(((NAVMNGR*)hNav)->hwndHost, TVM_GETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)0);
if (hIL && MLImageListI_GetRealList(((NAVMNGR*)hNav)->hmlilImages) == hIL)
{
COLORREF rgbBk, rgbFg;
GetItemColors(hNav, NIS_SELECTED_I | NIS_FOCUSED_I, &rgbBk, &rgbFg);
ilIndex = GetRealImageIndex(hNav, (NAVITM*)hItem, IMAGE_SELECTED_I, rgbBk, rgbFg);
}
}
else
hIL = NULL;
if (-1 != ilIndex && NULL != hIL)
{
IMAGEINFO ii;
ImageList_GetImageInfo(hIL, ilIndex, &ii);
cx += (ii.rcImage.right - ii.rcImage.left) + 5;
SetRect(&rcImage, 0, 0, ii.rcImage.right - ii.rcImage.left, ii.rcImage.bottom - ii.rcImage.top);
}
else SetRect(&rcImage, 0,0,0,0);
OffsetRect(&rcImage, DRAGIMAGE_OFFSET_X, ((cy - DRAGIMAGE_OFFSET_Y) - (rcImage.bottom - rcImage.top))/2);
OffsetRect(&rcText, rcImage.right + ((rcImage.right != rcImage.left) ? 5 : 0), ((cy - DRAGIMAGE_OFFSET_Y) - (rcText.bottom - rcText.top))/2);
if (pszTipText && *pszTipText)
{
HFONT hFontTmp;
hFontTip = (HFONT)::SendMessageW(((NAVITM*)hItem)->hwndTree, WM_GETFONT, 0, 0);
if (!hFontTip) hFontTip = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
hFontTmp = (HFONT)SelectObject(hdcMem, hFontTip);
DrawTextW(hdcMem, pszTipText, -1, &rcTip, DT_CALCRECT | DT_NOPREFIX);
SelectObject(hdcMem, hFontTmp);
if (rcTip.right - rcTip.left > (cx - rcText.left + 3)) cx = rcText.left + (rcTip.right - rcTip.left) + 3;
OffsetRect(&rcTip, rcText.left, cy + 1);
cy += ((rcTip.bottom - rcTip.top) + 3);
}
hbmp = (3 != cx) ? CreateCompatibleBitmap(hdcScreen, cx, cy) : NULL;
if (hbmp)
{
HGDIOBJ hgdiOld;
RECT rc;
hgdiOld = SelectObject(hdcMem, hbmp);
SetBkColor(hdcMem, WADlg_getColor(WADLG_SELBAR_BGCOLOR));
SetTextColor(hdcMem, WADlg_getColor(WADLG_SELBAR_FGCOLOR));
SetRect(&rc, 0, 0, cx, cy);
ExtTextOutW(hdcMem, 0, 0, ETO_OPAQUE, &rc, L"", 0, 0);
if (hIL && -1 != ilIndex)
{
ImageList_DrawEx(hIL, ilIndex, hdcMem, rcImage.left, rcImage.top,
(rcImage.right - rcImage.left), (rcImage.bottom - rcImage.top), CLR_DEFAULT, CLR_DEFAULT, ILD_NORMAL);
}
if (((NAVITM*)hItem)->pszText) DrawTextW(hdcMem, ((NAVITM*)hItem)->pszText, -1, &rcText, DT_NOPREFIX);
if (pszTipText && *pszTipText)
{
HFONT hFontTmp;
hFontTmp = (HFONT)SelectObject(hdcMem, hFontTip);
DrawTextW(hdcMem, pszTipText, -1, &rcTip, DT_NOPREFIX);
SelectObject(hdcMem, hFontTmp);
}
SelectObject(hdcMem, hgdiOld);
hIL = ImageList_Create(cx, cy, ILC_COLOR24 | ILC_MASK, 0, 1);
if (hIL && -1 == ImageList_Add(hIL, hbmp, NULL))
{
ImageList_Destroy(hIL);
hIL = NULL;
}
DeleteObject(hbmp);
}
if (hFont)
{
SelectObject(hdcMem, hFontOld);
if (fDestroyFont) DeleteObject(hFont);
}
// if (hFontTip) DeleteObject(hFontTip); // we not creating it...
DeleteDC(hdcMem);
ReleaseDC(((NAVITM*)hItem)->hwndTree, hdcScreen);
return hIL;
}