CBaseTreeItem* CMsgTree::GetNextItem(int Flags, CBaseTreeItem* Item) // Item is 'int ID' if MTGN_BYID flag is set; returns CBaseTreeItem* or NULL { COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl(); CBaseTreeItem* TreeItem = Item; if (Flags & MTGN_BYID) { int Order = TreeCtrl->IDToOrder((int)Item); _ASSERT(Order != -1); TreeItem = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; } int TVFlag = 0; switch (Flags & ~MTGN_BYID) { case MTGN_ROOT: TVFlag = TVGN_ROOT; break; case MTGN_CHILD: TVFlag = TVGN_CHILD; break; case MTGN_PARENT: TVFlag = TVGN_PARENT; break; case MTGN_NEXT: TVFlag = TVGN_NEXT; break; case MTGN_PREV: TVFlag = TVGN_PREVIOUS; break; default: _ASSERT(0); } int Order = TreeCtrl->hItemToOrder(TreeView_GetNextItem(hTreeView, TreeItem ? TreeItem->hItem : NULL, TVFlag)); if (Order == -1) return NULL; return (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; }
static LRESULT CALLBACK ParentSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { CMsgTree *dat = CWndUserData(hWnd).GetMsgTree(); switch (Msg) { case WM_NOTIFY: if (((LPNMHDR)lParam)->hwndFrom == dat->hTreeView) { switch (((LPNMHDR)lParam)->code) { case TVN_BEGINDRAG: { LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam; NMMSGTREE nm = { 0 }; COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); int Order = TreeCtrl->hItemToOrder(pnmtv->itemNew.hItem); _ASSERT(Order != -1); if (Order != -1) { nm.ItemOld = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; nm.hdr.code = MTN_BEGINDRAG; nm.hdr.hwndFrom = dat->hTreeView; nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView); if (!SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm)) { SetCapture(hWnd); dat->hPrevDropTarget = dat->hDragItem = pnmtv->itemNew.hItem; SetFocus(dat->hTreeView); TreeView_SelectItem(dat->hTreeView, dat->hDragItem); } } } break; case TVN_SELCHANGED: if (dat->UpdateLock) return 0; else { LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam; NMMSGTREE nm = { 0 }; COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); if (pnmtv->itemOld.hItem) { int Order = TreeCtrl->IDToOrder(pnmtv->itemOld.lParam); if (Order != -1) { nm.ItemOld = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; } } if (pnmtv->itemNew.hItem) { int Order = TreeCtrl->IDToOrder(pnmtv->itemNew.lParam); if (Order != -1) { nm.ItemNew = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; } } nm.hdr.code = MTN_SELCHANGED; nm.hdr.hwndFrom = dat->hTreeView; nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView); SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm); } break; case TVN_BEGINLABELEDIT: if (dat->GetTreeCtrl()->IDToOrder(((LPNMTVDISPINFO)lParam)->item.lParam) < 0) return true; // cancel editing g_OrigEditProc = (WNDPROC)SetWindowLongPtr(TreeView_GetEditControl(dat->hTreeView), GWLP_WNDPROC, (LONG_PTR)EditSubclassProc); break; case TVN_ENDLABELEDIT: { LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam; if (ptvdi->item.pszText) { COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); int Order = TreeCtrl->IDToOrder(ptvdi->item.lParam); if (Order >= 0) { TreeCtrl->Value[Order].Title = ptvdi->item.pszText; TreeCtrl->SetModified(true); NMMSGTREE nm = { 0 }; nm.ItemNew = &TreeCtrl->Value[Order]; nm.hdr.code = MTN_ITEMRENAMED; nm.hdr.hwndFrom = dat->hTreeView; nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView); SendMessage(GetParent(dat->hTreeView), WM_NOTIFY, 0, (LPARAM)&nm); return true; // commit new text } } } break; case NM_CLICK: case NM_RCLICK: { TVHITTESTINFO hitTest; hitTest.pt.x = (short)LOWORD(GetMessagePos()); hitTest.pt.y = (short)HIWORD(GetMessagePos()); ScreenToClient(dat->hTreeView, &hitTest.pt); TreeView_HitTest(dat->hTreeView, &hitTest); if (hitTest.hItem) { if (TreeView_GetSelection(dat->hTreeView) == hitTest.hItem) // make sure TVN_SELCHANGED notification is sent always, even if previous selected item was the same as new TreeView_SelectItem(dat->hTreeView, NULL); TreeView_SelectItem(dat->hTreeView, hitTest.hItem); } } break; case NM_CUSTOMDRAW: NMTVCUSTOMDRAW *lpNMCD = (NMTVCUSTOMDRAW*)lParam; switch (lpNMCD->nmcd.dwDrawStage) { case CDDS_PREPAINT: // the control is about to start painting return CDRF_NOTIFYITEMDRAW; // instruct the control to return information when it draws items case CDDS_ITEMPREPAINT: return CDRF_NOTIFYPOSTPAINT; case CDDS_ITEMPOSTPAINT: RECT rc; TreeView_GetItemRect(lpNMCD->nmcd.hdr.hwndFrom, (HTREEITEM)lpNMCD->nmcd.dwItemSpec, &rc, true); int iSize = GetSystemMetrics(SM_CXSMICON); int x = rc.left - iSize - 5; for (int i = 0; i < _countof(SettingsList); i++) { if (lpNMCD->nmcd.lItemlParam == dat->MsgTreePage.GetValue(SettingsList[i].DBSetting)) { DrawIconEx(lpNMCD->nmcd.hdc, x, rc.top, Skin_LoadProtoIcon(NULL, SettingsList[i].Status), iSize, iSize, 0, GetSysColorBrush(COLOR_WINDOW), DI_NORMAL); x -= iSize + 1; } } } } } break; case WM_MOUSEMOVE: if (dat->hDragItem) { TVHITTESTINFO hti; hti.pt.x = (short)LOWORD(lParam); hti.pt.y = (short)HIWORD(lParam); ClientToScreen(hWnd, &hti.pt); ScreenToClient(dat->hTreeView, &hti.pt); TreeView_HitTest(dat->hTreeView, &hti); if (hti.hItem) { TreeView_SelectDropTarget(dat->hTreeView, hti.hItem); SetTimer(hWnd, MSGTREE_TIMER_ID, MSGTREE_DRAGANDDROP_GROUPEXPANDTIME, NULL); } else { if (hti.flags & TVHT_ABOVE) SendMessage(dat->hTreeView, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0); if (hti.flags & TVHT_BELOW) SendMessage(dat->hTreeView, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0); TreeView_SelectDropTarget(dat->hTreeView, NULL); KillTimer(hWnd, MSGTREE_TIMER_ID); } } break; case WM_LBUTTONUP: if (dat->hDragItem) { TreeView_SelectDropTarget(dat->hTreeView, NULL); KillTimer(hWnd, MSGTREE_TIMER_ID); ReleaseCapture(); TVHITTESTINFO hti; hti.pt.x = (short)LOWORD(lParam); hti.pt.y = (short)HIWORD(lParam); ClientToScreen(hWnd, &hti.pt); ScreenToClient(dat->hTreeView, &hti.pt); TreeView_HitTest(dat->hTreeView, &hti); if (hti.hItem && dat->hDragItem != hti.hItem) { NMMSGTREE nm = { 0 }; COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); int OrderOld = TreeCtrl->hItemToOrder(dat->hDragItem); int OrderNew = TreeCtrl->hItemToOrder(hti.hItem); _ASSERT(OrderOld != -1 && OrderNew != -1); nm.ItemOld = (OrderOld <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(OrderOld)] : (CBaseTreeItem*)&TreeCtrl->Value[OrderOld]; nm.ItemNew = (OrderNew <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(OrderNew)] : (CBaseTreeItem*)&TreeCtrl->Value[OrderNew]; nm.hdr.code = MTN_ENDDRAG; nm.hdr.hwndFrom = dat->hTreeView; nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView); if (!SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm)) { dat->UpdateLock++; dat->GetTreeCtrl()->MoveItem(hWnd, dat->hDragItem, hti.hItem); dat->UpdateLock--; } } dat->hDragItem = NULL; } break; case WM_TIMER: if (wParam == MSGTREE_TIMER_ID) { KillTimer(hWnd, MSGTREE_TIMER_ID); TVHITTESTINFO hti; hti.pt.x = (short)LOWORD(GetMessagePos()); hti.pt.y = (short)HIWORD(GetMessagePos()); ScreenToClient(dat->hTreeView, &hti.pt); TreeView_HitTest(dat->hTreeView, &hti); if (hti.hItem && dat->hDragItem != hti.hItem && TreeView_GetChild(dat->hTreeView, hti.hItem)) // target is a group and is not the same item that we're dragging TreeView_Expand(dat->hTreeView, hti.hItem, TVE_EXPAND); } } return CallWindowProc(dat->OrigParentProc, hWnd, Msg, wParam, lParam); }