int SetRichTextRTF(HWND hwnd, const char *text) { SETTEXTEX st; st.flags = ST_DEFAULT; st.codepage = CP_UTF8; SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)text); return GetRichTextLength(hwnd, 1200, FALSE); }
char* GetRichTextUtf(HWND hwnd) { int textBufferSize = GetRichTextLength(hwnd, CP_UTF8, TRUE); if (textBufferSize == 0) return NULL; textBufferSize++; char *textBuffer = (char*)mir_alloc(textBufferSize); GETTEXTEX gt = { 0 }; gt.cb = textBufferSize; gt.flags = GT_USECRLF; gt.codepage = CP_UTF8; SendMessage(hwnd, EM_GETTEXTEX, (WPARAM)>, (LPARAM)textBuffer); return textBuffer; }
UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO *si, TCHAR* pszUID, TCHAR* pszWordText) { HMENU hSubMenu = 0; *hMenu = GetSubMenu(g_hMenu, iIndex); TranslateMenu(*hMenu); GCMENUITEMS gcmi = { 0 }; gcmi.pszID = si->ptszID; gcmi.pszModule = si->pszModule; gcmi.pszUID = pszUID; if (iIndex == 1) { int i = GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG)); EnableMenuItem(*hMenu, ID_CLEARLOG, MF_ENABLED); EnableMenuItem(*hMenu, ID_COPYALL, MF_ENABLED); ModifyMenu(*hMenu, 4, MF_GRAYED | MF_BYPOSITION, 4, NULL); if (!i) { EnableMenuItem(*hMenu, ID_COPYALL, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(*hMenu, ID_CLEARLOG, MF_BYCOMMAND | MF_GRAYED); if (pszWordText && pszWordText[0]) ModifyMenu(*hMenu, 4, MF_ENABLED | MF_BYPOSITION, 4, NULL); } if (pszWordText && pszWordText[0]) { TCHAR szMenuText[4096]; mir_sntprintf(szMenuText, _countof(szMenuText), TranslateT("Look up '%s':"), pszWordText); ModifyMenu(*hMenu, 4, MF_STRING | MF_BYPOSITION, 4, szMenuText); } else ModifyMenu(*hMenu, 4, MF_STRING | MF_GRAYED | MF_BYPOSITION, 4, TranslateT("No word to look up")); gcmi.Type = MENU_ON_LOG; } else if (iIndex == 0) { TCHAR szTemp[50]; if (pszWordText) mir_sntprintf(szTemp, TranslateT("&Message %s"), pszWordText); else mir_tstrncpy(szTemp, TranslateT("&Message"), _countof(szTemp) - 1); if (mir_tstrlen(szTemp) > 40) mir_tstrcpy(szTemp + 40, _T("...")); ModifyMenu(*hMenu, ID_MESS, MF_STRING | MF_BYCOMMAND, ID_MESS, szTemp); gcmi.Type = MENU_ON_NICKLIST; } NotifyEventHooks(pci->hBuildMenuEvent, 0, (WPARAM)&gcmi); if (gcmi.nItems > 0) AppendMenu(*hMenu, MF_SEPARATOR, 0, 0); for (int i = 0; i < gcmi.nItems; i++) { TCHAR* ptszText = TranslateTS(gcmi.Item[i].pszDesc); DWORD dwState = gcmi.Item[i].bDisabled ? MF_GRAYED : 0; if (gcmi.Item[i].uType == MENU_NEWPOPUP) { hSubMenu = CreateMenu(); AppendMenu(*hMenu, dwState | MF_POPUP, (UINT_PTR)hSubMenu, ptszText); } else if (gcmi.Item[i].uType == MENU_POPUPHMENU) AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszText); else if (gcmi.Item[i].uType == MENU_POPUPITEM) AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszText); else if (gcmi.Item[i].uType == MENU_POPUPCHECK) AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszText); else if (gcmi.Item[i].uType == MENU_POPUPSEPARATOR) AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, MF_SEPARATOR, 0, ptszText); else if (gcmi.Item[i].uType == MENU_SEPARATOR) AppendMenu(*hMenu, MF_SEPARATOR, 0, ptszText); else if (gcmi.Item[i].uType == MENU_HMENU) AppendMenu(*hMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszText); else if (gcmi.Item[i].uType == MENU_ITEM) AppendMenu(*hMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszText); else if (gcmi.Item[i].uType == MENU_CHECK) AppendMenu(*hMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszText); } return TrackPopupMenu(*hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL); }
void Log_StreamInEvent(HWND hwndDlg, LOGINFO* lin, SESSION_INFO *si, bool bRedraw) { CHARRANGE oldsel, sel, newsel; POINT point = { 0 }; TWindowData *dat = (TWindowData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if (hwndDlg == 0 || lin == 0 || si == 0 || dat == 0) return; HWND hwndRich = GetDlgItem(hwndDlg, IDC_CHAT_LOG); LOGSTREAMDATA streamData; memset(&streamData, 0, sizeof(streamData)); streamData.hwnd = hwndRich; streamData.si = si; streamData.lin = lin; streamData.bStripFormat = FALSE; streamData.dat = dat; if (!bRedraw && (si->iType == GCW_CHATROOM || si->iType == GCW_PRIVMESS) && si->bFilterEnabled && (si->iLogFilterFlags & lin->iType) == 0) return; bool bFlag = false, fDoReplace; EDITSTREAM stream = { 0 }; stream.pfnCallback = Log_StreamCallback; stream.dwCookie = (DWORD_PTR)& streamData; SCROLLINFO scroll = { 0 }; scroll.cbSize = sizeof(SCROLLINFO); scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; GetScrollInfo(GetDlgItem(hwndDlg, IDC_CHAT_LOG), SB_VERT, &scroll); SendMessage(hwndRich, EM_GETSCROLLPOS, 0, (LPARAM)&point); // do not scroll to bottom if there is a selection SendMessage(hwndRich, EM_EXGETSEL, 0, (LPARAM)&oldsel); if (oldsel.cpMax != oldsel.cpMin) SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0); //set the insertion point at the bottom sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich); SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&sel); // fix for the indent... must be a M$ bug if (sel.cpMax == 0) bRedraw = TRUE; // should the event(s) be appended to the current log WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF; //get the number of pixels per logical inch if (bRedraw) { HDC hdc = GetDC(NULL); pci->logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); pci->logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); ReleaseDC(NULL, hdc); SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0); bFlag = true; // SetCursor(LoadCursor(NULL, IDC_ARROW)); } // stream in the event(s) streamData.lin = lin; streamData.bRedraw = bRedraw; SendMessage(hwndRich, EM_STREAMIN, wp, (LPARAM)&stream); // for new added events, only replace in message or action events. // no need to replace smileys or math formulas elsewhere fDoReplace = (bRedraw || (lin->ptszText && (lin->iType == GC_EVENT_MESSAGE || lin->iType == GC_EVENT_ACTION))); // replace marked nicknames with hyperlinks to make the nicks clickable if (g_Settings.bClickableNicks) { FINDTEXTEX fi, fi2; CHARFORMAT2 cf2; memset(&cf2, 0, sizeof(CHARFORMAT2)); cf2.cbSize = sizeof(cf2); fi2.lpstrText = _T("#++~~"); fi.chrg.cpMin = bRedraw ? 0 : sel.cpMin; fi.chrg.cpMax = -1; fi.lpstrText = _T("~~++#"); while (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) > -1) { fi2.chrg.cpMin = fi.chrgText.cpMin; fi2.chrg.cpMax = -1; if (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi2) > -1) { SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi.chrgText); SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T("")); fi2.chrgText.cpMin -= fi.chrgText.cpMax - fi.chrgText.cpMin; fi2.chrgText.cpMax -= fi.chrgText.cpMax - fi.chrgText.cpMin; SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi2.chrgText); SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T("")); fi2.chrgText.cpMax = fi2.chrgText.cpMin; fi2.chrgText.cpMin = fi.chrgText.cpMin; SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi2.chrgText); cf2.dwMask = CFM_PROTECTED; cf2.dwEffects = CFE_PROTECTED; SendMessage(hwndRich, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); } fi.chrg.cpMin = fi.chrgText.cpMax; } SendMessage(hwndRich, EM_SETSEL, -1, -1); } // run smileyadd if (PluginConfig.g_SmileyAddAvail && fDoReplace) { newsel.cpMax = -1; newsel.cpMin = sel.cpMin; if (newsel.cpMin < 0) newsel.cpMin = 0; SMADD_RICHEDIT3 sm = { sizeof(sm) }; sm.hwndRichEditControl = hwndRich; sm.Protocolname = si->pszModule; sm.rangeToReplace = bRedraw ? NULL : &newsel; sm.disableRedraw = TRUE; sm.hContact = si->hContact; CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm); } // trim the message log to the number of most recent events // this uses hidden marks in the rich text to find the events which should be deleted if (si->bTrimmed) { TCHAR szPattern[50]; mir_sntprintf(szPattern, _T("~-+%d+-~"), si->pLogEnd); FINDTEXTEX fi; fi.lpstrText = szPattern; fi.chrg.cpMin = 0; fi.chrg.cpMax = -1; if (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) != 0) { CHARRANGE rng; rng.cpMin = 0; rng.cpMax = 20; SendMessage(hwndRich, EM_SETSEL, 0, fi.chrgText.cpMax + 1); SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T("")); } si->bTrimmed = FALSE; } // scroll log to bottom if the log was previously scrolled to bottom, else restore old position if ((bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)) SendMessage(GetParent(hwndRich), GC_SCROLLTOBOTTOM, 0, 0); else SendMessage(hwndRich, EM_SETSCROLLPOS, 0, (LPARAM)&point); // do we need to restore the selection if (oldsel.cpMax != oldsel.cpMin) { SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&oldsel); SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0); InvalidateRect(hwndRich, NULL, TRUE); } // need to invalidate the window if (bFlag) { sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich); SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&sel); SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0); InvalidateRect(hwndRich, NULL, TRUE); } }
void Log_StreamInEvent(HWND hwndDlg, LOGINFO* lin, SESSION_INFO *si, BOOL bRedraw, BOOL bPhaseTwo) { CHARRANGE oldsel, sel, newsel; POINT point ={0}; WPARAM wp; if (hwndDlg == 0 || lin == 0 || si == 0) return; HWND hwndRich = GetDlgItem(hwndDlg, IDC_LOG); LOGSTREAMDATA streamData; ZeroMemory(&streamData, sizeof(streamData)); streamData.hwnd = hwndRich; streamData.si = si; streamData.lin = lin; streamData.bStripFormat = FALSE; if (bRedraw || si->iType != GCW_CHATROOM || !si->bFilterEnabled || (si->iLogFilterFlags & lin->iType) != 0) { BOOL bFlag = FALSE; EDITSTREAM stream = { 0 }; stream.pfnCallback = Log_StreamCallback; stream.dwCookie = (DWORD_PTR) & streamData; SCROLLINFO scroll; scroll.cbSize = sizeof(SCROLLINFO); scroll.fMask= SIF_RANGE | SIF_POS|SIF_PAGE; GetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &scroll); SendMessage(hwndRich, EM_GETSCROLLPOS, 0, (LPARAM) &point); // do not scroll to bottom if there is a selection SendMessage(hwndRich, EM_EXGETSEL, 0, (LPARAM) &oldsel); if (oldsel.cpMax != oldsel.cpMin) SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0); //set the insertion point at the bottom sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich); SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) &sel); // fix for the indent... must be a M$ bug if (sel.cpMax == 0) bRedraw = TRUE; // should the event(s) be appended to the current log wp = bRedraw?SF_RTF:SFF_SELECTION|SF_RTF; //get the number of pixels per logical inch if (bRedraw) { HDC hdc = GetDC(NULL); pci->logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); pci->logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); ReleaseDC(NULL, hdc); SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0); bFlag = TRUE; } // stream in the event(s) streamData.lin = lin; streamData.bRedraw = bRedraw; SendMessage(hwndRich, EM_STREAMIN, wp, (LPARAM) & stream); // do smileys if (SmileyAddInstalled && (bRedraw || (lin->ptszText && lin->iType != GC_EVENT_JOIN && lin->iType != GC_EVENT_NICK && lin->iType != GC_EVENT_ADDSTATUS && lin->iType != GC_EVENT_REMOVESTATUS ))) { SMADD_RICHEDIT3 sm = {0}; newsel.cpMax = -1; newsel.cpMin = sel.cpMin; if (newsel.cpMin < 0) newsel.cpMin = 0; ZeroMemory(&sm, sizeof(sm)); sm.cbSize = sizeof(sm); sm.hwndRichEditControl = hwndRich; sm.Protocolname = si->pszModule; sm.rangeToReplace = bRedraw?NULL:&newsel; sm.disableRedraw = TRUE; sm.hContact = si->hContact; CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm); } // scroll log to bottom if the log was previously scrolled to bottom, else restore old position if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax-scroll.nPage-5 || scroll.nMax-scroll.nMin-scroll.nPage < 50) SendMessage(GetParent(hwndRich), GC_SCROLLTOBOTTOM, 0, 0); else SendMessage(hwndRich, EM_SETSCROLLPOS, 0, (LPARAM) &point); // do we need to restore the selection if (oldsel.cpMax != oldsel.cpMin) { SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & oldsel); SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0); InvalidateRect(hwndRich, NULL, TRUE); } // need to invalidate the window if (bFlag) { sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich); SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) &sel); SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0); InvalidateRect(hwndRich, NULL, TRUE); } } }