#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 #include 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"<>" #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; }