diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/General/gen_ml/navigation.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/General/gen_ml/navigation.cpp')
-rw-r--r-- | Src/Plugins/General/gen_ml/navigation.cpp | 2733 |
1 files changed, 2733 insertions, 0 deletions
diff --git a/Src/Plugins/General/gen_ml/navigation.cpp b/Src/Plugins/General/gen_ml/navigation.cpp new file mode 100644 index 00000000..fb01abd3 --- /dev/null +++ b/Src/Plugins/General/gen_ml/navigation.cpp @@ -0,0 +1,2733 @@ +#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; +}
\ No newline at end of file |