aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/General/gen_ml/navigation.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/General/gen_ml/navigation.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-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.cpp2733
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