void ShowPopup(SHOWPOPUP_DATA *sd) { TCString PopupText; if (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_SHOWPREVCLIENT)) { mir_sntprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s (was %s)"), (const TCHAR*)sd->MirVer, (const TCHAR*)sd->OldMirVer); PopupText.ReleaseBuffer(); } else { mir_sntprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s"), (const TCHAR*)sd->MirVer); PopupText.ReleaseBuffer(); } PLUGIN_DATA *pdata = (PLUGIN_DATA*)calloc(1, sizeof(PLUGIN_DATA)); POPUPDATAT ppd = {0}; ppd.lchContact = sd->hContact; char *szProto = GetContactProto(sd->hContact); pdata->hIcon = ppd.lchIcon = Finger_GetClientIcon(sd->MirVer, false); _ASSERT(ppd.lchIcon); if (!ppd.lchIcon || (DWORD)ppd.lchIcon == CALLSERVICE_NOTFOUND) { // if we didn't succeed retrieving client icon, show the usual status icon instead ppd.lchIcon = LoadSkinnedProtoIcon(szProto, db_get_w(sd->hContact, szProto, "Status", ID_STATUS_OFFLINE)); pdata->hIcon = NULL; } _tcsncpy(ppd.lptzContactName, (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)sd->hContact, GCDNF_TCHAR), lengthof(ppd.lptzContactName) - 1); _tcsncpy(ppd.lptzText, PopupText, lengthof(ppd.lptzText) - 1); ppd.colorBack = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFBGCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_BGCOLOUR)); ppd.colorText = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFTEXTCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_TEXTCOLOUR)); ppd.PluginWindowProc = PopupWndProc; pdata->PopupLClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_LCLICK_ACTION); pdata->PopupRClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_RCLICK_ACTION); ppd.iSeconds = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_POPUPDELAY); ppd.PluginData = pdata; PUAddPopupT(&ppd); }
void ShowPopup(SHOWPOPUP_DATA *sd) { TCString PopupText; if (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_SHOWPREVCLIENT)) { mir_snwprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s (was %s)"), (const wchar_t*)sd->MirVer, (const wchar_t*)sd->OldMirVer); PopupText.ReleaseBuffer(); } else { mir_snwprintf(PopupText.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("changed client to %s"), (const wchar_t*)sd->MirVer); PopupText.ReleaseBuffer(); } PLUGIN_DATA *pdata = (PLUGIN_DATA*)calloc(1, sizeof(PLUGIN_DATA)); POPUPDATAT ppd = { 0 }; ppd.lchContact = sd->hContact; char *szProto = GetContactProto(sd->hContact); pdata->hIcon = ppd.lchIcon = Finger_GetClientIcon(sd->MirVer, false); _ASSERT(ppd.lchIcon); if (!ppd.lchIcon || (INT_PTR)ppd.lchIcon == CALLSERVICE_NOTFOUND) { // if we didn't succeed retrieving client icon, show the usual status icon instead ppd.lchIcon = Skin_LoadProtoIcon(szProto, db_get_w(sd->hContact, szProto, "Status", ID_STATUS_OFFLINE)); pdata->hIcon = nullptr; } wcsncpy(ppd.lptzContactName, Clist_GetContactDisplayName(sd->hContact), _countof(ppd.lptzContactName) - 1); wcsncpy(ppd.lptzText, PopupText, _countof(ppd.lptzText) - 1); ppd.colorBack = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFBGCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_BGCOLOUR)); ppd.colorText = (sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_DEFTEXTCOLOUR) ? 0 : sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_TEXTCOLOUR)); ppd.PluginWindowProc = PopupWndProc; pdata->PopupLClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_LCLICK_ACTION); pdata->PopupRClickAction = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_RCLICK_ACTION); ppd.iSeconds = sd->PopupOptPage->GetValue(IDC_POPUPOPTDLG_POPUPDELAY); ppd.PluginData = pdata; PUAddPopupT(&ppd); }
void CMsgTree::UpdateItem(int ID) // updates item title, and expanded/collapsed state for groups { COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl(); int Order = TreeCtrl->IDToOrder(ID); if (Order != -1) { CBaseTreeItem* TreeItem = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; TCString NewTitle; TVITEM tvi; tvi.mask = TVIF_HANDLE | TVIF_TEXT; tvi.hItem = TreeItem->hItem; tvi.pszText = NewTitle.GetBuffer(TREEITEMTITLE_MAXLEN); tvi.cchTextMax = TREEITEMTITLE_MAXLEN; TreeView_GetItem(hTreeView, &tvi); if (TreeItem->Title != (const TCHAR*)tvi.pszText) { TreeCtrl->SetModified(true); NMMSGTREE nm = { 0 }; nm.ItemNew = TreeItem; nm.hdr.code = MTN_ITEMRENAMED; nm.hdr.hwndFrom = hTreeView; nm.hdr.idFrom = GetDlgCtrlID(hTreeView); SendMessage(GetParent(hTreeView), WM_NOTIFY, 0, (LPARAM)&nm); } tvi.mask = TVIF_HANDLE | TVIF_TEXT; tvi.pszText = TreeItem->Title; TreeView_SetItem(hTreeView, &tvi); TreeView_Expand(hTreeView, tvi.hItem, (TreeItem->Flags & TIF_EXPANDED) ? TVE_EXPAND : TVE_COLLAPSE); } }
TCString DBGetContactSettingAsString(MCONTACT hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue) { // also converts numeric values to a string DBVARIANT dbv = {0}; int iRes = db_get_ws(hContact, szModule, szSetting, &dbv); TCString Result; if (!iRes && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR)) { Result = dbv.ptszVal; } else if (dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD) { long value = (dbv.type == DBVT_DWORD) ? dbv.dVal : (dbv.type == DBVT_WORD ? dbv.wVal : dbv.bVal); _ultot(value, Result.GetBuffer(64), 10); Result.ReleaseBuffer(); } else Result = szDefaultValue; if (!iRes) db_free(&dbv); return Result; }
TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring, int ID) { TCString Result(_T("")); sPcreCompileData s = {0}; int NewID = PcreCompileData.AddElem(s); PcreCompileData[NewID].ID = ID; if (hPcreDLL && !bAddAsUsualSubstring) { const char *Err; int ErrOffs; int Flags = PCRE_CASELESS; if (Regexp[0] == '/') { TCString OrigRegexp = Regexp; Regexp = Regexp.Right(Regexp.GetLen() - 1); TCHAR *pRegexpEnd = (TCHAR*)Regexp + Regexp.GetLen(); TCHAR *p = _tcsrchr(Regexp.GetBuffer(), '/'); if (!p) { Regexp = OrigRegexp; } else { *p = 0; Flags = 0; while (++p < pRegexpEnd) { switch (*p) { case 'i': Flags |= PCRE_CASELESS; break; case 'm': Flags |= PCRE_MULTILINE; break; case 's': Flags |= PCRE_DOTALL; break; case 'x': Flags |= PCRE_EXTENDED; break; case 'A': Flags |= PCRE_ANCHORED; break; case 'f': Flags |= PCRE_FIRSTLINE; break; case 'D': Flags |= PCRE_DOLLAR_ENDONLY; break; case 'U': Flags |= PCRE_UNGREEDY; break; case 'X': Flags |= PCRE_EXTRA; break; default: // Result += LogMessage(Translate("Warning, unknown pattern modifier '%c':\n"), *p ); break; } } } Regexp.ReleaseBuffer(); } PcreCompileData[NewID].pPcre = pcre_compile(WCHAR2UTF8(Regexp).GetData(), PCRE_UTF8 | PCRE_NO_UTF8_CHECK | Flags, &Err, &ErrOffs, NULL); if (PcreCompileData[NewID].pPcre) { PcreCompileData[NewID].pExtra = NULL; if (pcre_study) PcreCompileData[NewID].pExtra = pcre_study(PcreCompileData[NewID].pPcre, 0, &Err); } else { // Result += LogMessage(TranslateT("Syntax error in regexp\n%s\nat offset %d: %s."), (TCHAR*)Regexp, ErrOffs, (TCHAR*)ANSI2TCHAR(Err)) + _T("\n\n"); PcreCompileData[NewID].Pattern = Regexp; } } else PcreCompileData[NewID].Pattern = Regexp; return Result; }
INT_PTR srvVariablesHandler(WPARAM, LPARAM lParam) { ARGUMENTSINFO *ai = (ARGUMENTSINFO*)lParam; ai->flags = AIF_DONTPARSE; TCString Result; if (!mir_tstrcmp(ai->targv[0], VAR_AWAYSINCE_TIME)) { GetTimeFormat(LOCALE_USER_DEFAULT, 0, g_ProtoStates[VarParseData.szProto].AwaySince, (ai->argc > 1 && *ai->targv[1]) ? ai->targv[1] : _T("H:mm"), Result.GetBuffer(256), 256); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_AWAYSINCE_DATE)) { GetDateFormat(LOCALE_USER_DEFAULT, 0, g_ProtoStates[VarParseData.szProto].AwaySince, (ai->argc > 1 && *ai->targv[1]) ? ai->targv[1] : NULL, Result.GetBuffer(256), 256); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_STATDESC)) { Result = (VarParseData.Flags & VPF_XSTATUS) ? STR_XSTATUSDESC : pcli->pfnGetStatusModeDescription(g_ProtoStates[VarParseData.szProto].Status, 0); } else if (!mir_tstrcmp(ai->targv[0], VAR_MYNICK)) { if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_MYNICKPERPROTO) && VarParseData.szProto) Result = db_get_s(NULL, VarParseData.szProto, "Nick", (TCHAR*)NULL); if (Result == NULL) Result = pcli->pfnGetContactDisplayName(NULL, 0); if (Result == NULL) Result = TranslateT("Stranger"); } else if (!mir_tstrcmp(ai->targv[0], VAR_REQUESTCOUNT)) { mir_sntprintf(Result.GetBuffer(16), 16, _T("%d"), db_get_w(ai->fi->hContact, MOD_NAME, DB_REQUESTCOUNT, 0)); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_MESSAGENUM)) { mir_sntprintf(Result.GetBuffer(16), 16, _T("%d"), db_get_w(ai->fi->hContact, MOD_NAME, DB_MESSAGECOUNT, 0)); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_TIMEPASSED)) { ULARGE_INTEGER ul_AwaySince, ul_Now; SYSTEMTIME st; GetLocalTime(&st); SystemTimeToFileTime(&st, (LPFILETIME)&ul_Now); SystemTimeToFileTime(g_ProtoStates[VarParseData.szProto].AwaySince, (LPFILETIME)&ul_AwaySince); ul_Now.QuadPart -= ul_AwaySince.QuadPart; ul_Now.QuadPart /= 10000000; // now it's in seconds Result.GetBuffer(256); if (ul_Now.LowPart >= 7200) // more than 2 hours mir_sntprintf(Result, 256, TranslateT("%d hours"), ul_Now.LowPart / 3600); else if (ul_Now.LowPart >= 120) // more than 2 minutes mir_sntprintf(Result, 256, TranslateT("%d minutes"), ul_Now.LowPart / 60); else mir_sntprintf(Result, 256, TranslateT("%d seconds"), ul_Now.LowPart); Result.ReleaseBuffer(); } else if (!mir_tstrcmp(ai->targv[0], VAR_PREDEFINEDMESSAGE)) { ai->flags = 0; // reset AIF_DONTPARSE flag if (ai->argc != 2) return NULL; COptPage MsgTreeData(g_MsgTreePage); COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE); TreeCtrl->DBToMem(CString(MOD_NAME)); for (int i = 0; i < TreeCtrl->Value.GetSize(); i++) { if (!(TreeCtrl->Value[i].Flags & TIF_GROUP) && !mir_tstrcmpi(TreeCtrl->Value[i].Title, ai->targv[1])) { Result = TreeCtrl->Value[i].User_Str1; break; } } if (Result == NULL) // if we didn't find a message with specified title return NULL; // return it now, as later we change NULL to "" } else if (!mir_tstrcmp(ai->targv[0], VAR_PROTOCOL)) { if (VarParseData.szProto) { CString AnsiResult; CallProtoService(VarParseData.szProto, PS_GETNAME, 256, (LPARAM)AnsiResult.GetBuffer(256)); AnsiResult.ReleaseBuffer(); Result = _A2T(AnsiResult); } if (Result == NULL) // if we didn't find a message with specified title return NULL; // return it now, as later we change NULL to "" } TCHAR *szResult = (TCHAR*)malloc((Result.GetLen() + 1) * sizeof(TCHAR)); if (!szResult) return NULL; mir_tstrcpy(szResult, (Result != NULL) ? Result : _T("")); return (INT_PTR)szResult; }
int ContactSettingChanged(WPARAM hContact, LPARAM lParam) { DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; if (lstrcmpA(cws->szSetting, DB_MIRVER)) return 0; SHOWPOPUP_DATA sd = {0}; char *szProto = GetContactProto(hContact); if (g_PreviewOptPage) sd.MirVer = _T("Miranda NG ICQ 0.93.5.3007"); else { if (!hContact) // exit if hContact == NULL and it's not a popup preview return 0; _ASSERT(szProto); if (!strcmp(szProto, META_PROTO)) // workaround for metacontacts return 0; sd.MirVer = db_get_s(hContact, szProto, DB_MIRVER, _T("")); if (sd.MirVer.IsEmpty()) return 0; } sd.OldMirVer = db_get_s(hContact, MOD_NAME, DB_OLDMIRVER, _T("")); db_set_ts(hContact, MOD_NAME, DB_OLDMIRVER, sd.MirVer); // we have to write it here, because we modify sd.OldMirVer and sd.MirVer to conform our settings later if (sd.OldMirVer.IsEmpty()) // looks like it's the right way to do return 0; COptPage PopupOptPage; if (g_PreviewOptPage) PopupOptPage = *g_PreviewOptPage; else { PopupOptPage = g_PopupOptPage; PopupOptPage.DBToMem(); } MCONTACT hContactOrMeta = (hContact) ? db_mc_getMeta(hContact) : 0; if (!hContactOrMeta) hContactOrMeta = hContact; if (hContact && db_get_b(hContactOrMeta, "CList", "Hidden", 0)) return 0; int PerContactSetting = hContact ? db_get_b(hContact, MOD_NAME, DB_CCN_NOTIFY, NOTIFY_USEGLOBAL) : NOTIFY_ALWAYS; // NOTIFY_ALWAYS for preview if (PerContactSetting == NOTIFY_USEGLOBAL && hContactOrMeta != hContact) // subcontact setting has a priority over a metacontact setting PerContactSetting = db_get_b(hContactOrMeta, MOD_NAME, DB_CCN_NOTIFY, NOTIFY_USEGLOBAL); if (PerContactSetting && (PerContactSetting == NOTIFY_ALMOST_ALWAYS || PerContactSetting == NOTIFY_ALWAYS || !PopupOptPage.GetValue(IDC_POPUPOPTDLG_USESTATUSNOTIFYFLAG) || !(db_get_dw(hContactOrMeta, "Ignore", "Mask1", 0) & 0x8))) { // check if we need to notify at all sd.hContact = hContact; sd.PopupOptPage = &PopupOptPage; if (!PopupOptPage.GetValue(IDC_POPUPOPTDLG_VERCHGNOTIFY) || !PopupOptPage.GetValue(IDC_POPUPOPTDLG_SHOWVER)) { if (bFingerprintExists) { LPCTSTR ptszOldClient = Finger_GetClientDescr(sd.OldMirVer); LPCTSTR ptszClient = Finger_GetClientDescr(sd.MirVer); if (ptszOldClient && ptszClient) { if (PerContactSetting != NOTIFY_ALMOST_ALWAYS && PerContactSetting != NOTIFY_ALWAYS && !PopupOptPage.GetValue(IDC_POPUPOPTDLG_VERCHGNOTIFY) && !_tcscmp(ptszClient, ptszOldClient)) return 0; if (!PopupOptPage.GetValue(IDC_POPUPOPTDLG_SHOWVER)) { sd.MirVer = ptszClient; sd.OldMirVer = ptszOldClient; } } } } if (sd.MirVer == (const TCHAR*)sd.OldMirVer) { _ASSERT(hContact); return 0; } if (PerContactSetting == NOTIFY_ALWAYS || (PopupOptPage.GetValue(IDC_POPUPOPTDLG_POPUPNOTIFY) && (g_PreviewOptPage || PerContactSetting == NOTIFY_ALMOST_ALWAYS || -1 == PcreCheck(sd.MirVer)))) { ShowPopup(&sd); SkinPlaySound(CLIENTCHANGED_SOUND); } } if (hContact) { TCString ClientName; if (PopupOptPage.GetValue(IDC_POPUPOPTDLG_SHOWPREVCLIENT) && sd.OldMirVer.GetLen()) { mir_sntprintf(ClientName.GetBuffer(MAX_MSG_LEN), MAX_MSG_LEN, TranslateT("%s (was %s)"), (const TCHAR*)sd.MirVer, (const TCHAR*)sd.OldMirVer); ClientName.ReleaseBuffer(); } else ClientName = sd.MirVer; } _ASSERT(sd.MirVer.GetLen()); // save the last known MirVer value even if the new one is empty return 0; }
static LRESULT CALLBACK MsgTreeSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { CMsgTree *dat = CWndUserData(GetParent(hWnd)).GetMsgTree(); switch (Msg) { case UM_MSGTREE_UPDATE: // returns TRUE if updated { bool Modified = dat->MsgTreePage.GetModified(); TCString WndTitle; if (Modified) { WndTitle.GetBuffer(256); HWND hCurWnd = hWnd; do { hCurWnd = GetParent(hCurWnd); } while (hCurWnd && !GetWindowText(hCurWnd, WndTitle, 256)); WndTitle.ReleaseBuffer(); } if (!Modified || MessageBox(GetParent(hWnd), TCString(TranslateT("You've made changes to multiple message trees at a time.\r\nDo you want to leave changes in \"")) + WndTitle + TranslateT("\" dialog?\r\nPress Yes to leave changes in this dialog, or No to discard its changes and save changes of the other message tree instead."), WndTitle + _T(" - ") + TranslateT("New Away System"), MB_ICONQUESTION | MB_YESNO) == IDNO) { COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); TCString OldTitle, OldMsg, NewTitle, NewMsg; int OldOrder = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hWnd))); if (OldOrder != -1) { CBaseTreeItem* ItemOld = (OldOrder <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(OldOrder)] : (CBaseTreeItem*)&TreeCtrl->Value[OldOrder]; OldTitle = ItemOld->Title; if (!(ItemOld->Flags & TIF_ROOTITEM)) OldMsg = ((CTreeItem*)ItemOld)->User_Str1; } dat->UpdateLock++; dat->MsgTreePage.DBToMemToPage(); dat->UpdateLock--; NMMSGTREE nm = { 0 }; int Order = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hWnd))); if (Order != -1) { nm.ItemNew = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order]; NewTitle = nm.ItemNew->Title; if (!(nm.ItemNew->Flags & TIF_ROOTITEM)) NewMsg = ((CTreeItem*)nm.ItemNew)->User_Str1; } if (OldTitle.IsEmpty()) OldTitle = _T(""); // to be sure that NULL will be equal to "" in the latter comparisons if (OldMsg.IsEmpty()) OldMsg = _T(""); if (NewTitle.IsEmpty()) NewTitle = _T(""); if (NewMsg.IsEmpty()) NewMsg = _T(""); if (OldTitle != (const TCHAR*)NewTitle || OldMsg != (const TCHAR*)NewMsg) { // probably it's better to leave nm.ItemOld = NULL, to prevent accidental rewriting of it with old data from an edit control etc. nm.hdr.code = MTN_SELCHANGED; nm.hdr.hwndFrom = hWnd; nm.hdr.idFrom = GetDlgCtrlID(hWnd); SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nm); } return true; } } return false; case WM_KEYDOWN: switch (wParam) { case VK_DELETE: dat->DeleteSelectedItem(); break; case VK_INSERT: dat->AddMessage(); break; } break; case WM_RBUTTONDOWN: SetFocus(hWnd); { TVHITTESTINFO hitTest; hitTest.pt.x = (short)LOWORD(lParam); hitTest.pt.y = (short)HIWORD(lParam); TreeView_HitTest(hWnd, &hitTest); if (hitTest.hItem && hitTest.flags & TVHT_ONITEM) TreeView_SelectItem(hWnd, hitTest.hItem); return DefWindowProc(hWnd, Msg, wParam, lParam); } break; case WM_CONTEXTMENU: { TVHITTESTINFO ht; ht.pt.x = GET_X_LPARAM(lParam); ht.pt.y = GET_Y_LPARAM(lParam); TVITEM tvi = { 0 }; if (ht.pt.x == -1 && ht.pt.y == -1) { // use selected item if (tvi.hItem = TreeView_GetSelection(hWnd)) { TreeView_EnsureVisible(hWnd, tvi.hItem); RECT rc; TreeView_GetItemRect(hWnd, tvi.hItem, &rc, true); ht.pt.x = rc.left; ht.pt.y = rc.bottom; } } else { ScreenToClient(hWnd, &ht.pt); TreeView_HitTest(hWnd, &ht); if (ht.hItem && ht.flags & TVHT_ONITEM) { tvi.hItem = ht.hItem; } } if (tvi.hItem) { COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl(); tvi.mask = TVIF_HANDLE | TVIF_PARAM; TreeView_GetItem(hWnd, &tvi); int Order = TreeCtrl->IDToOrder(tvi.lParam); if (Order >= 0) { HMENU hMenu; if (TreeCtrl->Value[Order].Flags & TIF_GROUP) hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MSGTREE_CATEGORYMENU)); else hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MSGTREE_MESSAGEMENU)); _ASSERT(hMenu); HMENU hPopupMenu = GetSubMenu(hMenu, 0); TranslateMenu(hPopupMenu); ClientToScreen(hWnd, &ht.pt); struct { int ItemID, IconID; } MenuItems[] = { IDM_MSGTREEMENU_NEWMESSAGE, IMGLIST_NEWMESSAGE, IDM_MSGTREEMENU_NEWCATEGORY, IMGLIST_NEWCATEGORY, IDM_MSGTREEMENU_DELETE, IMGLIST_DELETE }; MENUITEMINFO mii = { 0 }; mii.cbSize = sizeof(mii); mii.fMask = MIIM_BITMAP | MIIM_DATA | MIIM_STATE | MIIM_CHECKMARKS; mii.hbmpItem = HBMMENU_CALLBACK; int i; for (i = 0; i < _countof(MenuItems); i++) { // set icons mii.dwItemData = MenuItems[i].IconID; SetMenuItemInfo(hPopupMenu, MenuItems[i].ItemID, false, &mii); } mii.fMask = MIIM_STATE; mii.fState = MFS_CHECKED; for (i = 0; i < _countof(SettingsList); i++) // set checkmarks if (TreeCtrl->Value[Order].ID == dat->MsgTreePage.GetValue(SettingsList[i].DBSetting)) SetMenuItemInfo(hPopupMenu, SettingsList[i].MenuItemID, false, &mii); int MenuResult = TrackPopupMenu(hPopupMenu, TPM_RIGHTBUTTON | TPM_RETURNCMD, ht.pt.x, ht.pt.y, 0, hWnd, NULL); switch (MenuResult) { case IDM_MSGTREEMENU_NEWMESSAGE: dat->AddMessage(); break; case IDM_MSGTREEMENU_NEWCATEGORY: dat->AddCategory(); break; case IDM_MSGTREEMENU_RENAME: TreeView_EditLabel(hWnd, tvi.hItem); break; case IDM_MSGTREEMENU_DELETE: dat->DeleteSelectedItem(); break; case IDR_MSGTREEMENU_DEF_ONL: case IDR_MSGTREEMENU_DEF_AWAY: case IDR_MSGTREEMENU_DEF_NA: case IDR_MSGTREEMENU_DEF_OCC: case IDR_MSGTREEMENU_DEF_DND: case IDR_MSGTREEMENU_DEF_FFC: case IDR_MSGTREEMENU_DEF_INV: case IDR_MSGTREEMENU_DEF_OTP: case IDR_MSGTREEMENU_DEF_OTL: for (int i = 0; i < _countof(SettingsList); i++) { if (SettingsList[i].MenuItemID == MenuResult) { dat->SetDefMsg(SettingsList[i].Status, tvi.lParam); break; } } } DestroyMenu(hMenu); return 0; } } } break; case WM_MEASUREITEM: { LPMEASUREITEMSTRUCT lpmi = (LPMEASUREITEMSTRUCT)lParam; if (lpmi->CtlType == ODT_MENU) { lpmi->itemWidth = max(0, GetSystemMetrics(SM_CXSMICON) - GetSystemMetrics(SM_CXMENUCHECK) + 4); lpmi->itemHeight = GetSystemMetrics(SM_CYSMICON) + 2; return true; } } break; case WM_DRAWITEM: { LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; if (dis->CtlType == ODT_MENU) { ImageList_DrawEx(dat->hImageList, dis->itemData, dis->hDC, 2, (dis->rcItem.bottom + dis->rcItem.top - GetSystemMetrics(SM_CYSMICON)) / 2 + 1, 0, 0, GetSysColor(COLOR_WINDOW), CLR_NONE, ILD_NORMAL); return true; } } break; } return CallWindowProc(dat->OrigTreeViewProc, hWnd, Msg, wParam, lParam); }