From 61fde2711609ea8a2f1005f21d9ec4502044bce1 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 23 Mar 2017 22:07:41 +0300 Subject: tabSRMM: windows virtualization --- plugins/TabSRMM/src/chat_window.cpp | 2361 +++++++++++++++++------------------ plugins/TabSRMM/src/msgdialog.cpp | 669 +++++----- plugins/TabSRMM/src/msgs.h | 21 +- plugins/TabSRMM/src/themes.cpp | 11 +- plugins/TabSRMM/src/utils.cpp | 2 +- 5 files changed, 1513 insertions(+), 1551 deletions(-) diff --git a/plugins/TabSRMM/src/chat_window.cpp b/plugins/TabSRMM/src/chat_window.cpp index f1f66ff400..f28590f15e 100644 --- a/plugins/TabSRMM/src/chat_window.cpp +++ b/plugins/TabSRMM/src/chat_window.cpp @@ -40,15 +40,6 @@ extern HMENU g_hMenu; static HKL hkl = nullptr; char szIndicators[] = { 0, '+', '%', '@', '!', '*' }; -struct MESSAGESUBDATA -{ - time_t lastEnterTime; - wchar_t *szSearchQuery; - wchar_t *szSearchResult; - BOOL iSavedSpaces; - SESSION_INFO *lastSession; -}; - const CLSID IID_ITextDocument = { 0x8CC497C0, 0xA1DF, 0x11CE, { 0x80, 0x98, 0x00, 0xAA, 0x00, 0x47, 0xBE, 0x5D } }; ///////////////////////////////////////////////////////////////////////////////////////// @@ -378,19 +369,16 @@ int CChatRoomDlg::Resizer(UTILRESIZECONTROL *urc) return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; } -///////////////////////////////////////////////////////////////////////////////////////// -// subclassing for the message input control(a richedit text control) - -static bool TabAutoComplete(HWND hwnd, MESSAGESUBDATA *dat, SESSION_INFO *si) +bool CChatRoomDlg::TabAutoComplete() { - LRESULT lResult = (LRESULT)SendMessage(hwnd, EM_GETSEL, 0, 0); + LRESULT lResult = m_message.SendMsg(EM_GETSEL, 0, 0); int start = LOWORD(lResult), end = HIWORD(lResult); - SendMessage(hwnd, EM_SETSEL, end, end); + m_message.SendMsg(EM_SETSEL, end, end); GETTEXTEX gt = { 0 }; gt.codepage = 1200; gt.flags = GTL_DEFAULT | GTL_PRECISE; - int iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>, 0); + int iLen = m_message.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)>, 0); if (iLen <= 0) return false; @@ -400,14 +388,14 @@ static bool TabAutoComplete(HWND hwnd, MESSAGESUBDATA *dat, SESSION_INFO *si) gt.flags = GT_DEFAULT; gt.cb = (iLen + 9) * sizeof(wchar_t); - SendMessage(hwnd, EM_GETTEXTEX, (WPARAM)>, (LPARAM)pszText); + m_message.SendMsg(EM_GETTEXTEX, (WPARAM)>, (LPARAM)pszText); if (start > 1 && pszText[start - 1] == ' ' && pszText[start - 2] == ':') start -= 2; - if (dat->szSearchResult != nullptr) { - int cbResult = (int)mir_wstrlen(dat->szSearchResult); - if (start >= cbResult && !wcsnicmp(dat->szSearchResult, pszText + start - cbResult, cbResult)) { + if (m_wszSearchResult != nullptr) { + int cbResult = (int)mir_wstrlen(m_wszSearchResult); + if (start >= cbResult && !wcsnicmp(m_wszSearchResult, pszText + start - cbResult, cbResult)) { start -= cbResult; goto LBL_SkipEnd; } @@ -429,24 +417,24 @@ LBL_SkipEnd: if (topicStart > 5 && wcsstr(&pszText[topicStart - 6], L"/topic") == &pszText[topicStart - 6]) isTopic = TRUE; } - if (dat->szSearchQuery == nullptr) { - dat->szSearchQuery = mir_wstrndup(pszText + start, end - start); - dat->szSearchResult = mir_wstrdup(dat->szSearchQuery); - dat->lastSession = nullptr; + if (m_wszSearchQuery == nullptr) { + m_wszSearchQuery = mir_wstrndup(pszText + start, end - start); + m_wszSearchResult = mir_wstrdup(m_wszSearchQuery); + m_pLastSession = nullptr; } if (isTopic) - pszName = si->ptszTopic; + pszName = m_si->ptszTopic; else if (isRoom) { - dat->lastSession = SM_FindSessionAutoComplete(si->pszModule, si, dat->lastSession, dat->szSearchQuery, dat->szSearchResult); - if (dat->lastSession != nullptr) - pszName = dat->lastSession->ptszName; + m_pLastSession = SM_FindSessionAutoComplete(m_si->pszModule, m_si, m_pLastSession, m_wszSearchQuery, m_wszSearchResult); + if (m_pLastSession != nullptr) + pszName = m_pLastSession->ptszName; } - else pszName = pci->UM_FindUserAutoComplete(si->pUsers, dat->szSearchQuery, dat->szSearchResult); + else pszName = pci->UM_FindUserAutoComplete(m_si->pUsers, m_wszSearchQuery, m_wszSearchResult); - replaceStrW(dat->szSearchResult, nullptr); + replaceStrW(m_wszSearchResult, nullptr); if (pszName != nullptr) { - dat->szSearchResult = mir_wstrdup(pszName); + m_wszSearchResult = mir_wstrdup(pszName); if (end != start) { ptrW szReplace; if (!isRoom && !isTopic && g_Settings.bAddColonToAutoComplete && start == 0) { @@ -455,1429 +443,1400 @@ LBL_SkipEnd: mir_wstrcat(szReplace, g_Settings.bUseCommaAsColon ? L", " : L": "); pszName = szReplace; } - SendMessage(hwnd, EM_SETSEL, start, end); - SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)pszName); + m_message.SendMsg(EM_SETSEL, start, end); + m_message.SendMsg(EM_REPLACESEL, TRUE, (LPARAM)pszName); } return true; } if (end != start) { - SendMessage(hwnd, EM_SETSEL, start, end); - SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)dat->szSearchQuery); + m_message.SendMsg(EM_SETSEL, start, end); + m_message.SendMsg(EM_REPLACESEL, TRUE, (LPARAM)m_wszSearchQuery); } - replaceStrW(dat->szSearchQuery, nullptr); + replaceStrW(m_wszSearchQuery, nullptr); return false; } -LRESULT CALLBACK CChatRoomDlg::MessageSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +///////////////////////////////////////////////////////////////////////////////////////// +// calculate the required rectangle for a string using the given font. This is more +// precise than using GetTextExtentPoint...() + +int GetTextPixelSize(wchar_t* pszText, HFONT hFont, bool bWidth) { - HWND hwndParent = GetParent(hwnd); - CChatRoomDlg *pDlg = (CChatRoomDlg*)GetWindowLongPtr(hwndParent, GWLP_USERDATA); - if (pDlg == nullptr) + if (!pszText || !hFont) return 0; - MESSAGESUBDATA *dat = (MESSAGESUBDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + HDC hdc = GetDC(nullptr); + HFONT hOldFont = (HFONT)SelectObject(hdc, hFont); - if (pDlg->m_bkeyProcessed && (msg == WM_KEYUP)) { - GetKeyboardState(pDlg->kstate); - if (!(pDlg->kstate[VK_CONTROL] & 0x80) && !(pDlg->kstate[VK_SHIFT] & 0x80)) - pDlg->m_bkeyProcessed = false; - return 0; - } + RECT rc = { 0 }; + DrawText(hdc, pszText, -1, &rc, DT_CALCRECT); - switch (msg) { - case WM_NCCALCSIZE: - return CSkin::NcCalcRichEditFrame(hwnd, pDlg, ID_EXTBKINPUTAREA, msg, wParam, lParam, MessageSubclassProc); + SelectObject(hdc, hOldFont); + ReleaseDC(nullptr, hdc); + return bWidth ? rc.right - rc.left : rc.bottom - rc.top; +} - case WM_NCPAINT: - return CSkin::DrawRichEditFrame(hwnd, pDlg, ID_EXTBKINPUTAREA, msg, wParam, lParam, MessageSubclassProc); +static void __cdecl phase2(void * lParam) +{ + Thread_SetName("TabSRMM: phase2"); - case EM_SUBCLASSED: - dat = (MESSAGESUBDATA*)mir_calloc(sizeof(MESSAGESUBDATA)); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)dat); - return 0; + SESSION_INFO *si = (SESSION_INFO*)lParam; + Sleep(30); + if (si && si->pDlg) + si->pDlg->RedrawLog2(); +} - case WM_CONTEXTMENU: - POINT pt; - GetCursorPos(&pt); - { - HMENU hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT)); - HMENU hSubMenu = GetSubMenu(hMenu, 2); - RemoveMenu(hSubMenu, 9, MF_BYPOSITION); - RemoveMenu(hSubMenu, 8, MF_BYPOSITION); - RemoveMenu(hSubMenu, 4, MF_BYPOSITION); +///////////////////////////////////////////////////////////////////////////////////////// +// the actual group chat session window procedure.Handles the entire chat session window +// which is usually a (tabbed) child of a container class window. - MODULEINFO *mi = pci->MM_FindModule(pDlg->m_si->pszModule); - EnableMenuItem(hSubMenu, IDM_PASTEFORMATTED, MF_BYCOMMAND | ((mi && mi->bBold) ? MF_ENABLED : MF_GRAYED)); - TranslateMenu(hSubMenu); +CChatRoomDlg::CChatRoomDlg(SESSION_INFO *si) + : CTabBaseDlg(IDD_CHANNEL, si), + m_btnOk(this, IDOK) +{ + m_szProto = GetContactProto(m_hContact); + m_bFilterEnabled = db_get_b(m_hContact, CHAT_MODULE, "FilterEnabled", m_bFilterEnabled) != 0; + Chat_SetFilters(m_si); - CHARRANGE sel, all = { 0, -1 }; - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - if (sel.cpMin == sel.cpMax) { - EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(hSubMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED); - } + m_btnOk.OnClick = Callback(this, &CChatRoomDlg::onClick_OK); + m_btnFilter.OnClick = Callback(this, &CChatRoomDlg::onClick_Filter); + m_btnNickList.OnClick = Callback(this, &CChatRoomDlg::onClick_ShowNickList); + + m_message.OnChange = Callback(this, &CChatRoomDlg::onChange_Message); +} - MessageWindowPopupData mwpd = { sizeof(mwpd) }; - mwpd.uType = MSG_WINDOWPOPUP_SHOWING; - mwpd.uFlags = MSG_WINDOWPOPUP_INPUT; - mwpd.hContact = pDlg->m_hContact; - mwpd.hwnd = hwnd; - mwpd.hMenu = hSubMenu; - mwpd.pt = pt; - NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd); +CThumbBase* CChatRoomDlg::tabCreateThumb(CProxyWindow *pProxy) const +{ + return new CThumbMUC(pProxy, m_si); +} - int iSelection = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, GetParent(hwnd), nullptr); +void CChatRoomDlg::tabClearLog() +{ + SESSION_INFO *s = pci->SM_FindSession(m_si->ptszID, m_si->pszModule); + if (s) { + ClearLog(); + pci->LM_RemoveAll(&s->pLog, &s->pLogEnd); + s->iEventCount = 0; + s->LastTime = 0; + m_si->iEventCount = 0; + m_si->LastTime = 0; + m_si->pLog = s->pLog; + m_si->pLogEnd = s->pLogEnd; + PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0); + } +} - mwpd.selection = iSelection; - mwpd.uType = MSG_WINDOWPOPUP_SELECTED; - NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd); +void CChatRoomDlg::OnInitDialog() +{ + CTabBaseDlg::OnInitDialog(); - switch (iSelection) { - case IDM_COPY: - SendMessage(hwnd, WM_COPY, 0, 0); - break; - case IDM_CUT: - SendMessage(hwnd, WM_CUT, 0, 0); - break; - case IDM_PASTE: - case IDM_PASTEFORMATTED: - SendMessage(hwnd, EM_PASTESPECIAL, (iSelection == IDM_PASTE) ? CF_UNICODETEXT : 0, 0); - break; - case IDM_COPYALL: - SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&all); - SendMessage(hwnd, WM_COPY, 0, 0); - SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); - break; - case IDM_SELECTALL: - SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&all); - break; - } - DestroyMenu(hMenu); - } - return TRUE; + m_si->pDlg = this; + + m_iSplitterY = m_pContainer->settings->iSplitterY; + if (m_bIsAutosizingInput) + m_iSplitterY = GetDefaultMinimumInputHeight(); - case WM_MOUSEWHEEL: - if (pDlg->DM_MouseWheelHandler(wParam, lParam) == 0) - return 0; + // Typing support for GCW_PRIVMESS sessions + if (m_si->iType == GCW_PRIVMESS) { + m_nTypeMode = PROTOTYPE_SELFTYPING_OFF; + SetTimer(m_hwnd, TIMERID_TYPE, 1000, nullptr); + } - dat->lastEnterTime = 0; - break; + m_pPanel.getVisibility(); + m_pPanel.Configure(); - case WM_SYSKEYUP: - if (wParam == VK_MENU) { - ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_MESSAGE); - return 0; - } - break; + m_log.SendMsg(EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback); + m_log.SendMsg(EM_AUTOURLDETECT, 1, 0); + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_PANELSPLITTER), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc); + FireEvent(MSG_WINDOW_EVT_OPENING, 0); - case WM_SYSKEYDOWN: - pDlg->m_bkeyProcessed = false; - if (ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_MESSAGE)) { - pDlg->m_bkeyProcessed = true; - return 0; - } - break; + m_log.SendMsg(EM_SETEVENTMASK, 0, m_log.SendMsg(EM_GETEVENTMASK, 0, 0) | ENM_LINK | ENM_MOUSEEVENTS | ENM_KEYEVENTS); + m_log.SendMsg(EM_LIMITTEXT, 0x7FFFFFFF, 0); + m_log.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); - case WM_SYSCHAR: - if (pDlg->m_bkeyProcessed) { - pDlg->m_bkeyProcessed = false; // preceeding key event has been processed by miranda hotkey service - return 0; - } + m_message.SendMsg(EM_SETEVENTMASK, 0, ENM_REQUESTRESIZE | ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE); + m_message.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); - if ((wParam >= '0' && wParam <= '9') && (GetKeyState(VK_MENU) & 0x8000)) { // ALT-1 -> ALT-0 direct tab selection - BYTE bChar = (BYTE)wParam; - int iIndex = (bChar == '0') ? 10 : bChar - (BYTE)'0'; - SendMessage(pDlg->m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_BY_INDEX, (LPARAM)iIndex); - return 0; - } - break; + m_pPanel.loadHeight(); - case WM_CHAR: - bool isShift, isAlt, isCtrl; - pDlg->KbdState(isShift, isCtrl, isAlt); + if (PluginConfig.g_hMenuTrayUnread != 0 && m_hContact != 0 && m_szProto != nullptr) + UpdateTrayMenu(0, m_wStatus, m_szProto, m_wszStatus, m_hContact, FALSE); - if (PluginConfig.m_bSoundOnTyping && !isAlt && !isCtrl && !(pDlg->m_pContainer->dwFlags & CNT_NOSOUND) && wParam != VK_ESCAPE && !(wParam == VK_TAB && PluginConfig.m_bAllowTab)) - SkinPlaySound("SoundOnTyping"); + m_log.SendMsg(EM_HIDESELECTION, TRUE, 0); - if (isCtrl && !isAlt && !isShift) - switch(wParam) { - case 0x17: - PostMessage(hwndParent, WM_CLOSE, 0, 1); - return 0; - } + GetMYUIN(); + GetMyNick(); - break; + HWND hwndBtn = CreateWindowEx(0, L"MButtonClass", L"", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0, 0, 6, DPISCALEY_S(20), m_hwnd, (HMENU)IDC_TOGGLESIDEBAR, g_hInst, nullptr); + CustomizeButton(hwndBtn); + SendMessage(hwndBtn, BUTTONSETASTHEMEDBTN, 1, 0); + SendMessage(hwndBtn, BUTTONSETCONTAINER, (LPARAM)m_pContainer, 0); + SendMessage(hwndBtn, BUTTONSETASFLATBTN, FALSE, 0); + SendMessage(hwndBtn, BUTTONSETASTOOLBARBUTTON, TRUE, 0); + SendMessage(hwndBtn, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Expand or collapse the side bar"), BATF_UNICODE); - case WM_KEYDOWN: - pDlg->KbdState(isShift, isCtrl, isAlt); + DM_InitTip(); + BB_InitDlgButtons(); + SendMessage(m_hwnd, WM_CBD_LOADICONS, 0, 0); - // sound on typing.. - if (PluginConfig.m_bSoundOnTyping && !isAlt && wParam == VK_DELETE) - SkinPlaySound("SoundOnTyping"); + mir_subclassWindow(GetDlgItem(m_hwnd, IDC_SPLITTERX), SplitterSubclassProc); + mir_subclassWindow(GetDlgItem(m_hwnd, IDC_SPLITTERY), SplitterSubclassProc); - if (pDlg->ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) - return true; + UpdateOptions(); + UpdateStatusBar(); + UpdateTitle(); + m_hTabIcon = m_hTabStatusIcon; - if (wParam == VK_INSERT && !isShift && !isCtrl && !isAlt) { - pDlg->m_bInsertMode = !pDlg->m_bInsertMode; - SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd); - } - if (wParam == VK_CAPITAL || wParam == VK_NUMLOCK) - SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd); + RECT rc; + SendMessage(m_pContainer->m_hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); + SetWindowPos(m_hwnd, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), 0); + ShowWindow(m_hwnd, SW_SHOW); + UpdateNickList(); + m_pContainer->m_hwndActive = m_hwnd; + FireEvent(MSG_WINDOW_EVT_OPEN, 0); +} - if (isCtrl && isAlt && !isShift) { - switch (wParam) { - case VK_UP: - case VK_DOWN: - case VK_PRIOR: - case VK_NEXT: - case VK_HOME: - case VK_END: - WPARAM wp = 0; +void CChatRoomDlg::OnDestroy() +{ + // Typing support for GCW_PRIVMESS sessions + if (m_si->iType == GCW_PRIVMESS) + if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) + DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF); - if (wParam == VK_UP) - wp = MAKEWPARAM(SB_LINEUP, 0); - else if (wParam == VK_PRIOR) - wp = MAKEWPARAM(SB_PAGEUP, 0); - else if (wParam == VK_NEXT) - wp = MAKEWPARAM(SB_PAGEDOWN, 0); - else if (wParam == VK_HOME) - wp = MAKEWPARAM(SB_TOP, 0); - else if (wParam == VK_END) { - pDlg->DM_ScrollToBottom(0, 0); - return 0; - } - else if (wParam == VK_DOWN) - wp = MAKEWPARAM(SB_LINEDOWN, 0); + if (pcli->pfnGetEvent(m_si->hContact, 0)) + pcli->pfnRemoveEvent(m_si->hContact, GC_FAKE_EVENT); + m_si->wState &= ~STATE_TALK; + m_si->pDlg = nullptr; + m_si = nullptr; - SendDlgItemMessage(hwndParent, IDC_LOG, WM_VSCROLL, wp, 0); - return 0; - } - } + FireEvent(MSG_WINDOW_EVT_CLOSING, 0); - if (wParam == VK_RETURN) { - if (isShift) { - if (PluginConfig.m_bSendOnShiftEnter) { - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - break; - } - if ((isCtrl && !isShift) ^ (0 != PluginConfig.m_bSendOnEnter)) { - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - if (!PluginConfig.m_bSendOnEnter && !PluginConfig.m_bSendOnDblEnter) - break; - if (isCtrl) - break; + DM_FreeTheme(); - if (PluginConfig.m_bSendOnDblEnter) { - if (dat->lastEnterTime + 2 < time(nullptr)) { - dat->lastEnterTime = time(nullptr); - break; - } + UpdateTrayMenuState(this, FALSE); // remove me from the tray menu (if still there) + if (PluginConfig.g_hMenuTrayUnread) + DeleteMenu(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)m_hContact, MF_BYCOMMAND); - SendMessage(hwnd, WM_KEYDOWN, VK_BACK, 0); - SendMessage(hwnd, WM_KEYUP, VK_BACK, 0); - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - else dat->lastEnterTime = 0; + if (m_hwndTip) + DestroyWindow(m_hwndTip); - if ((wParam == VK_NEXT && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && !isShift)) { // CTRL-TAB (switch tab/window) - SendMessage(pDlg->m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_NEXT, 0); - return TRUE; - } + int i = GetTabIndexFromHWND(m_hwndParent, m_hwnd); + if (i >= 0) { + SendMessage(m_hwndParent, WM_USER + 100, 0, 0); // clean up tooltip + TabCtrl_DeleteItem(m_hwndParent, i); + m_pContainer->UpdateTabs(); + m_iTabID = -1; + } + if (m_pWnd) { + delete m_pWnd; + m_pWnd = 0; + } + if (m_sbCustom) { + delete m_sbCustom; + m_sbCustom = 0; + } - if ((wParam == VK_PRIOR && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && isShift)) { // CTRL_SHIFT-TAB (switch tab/window) - SendMessage(pDlg->m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_PREV, 0); - return TRUE; - } - if (wParam == VK_TAB && !isCtrl && !isShift) { // tab-autocomplete - SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); - bool fCompleted = TabAutoComplete(hwnd, dat, pDlg->m_si); - SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); - RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE); - if (!fCompleted && !PluginConfig.m_bAllowTab) { - if ((GetSendButtonState(pDlg->GetHwnd()) != PBS_DISABLED)) - SetFocus(GetDlgItem(pDlg->GetHwnd(), IDOK)); - else - SetFocus(GetDlgItem(pDlg->GetHwnd(), IDC_LOG)); - } - return 0; - } - if (wParam != VK_RIGHT && wParam != VK_LEFT) { - mir_free(dat->szSearchQuery); - dat->szSearchQuery = nullptr; - mir_free(dat->szSearchResult); - dat->szSearchResult = nullptr; - } + M.RemoveWindow(m_hwnd); - if (wParam == VK_F4 && isCtrl && !isAlt) { // ctrl-F4 (close tab) - SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CLOSE, BN_CLICKED), 0); - return 0; - } + FireEvent(MSG_WINDOW_EVT_CLOSE, 0); - if (wParam == VK_NEXT || wParam == VK_PRIOR) { - HWND htemp = hwndParent; - SendDlgItemMessage(htemp, IDC_LOG, msg, wParam, lParam); - dat->lastEnterTime = 0; - return 0; - } + m_pContainer->ClearMargins(); + PostMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 1); - if (wParam == VK_UP && isCtrl && !isAlt) { - char *lpPrevCmd = pci->SM_GetPrevCommand(pDlg->m_si->ptszID, pDlg->m_si->pszModule); + if (m_pContainer->dwFlags & CNT_SIDEBAR) + m_pContainer->SideBar->removeSession(this); + mir_free(m_enteredText); - if (!pDlg->m_si->lpCurrentCommand || !pDlg->m_si->lpCurrentCommand->last) { - // Next command is not defined. It means currently entered text is not saved in the history and it - // need to be saved in the window context. - char *enteredText = Message_GetFromStream(hwndParent); - if (pDlg->m_enteredText) - mir_free(pDlg->m_enteredText); + CSuper::OnDestroy(); +} - pDlg->m_enteredText = enteredText; - } +void CChatRoomDlg::onClick_OK(CCtrlButton*) +{ + if (GetSendButtonState(m_hwnd) == PBS_DISABLED) + return; - SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule); + if (mi == nullptr) + return; - LOGFONTA lf; - LoadLogfont(FONTSECTION_IM, MSGFONTID_MESSAGEAREA, &lf, nullptr, FONTMODULE); + ptrA pszRtf(Message_GetFromStream(m_message.GetHwnd())); + pci->SM_AddCommand(m_si->ptszID, m_si->pszModule, pszRtf); - SETTEXTEX ste; - ste.flags = ST_DEFAULT; - ste.codepage = CP_ACP; - if (lpPrevCmd) - SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd); - else - SetWindowText(hwnd, L""); + CMStringW ptszText(ptrW(mir_utf8decodeW(pszRtf))); + if (ptszText.IsEmpty()) + return; - GETTEXTLENGTHEX gtl = { 0 }; - gtl.flags = GTL_PRECISE; - gtl.codepage = CP_ACP; - int iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); - SendMessage(hwnd, EM_SCROLLCARET, 0, 0); - SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); - RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE); - SendMessage(hwnd, EM_SETSEL, iLen, iLen); - dat->lastEnterTime = 0; - return 0; - } + DoRtfToTags(ptszText, mi->nColorCount, mi->crColors); + ptszText.Trim(); + ptszText.Replace(L"%", L"%%"); - if (wParam == VK_DOWN && isCtrl && !isAlt) { - SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + if (mi->bAckMsg) { + Utils::enableDlgControl(m_hwnd, IDC_MESSAGE, false); + m_message.SendMsg(EM_SETREADONLY, TRUE, 0); + } + else SetDlgItemText(m_hwnd, IDC_MESSAGE, L""); - SETTEXTEX ste; - ste.flags = ST_DEFAULT; - ste.codepage = CP_ACP; + Utils::enableDlgControl(m_hwnd, IDOK, false); - char *lpPrevCmd = pci->SM_GetNextCommand(pDlg->m_si->ptszID, pDlg->m_si->pszModule); - if (lpPrevCmd) - SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd); - else if (pDlg->m_enteredText) { - // If we cannot load the message from history, load the last edited text. - SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)pDlg->m_enteredText); - mir_free(pDlg->m_enteredText); - pDlg->m_enteredText = nullptr; - } + // Typing support for GCW_PRIVMESS sessions + if (m_si->iType == GCW_PRIVMESS) + if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) + DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF); - GETTEXTLENGTHEX gtl = { 0 }; - gtl.flags = GTL_PRECISE; - gtl.codepage = CP_ACP; - int iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); - SendMessage(hwnd, EM_SCROLLCARET, 0, 0); - SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); - RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE); - SendMessage(hwnd, EM_SETSEL, iLen, iLen); - dat->lastEnterTime = 0; - return 0; - } - // fall through + bool fSound = true; + if (ptszText[0] == '/' || m_si->iType == GCW_SERVER) + fSound = false; + DoEventHook(GC_USER_MESSAGE, nullptr, ptszText, 0); + mi->idleTimeStamp = time(0); + mi->lastIdleCheck = 0; + UpdateStatusBar(); + if (m_pContainer) + if (fSound && !nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND)) + SkinPlaySound("ChatSent"); - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_KILLFOCUS: - dat->lastEnterTime = 0; - break; + SetFocus(m_message.GetHwnd()); +} - case WM_KEYUP: - case WM_LBUTTONUP: - case WM_RBUTTONUP: - case WM_MBUTTONUP: - pDlg->RefreshButtonStatus(); - break; +void CChatRoomDlg::onClick_Filter(CCtrlButton *pButton) +{ + if (!pButton->Enabled()) + return; - case WM_INPUTLANGCHANGE: - if (PluginConfig.m_bAutoLocaleSupport && GetFocus() == hwnd && pDlg->m_pContainer->m_hwndActive == hwndParent && GetForegroundWindow() == pDlg->m_pContainer->m_hwnd && GetActiveWindow() == pDlg->m_pContainer->m_hwnd) { - pDlg->DM_SaveLocale(wParam, lParam); - SendMessage(hwnd, EM_SETLANGOPTIONS, 0, (LPARAM)SendMessage(hwnd, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); - return 1; - } - break; + if (m_iLogFilterFlags == 0 && !m_bFilterEnabled) { + MessageBox(0, TranslateT("The filter cannot be enabled, because there are no event types selected either global or for this chat room"), TranslateT("Event filter error"), MB_OK); + m_bFilterEnabled = false; + } + else m_bFilterEnabled = !m_bFilterEnabled; - case WM_ERASEBKGND: - return !CSkin::m_skinEnabled; + m_btnFilter.SendMsg(BUTTONSETOVERLAYICON, (LPARAM)(m_bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled), 0); - case WM_DESTROY: - mir_free(dat); + if (m_bFilterEnabled && M.GetByte(CHAT_MODULE, "RightClickFilter", 0) == 0) { + ShowFilterMenu(); + return; } - - return mir_callNextSubclass(hwnd, MessageSubclassProc, msg, wParam, lParam); + RedrawLog(); + UpdateTitle(); + db_set_b(m_si->hContact, CHAT_MODULE, "FilterEnabled", m_bFilterEnabled); } -///////////////////////////////////////////////////////////////////////////////////////// -// subclassing for the message filter dialog (set and configure event filters for the -// current session - -static UINT _eventorder[] = +void CChatRoomDlg::onClick_ShowNickList(CCtrlButton *pButton) { - GC_EVENT_ACTION, - GC_EVENT_MESSAGE, - GC_EVENT_NICK, - GC_EVENT_JOIN, - GC_EVENT_PART, - GC_EVENT_TOPIC, - GC_EVENT_ADDSTATUS, - GC_EVENT_INFORMATION, - GC_EVENT_QUIT, - GC_EVENT_KICK, - GC_EVENT_NOTICE -}; + if (!pButton->Enabled() || m_si->iType == GCW_SERVER) + return; -INT_PTR CALLBACK CChatRoomDlg::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - CChatRoomDlg *pDlg = (CChatRoomDlg*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - switch (uMsg) { - case WM_INITDIALOG: - pDlg = (CChatRoomDlg*)lParam; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - { - DWORD dwMask = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "FilterMask", 0); - DWORD dwFlags = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "FilterFlags", 0); + m_bNicklistEnabled = !m_bNicklistEnabled; - DWORD dwPopupMask = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "PopupMask", 0); - DWORD dwPopupFlags = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "PopupFlags", 0); + SendMessage(m_hwnd, WM_SIZE, 0, 0); + if (CSkin::m_skinEnabled) + InvalidateRect(m_hwnd, nullptr, TRUE); + ScrollToBottom(); +} - DWORD dwTrayMask = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconMask", 0); - DWORD dwTrayFlags = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconFlags", 0); +void CChatRoomDlg::onChange_Message(CCtrlEdit*) +{ + if (m_pContainer->m_hwndActive == m_hwnd) + UpdateReadChars(); + m_dwLastActivity = GetTickCount(); + m_pContainer->dwLastActivity = m_dwLastActivity; + m_btnOk.SendMsg(BUTTONSETASNORMAL, GetRichTextLength(m_message.GetHwnd()) != 0, 0); + m_btnOk.Enable(GetRichTextLength(m_message.GetHwnd()) != 0); - for (int i = 0; i < _countof(_eventorder); i++) { - CheckDlgButton(hwndDlg, IDC_1 + i, dwMask & _eventorder[i] ? (dwFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); - CheckDlgButton(hwndDlg, IDC_P1 + i, dwPopupMask & _eventorder[i] ? (dwPopupFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); - CheckDlgButton(hwndDlg, IDC_T1 + i, dwTrayMask & _eventorder[i] ? (dwTrayFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); + // Typing support for GCW_PRIVMESS sessions + if (m_si->iType == GCW_PRIVMESS) { + if (!(GetKeyState(VK_CONTROL) & 0x8000)) { + m_nLastTyping = GetTickCount(); + if (GetWindowTextLength(m_message.GetHwnd())) { + if (m_nTypeMode == PROTOTYPE_SELFTYPING_OFF) { + if (!(m_dwFlags & MWF_INITMODE)) + DM_NotifyTyping(PROTOTYPE_SELFTYPING_ON); + } } + else if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) + DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF); } - return FALSE; - - case WM_CTLCOLOREDIT: - case WM_CTLCOLORSTATIC: - SetTextColor((HDC)wParam, RGB(60, 60, 150)); - SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + } +} - case WM_CLOSE: - if (wParam == 1 && lParam == 1) { - int iFlags = 0, i; - DWORD dwMask = 0; +///////////////////////////////////////////////////////////////////////////////////////// - for (i = 0; i < _countof(_eventorder); i++) { - int result = IsDlgButtonChecked(hwndDlg, IDC_1 + i); - dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); - iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); - } +void CChatRoomDlg::AddLog() +{ + if (PluginConfig.m_bUseDividers) { + if (PluginConfig.m_bDividersUsePopupConfig) { + if (!MessageWindowOpened(0, (LPARAM)m_hwnd)) + DM_AddDivider(); + } + else { + bool bInactive = (GetForegroundWindow() != m_pContainer->m_hwnd || GetActiveWindow() != m_pContainer->m_hwnd); + if (bInactive) + DM_AddDivider(); + else if (m_pContainer->m_hwndActive != m_hwnd) + DM_AddDivider(); + } + } - if (iFlags & GC_EVENT_ADDSTATUS) - iFlags |= GC_EVENT_REMOVESTATUS; + CSrmmBaseDialog::AddLog(); +} - if (pDlg) { - if (dwMask == 0) { - db_unset(pDlg->m_hContact, CHAT_MODULE, "FilterFlags"); - db_unset(pDlg->m_hContact, CHAT_MODULE, "FilterMask"); - } - else { - db_set_dw(pDlg->m_hContact, CHAT_MODULE, "FilterFlags", iFlags); - db_set_dw(pDlg->m_hContact, CHAT_MODULE, "FilterMask", dwMask); - } - } - - dwMask = iFlags = 0; +void CChatRoomDlg::CloseTab() +{ + int iTabs = TabCtrl_GetItemCount(m_hwndParent); + if (iTabs == 1 && CMimAPI::m_shutDown == 0) { + SendMessage(m_pContainer->m_hwnd, WM_CLOSE, 0, 1); + return; + } - for (i = 0; i < _countof(_eventorder); i++) { - int result = IsDlgButtonChecked(hwndDlg, IDC_P1 + i); - dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); - iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); - } + m_pContainer->iChilds--; + int i = GetTabIndexFromHWND(m_hwndParent, m_hwnd); - if (iFlags & GC_EVENT_ADDSTATUS) - iFlags |= GC_EVENT_REMOVESTATUS; + // after closing a tab, we need to activate the tab to the left side of + // the previously open tab. + // normally, this tab has the same index after the deletion of the formerly active tab + // unless, of course, we closed the last (rightmost) tab. + if (!m_pContainer->bDontSmartClose && iTabs > 1) { + if (i == iTabs - 1) + i--; + else + i++; + TabCtrl_SetCurSel(m_hwndParent, i); - if (pDlg) { - if (dwMask == 0) { - db_unset(pDlg->m_hContact, CHAT_MODULE, "PopupFlags"); - db_unset(pDlg->m_hContact, CHAT_MODULE, "PopupMask"); - } - else { - db_set_dw(pDlg->m_hContact, CHAT_MODULE, "PopupFlags", iFlags); - db_set_dw(pDlg->m_hContact, CHAT_MODULE, "PopupMask", dwMask); - } - } + TCITEM item = {}; + item.mask = TCIF_PARAM; + TabCtrl_GetItem(m_hwndParent, i, &item); // retrieve dialog hwnd for the now active tab... + m_pContainer->m_hwndActive = (HWND)item.lParam; - dwMask = iFlags = 0; + RECT rc; + SendMessage(m_pContainer->m_hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); + SetWindowPos(m_pContainer->m_hwndActive, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), SWP_SHOWWINDOW); + ShowWindow((HWND)item.lParam, SW_SHOW); + SetForegroundWindow(m_pContainer->m_hwndActive); + SetFocus(m_pContainer->m_hwndActive); + SendMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 0); + } - for (i = 0; i < _countof(_eventorder); i++) { - int result = IsDlgButtonChecked(hwndDlg, IDC_T1 + i); - dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); - iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); - } - if (iFlags & GC_EVENT_ADDSTATUS) - iFlags |= GC_EVENT_REMOVESTATUS; + if (iTabs == 1) + SendMessage(m_pContainer->m_hwnd, WM_CLOSE, 0, 1); + else { + PostMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 0); + DestroyWindow(m_hwnd); + } +} - if (pDlg) { - if (dwMask == 0) { - db_unset(pDlg->m_hContact, CHAT_MODULE, "TrayIconFlags"); - db_unset(pDlg->m_hContact, CHAT_MODULE, "TrayIconMask"); - } - else { - db_set_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconFlags", iFlags); - db_set_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconMask", dwMask); - } - Chat_SetFilters(pDlg->m_si); - if (pDlg->m_iLogFilterFlags == 0 && pDlg->m_bFilterEnabled) - pDlg->onClick_Filter(&pDlg->m_btnFilter); - if (pDlg->m_bFilterEnabled) - pDlg->RedrawLog(); +void CChatRoomDlg::RedrawLog() +{ + m_si->LastTime = 0; + if (m_si->pLog) { + LOGINFO *pLog = m_si->pLog; + if (m_si->iEventCount > 60) { + int index = 0; + while (index < 59) { + if (pLog->next == nullptr) + break; + pLog = pLog->next; + if ((m_si->iType != GCW_CHATROOM && m_si->iType != GCW_PRIVMESS) || !m_bFilterEnabled || (m_iLogFilterFlags & pLog->iType) != 0) + index++; } + StreamInEvents(pLog, TRUE); + mir_forkthread(phase2, m_si); } - DestroyWindow(hwndDlg); - break; - - case WM_DESTROY: - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); - break; + else StreamInEvents(m_si->pLogEnd, TRUE); } - return FALSE; + else ClearLog(); } -///////////////////////////////////////////////////////////////////////////////////////// -// subclassing for the message history display(rich edit control in which the chat history appears) - -static LRESULT CALLBACK LogSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +void CChatRoomDlg::ScrollToBottom() { - HWND hwndParent = GetParent(hwnd); - CChatRoomDlg *pDlg = (CChatRoomDlg*)GetWindowLongPtr(hwndParent, GWLP_USERDATA); - - switch (msg) { - case WM_NCCALCSIZE: - return CSkin::NcCalcRichEditFrame(hwnd, pDlg, ID_EXTBKHISTORY, msg, wParam, lParam, LogSubclassProc); - - case WM_NCPAINT: - return CSkin::DrawRichEditFrame(hwnd, pDlg, ID_EXTBKHISTORY, msg, wParam, lParam, LogSubclassProc); - - case WM_COPY: - return Utils::WMCopyHandler(hwnd, LogSubclassProc, msg, wParam, lParam); - - case WM_SETCURSOR: - if (g_Settings.bClickableNicks && (LOWORD(lParam) == HTCLIENT)) { - POINT pt; - GetCursorPos(&pt); - ScreenToClient(hwnd, &pt); - if (CheckCustomLink(hwnd, &pt, msg, wParam, lParam, FALSE)) return TRUE; - } - break; - - case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_RBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - if (g_Settings.bClickableNicks) { - POINT pt = { LOWORD(lParam), HIWORD(lParam) }; - CheckCustomLink(hwnd, &pt, msg, wParam, lParam, TRUE); - } - break; + DM_ScrollToBottom(0, 0); +} - case WM_LBUTTONUP: - if (g_Settings.bClickableNicks) { - POINT pt = { LOWORD(lParam), HIWORD(lParam) }; - CheckCustomLink(hwnd, &pt, msg, wParam, lParam, TRUE); - } - if (M.GetByte("autocopy", 1)) { - CHARRANGE sel; - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - if (sel.cpMin != sel.cpMax) { - SendMessage(hwnd, WM_COPY, 0, 0); - sel.cpMin = sel.cpMax; - SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); - SetFocus(GetDlgItem(hwndParent, IDC_MESSAGE)); - } - } - break; +void CChatRoomDlg::ShowFilterMenu() +{ + m_hwndFilter = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), m_pContainer->m_hwnd, FilterWndProc, (LPARAM)this); + TranslateDialogDefault(m_hwndFilter); - case WM_KEYDOWN: - if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) - PostMessage(hwndParent, WM_CLOSE, 0, 1); - return TRUE; - } - if (wParam == VK_INSERT && GetKeyState(VK_CONTROL) & 0x8000) - return Utils::WMCopyHandler(hwnd, LogSubclassProc, msg, wParam, lParam); - break; + RECT rcFilter, rcLog; + GetClientRect(m_hwndFilter, &rcFilter); + GetWindowRect(m_log.GetHwnd(), &rcLog); - case WM_SYSKEYUP: - if (wParam == VK_MENU) { - ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_LOG); - return 0; - } - break; + POINT pt; + pt.x = rcLog.right; pt.y = rcLog.bottom; + ScreenToClient(m_pContainer->m_hwnd, &pt); - case WM_SYSKEYDOWN: - pDlg->m_bkeyProcessed = false; - if (ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_LOG)) { - pDlg->m_bkeyProcessed = true; - return 0; - } - break; + SetWindowPos(m_hwndFilter, HWND_TOP, pt.x - rcFilter.right, pt.y - rcFilter.bottom, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); +} - case WM_SYSCHAR: - if (pDlg->m_bkeyProcessed) { - pDlg->m_bkeyProcessed = false; - return 0; - } - break; +void CChatRoomDlg::UpdateNickList() +{ + int i = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0); + m_nickList.SendMsg(LB_SETCOUNT, m_si->nUsersInNicklist, 0); + m_nickList.SendMsg(LB_SETTOPINDEX, i, 0); + UpdateTitle(); + m_hTabIcon = m_hTabStatusIcon; +} - case WM_ACTIVATE: - if (LOWORD(wParam) == WA_INACTIVE) { - CHARRANGE sel; - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - if (sel.cpMin != sel.cpMax) { - sel.cpMin = sel.cpMax; - SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel); - } - } - break; +void CChatRoomDlg::UpdateOptions() +{ + MODULEINFO *pInfo = m_si ? pci->MM_FindModule(m_si->pszModule) : nullptr; + if (pInfo) { + m_btnBold.Enable(pInfo->bBold); + m_btnItalic.Enable(pInfo->bItalics); + m_btnUnderline.Enable(pInfo->bUnderline); + m_btnColor.Enable(pInfo->bColor); + m_btnBkColor.Enable(pInfo->bBkgColor); + if (m_si->iType == GCW_CHATROOM) + m_btnChannelMgr.Enable(pInfo->bChanMgr); + } + m_log.SendMsg(EM_SETBKGNDCOLOR, 0, M.GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR)); - case WM_CHAR: - bool isCtrl, isShift, isAlt; - pDlg->KbdState(isShift, isCtrl, isAlt); - if (wParam == 0x03 && isCtrl) // Ctrl+C - return Utils::WMCopyHandler(hwnd, LogSubclassProc, msg, wParam, lParam); + DM_InitRichEdit(); + m_btnOk.SendMsg(BUTTONSETASNORMAL, TRUE, 0); - SetFocus(GetDlgItem(hwndParent, IDC_MESSAGE)); - SendDlgItemMessage(hwndParent, IDC_MESSAGE, WM_CHAR, wParam, lParam); - break; - } + m_nickList.SetItemHeight(0, g_Settings.iNickListFontHeight); + InvalidateRect(m_nickList.GetHwnd(), nullptr, TRUE); - return mir_callNextSubclass(hwnd, LogSubclassProc, msg, wParam, lParam); + m_btnFilter.SendMsg(BUTTONSETOVERLAYICON, (LPARAM)(m_bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled), 0); + SendMessage(m_hwnd, WM_SIZE, 0, 0); + RedrawLog2(); } -///////////////////////////////////////////////////////////////////////////////////////// -// subclassing for the nickname list control.It is an ownerdrawn listbox - -LRESULT CALLBACK CChatRoomDlg::NicklistSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +void CChatRoomDlg::UpdateStatusBar() { - HWND hwndParent = GetParent(hwnd); - CChatRoomDlg *dat = (CChatRoomDlg*)GetWindowLongPtr(hwndParent, GWLP_USERDATA); - - switch (msg) { - case WM_NCCALCSIZE: - if (CSkin::m_DisableScrollbars) { - RECT lpRect; - GetClientRect(hwnd, &lpRect); - LONG itemHeight = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0); - g_cLinesPerPage = (lpRect.bottom - lpRect.top) / itemHeight; - } - return CSkin::NcCalcRichEditFrame(hwnd, dat, ID_EXTBKUSERLIST, msg, wParam, lParam, NicklistSubclassProc); + if (m_pContainer->m_hwndActive != m_hwnd || m_pContainer->hwndStatus == 0 || CMimAPI::m_shutDown || m_wszStatusBar[0]) + return; - case WM_NCPAINT: - return CSkin::DrawRichEditFrame(hwnd, dat, ID_EXTBKUSERLIST, msg, wParam, lParam, NicklistSubclassProc); + if (m_si->pszModule == nullptr) + return; - case WM_ERASEBKGND: - { - HDC dc = (HDC)wParam; - if (dc) { - int index = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0); - if (index == LB_ERR || dat->m_si->nUsersInNicklist <= 0) - return 0; + //Mad: strange rare crash here... + MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule); + if (!mi) + return; - int items = dat->m_si->nUsersInNicklist - index; - int height = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0); + if (!mi->ptszModDispName) + return; - if (height != LB_ERR) { - RECT rc = { 0 }; - GetClientRect(hwnd, &rc); + int x = 12; + x += GetTextPixelSize(mi->ptszModDispName, (HFONT)SendMessage(m_pContainer->hwndStatus, WM_GETFONT, 0, 0), TRUE); + x += GetSystemMetrics(SM_CXSMICON); - if (rc.bottom - rc.top > items * height) { - rc.top = items * height; - FillRect(dc, &rc, pci->hListBkgBrush); - } - } + wchar_t szFinalStatusBarText[512]; + if (m_pPanel.isActive()) { + time_t now = time(0); + DWORD diff = (now - mi->idleTimeStamp) / 60; + + if ((diff >= 1 && diff != mi->lastIdleCheck)) { + mi->lastIdleCheck = diff; + if (diff > 59) { + DWORD hours = diff / 60; + DWORD minutes = diff % 60; + mir_snwprintf(mi->tszIdleMsg, TranslateT(", %d %s, %d %s idle"), + hours, hours > 1 ? TranslateT("hours") : TranslateT("hour"), + minutes, minutes > 1 ? TranslateT("minutes") : TranslateT("minute")); } + else mir_snwprintf(mi->tszIdleMsg, TranslateT(", %d %s idle"), diff, diff > 1 ? TranslateT("minutes") : TranslateT("minute")); } - return 1; + mir_snwprintf(szFinalStatusBarText, TranslateT("%s on %s%s"), m_wszMyNickname, mi->ptszModDispName, mi->tszIdleMsg); + } + else { + if (m_si->ptszStatusbarText) + mir_snwprintf(szFinalStatusBarText, L"%s %s", mi->ptszModDispName, m_si->ptszStatusbarText); + else + wcsncpy_s(szFinalStatusBarText, mi->ptszModDispName, _TRUNCATE); + } + SendMessage(m_pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szFinalStatusBarText); + tabUpdateStatusBar(); + m_pPanel.Invalidate(); + if (m_pWnd) + m_pWnd->Invalidate(); +} - case WM_MOUSEWHEEL: - if (CSkin::m_DisableScrollbars) { - UINT uScroll; - short zDelta = (short)HIWORD(wParam); - if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uScroll, 0)) - uScroll = 3; /* default value */ +void CChatRoomDlg::UpdateTitle() +{ + m_wStatus = m_si->wStatus; - if (uScroll == WHEEL_PAGESCROLL) - uScroll = g_cLinesPerPage; - if (uScroll == 0) - return 0; + const wchar_t *szNick = m_cache->getNick(); + if (mir_wstrlen(szNick) > 0) { + if (M.GetByte("cuttitle", 0)) + CutContactName(szNick, m_wszTitle, _countof(m_wszTitle)); + else + wcsncpy_s(m_wszTitle, szNick, _TRUNCATE); + } - zDelta += g_iWheelCarryover; /* Accumulate wheel motion */ + wchar_t szTemp[100]; + HICON hIcon = 0; - int dLines = zDelta * (int)uScroll / WHEEL_DELTA; + switch (m_si->iType) { + case GCW_CHATROOM: + hIcon = Skin_LoadProtoIcon(m_si->pszModule, (m_wStatus <= ID_STATUS_OFFLINE) ? ID_STATUS_OFFLINE : m_wStatus); + mir_snwprintf(szTemp, + (m_si->nUsersInNicklist == 1) ? TranslateT("%s: chat room (%u user%s)") : TranslateT("%s: chat room (%u users%s)"), + szNick, m_si->nUsersInNicklist, m_bFilterEnabled ? TranslateT(", event filter active") : L""); + break; + case GCW_PRIVMESS: + hIcon = Skin_LoadProtoIcon(m_si->pszModule, (m_wStatus <= ID_STATUS_OFFLINE) ? ID_STATUS_OFFLINE : m_wStatus); + if (m_si->nUsersInNicklist == 1) + mir_snwprintf(szTemp, TranslateT("%s: message session"), szNick); + else + mir_snwprintf(szTemp, TranslateT("%s: message session (%u users)"), szNick, m_si->nUsersInNicklist); + break; + case GCW_SERVER: + mir_snwprintf(szTemp, L"%s: Server", szNick); + hIcon = LoadIconEx("window"); + break; + } - //Record the unused portion as the next carryover. - g_iWheelCarryover = zDelta - dLines * WHEEL_DELTA / (int)uScroll; + if (m_pWnd) { + m_pWnd->updateTitle(m_wszTitle); + m_pWnd->updateIcon(hIcon); + } + m_hTabStatusIcon = hIcon; - // scrolling. - while (abs(dLines)) { - if (dLines > 0) { - SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); - dLines--; - } - else { - SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); - dLines++; - } + if (m_cache->getStatus() != m_cache->getOldStatus()) { + wcsncpy_s(m_wszStatus, pcli->pfnGetStatusModeDescription(m_wStatus, 0), _TRUNCATE); + + TCITEM item = {}; + item.mask = TCIF_TEXT; + item.pszText = m_wszTitle; + TabCtrl_SetItem(m_hwndParent, m_iTabID, &item); + } + SetWindowText(m_hwnd, szTemp); + if (m_pContainer->m_hwndActive == m_hwnd) { + m_pContainer->UpdateTitle(0, this); + UpdateStatusBar(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// subclassing for the message history display(rich edit control in which the chat history appears) + +LRESULT CChatRoomDlg::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_NCCALCSIZE: + return CSkin::NcCalcRichEditFrame(m_log.GetHwnd(), this, ID_EXTBKHISTORY, msg, wParam, lParam, nullptr); + + case WM_NCPAINT: + return CSkin::DrawRichEditFrame(m_log.GetHwnd(), this, ID_EXTBKHISTORY, msg, wParam, lParam, nullptr); + + case WM_COPY: + return Utils::WMCopyHandler(m_log.GetHwnd(), nullptr, msg, wParam, lParam); + + case WM_SETCURSOR: + if (g_Settings.bClickableNicks && (LOWORD(lParam) == HTCLIENT)) { + POINT pt; + GetCursorPos(&pt); + ScreenToClient(m_log.GetHwnd(), &pt); + if (CheckCustomLink(m_log.GetHwnd(), &pt, msg, wParam, lParam, FALSE)) return TRUE; + } + break; + + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + if (g_Settings.bClickableNicks) { + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + CheckCustomLink(m_log.GetHwnd(), &pt, msg, wParam, lParam, TRUE); + } + break; + + case WM_LBUTTONUP: + if (g_Settings.bClickableNicks) { + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + CheckCustomLink(m_log.GetHwnd(), &pt, msg, wParam, lParam, TRUE); + } + if (M.GetByte("autocopy", 1)) { + CHARRANGE sel; + SendMessage(m_log.GetHwnd(), EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin != sel.cpMax) { + SendMessage(m_log.GetHwnd(), WM_COPY, 0, 0); + sel.cpMin = sel.cpMax; + SendMessage(m_log.GetHwnd(), EM_EXSETSEL, 0, (LPARAM)&sel); + SetFocus(m_message.GetHwnd()); } - return 0; } break; case WM_KEYDOWN: if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) - PostMessage(hwndParent, WM_CLOSE, 0, 1); + PostMessage(m_hwnd, WM_CLOSE, 0, 1); return TRUE; } + if (wParam == VK_INSERT && GetKeyState(VK_CONTROL) & 0x8000) + return Utils::WMCopyHandler(m_log.GetHwnd(), nullptr, msg, wParam, lParam); + break; - if (wParam == VK_ESCAPE || wParam == VK_UP || wParam == VK_DOWN || wParam == VK_NEXT || - wParam == VK_PRIOR || wParam == VK_TAB || wParam == VK_HOME || wParam == VK_END) { - if (dat) { - dat->m_wszSearch[0] = 0; - dat->m_iSearchItem = -1; - } + case WM_SYSKEYUP: + if (wParam == VK_MENU) { + ProcessHotkeysByMsgFilter(m_log.GetHwnd(), msg, wParam, lParam, IDC_LOG); + return 0; } break; - case WM_SETFOCUS: - case WM_KILLFOCUS: - if (dat) { // set/kill focus invalidates incremental search status - dat->m_wszSearch[0] = 0; - dat->m_iSearchItem = -1; + case WM_SYSKEYDOWN: + m_bkeyProcessed = false; + if (ProcessHotkeysByMsgFilter(m_log.GetHwnd(), msg, wParam, lParam, IDC_LOG)) { + m_bkeyProcessed = true; + return 0; } break; - case WM_CHAR: - case WM_UNICHAR: - // simple incremental search for the user (nick) - list control - // typing esc or movement keys will clear the current search string - if (dat) { - if (wParam == 27 && dat->m_wszSearch[0]) { // escape - reset everything - dat->m_wszSearch[0] = 0; - dat->m_iSearchItem = -1; - break; - } - if (wParam == '\b' && dat->m_wszSearch[0]) // backspace - dat->m_wszSearch[mir_wstrlen(dat->m_wszSearch) - 1] = '\0'; - else if (wParam < ' ') - break; - else { - if (mir_wstrlen(dat->m_wszSearch) >= _countof(dat->m_wszSearch) - 2) { - MessageBeep(MB_OK); - break; - } - wchar_t szNew[2]; - szNew[0] = (wchar_t)wParam; - szNew[1] = '\0'; - mir_wstrcat(dat->m_wszSearch, szNew); - } - if (dat->m_wszSearch[0]) { - // iterate over the (sorted) list of nicknames and search for the - // string we have - int i, iItems = SendMessage(hwnd, LB_GETCOUNT, 0, 0); - for (i = 0; i < iItems; i++) { - USERINFO *ui = pci->UM_FindUserFromIndex(dat->m_si->pUsers, i); - if (ui) { - if (!wcsnicmp(ui->pszNick, dat->m_wszSearch, mir_wstrlen(dat->m_wszSearch))) { - SendMessage(hwnd, LB_SETSEL, FALSE, -1); - SendMessage(hwnd, LB_SETSEL, TRUE, i); - dat->m_iSearchItem = i; - InvalidateRect(hwnd, nullptr, FALSE); - return 0; - } - } - } - if (i == iItems) { - MessageBeep(MB_OK); - dat->m_wszSearch[mir_wstrlen(dat->m_wszSearch) - 1] = '\0'; - return 0; - } - } + case WM_SYSCHAR: + if (m_bkeyProcessed) { + m_bkeyProcessed = false; + return 0; } break; - case WM_RBUTTONDOWN: - { - int iCounts = SendMessage(hwnd, LB_GETSELCOUNT, 0, 0); - if (iCounts != LB_ERR && iCounts > 1) - return 0; - SendMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam); + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_INACTIVE) { + CHARRANGE sel; + SendMessage(m_log.GetHwnd(), EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin != sel.cpMax) { + sel.cpMin = sel.cpMax; + SendMessage(m_log.GetHwnd(), EM_EXSETSEL, 0, (LPARAM)&sel); + } } break; - case WM_RBUTTONUP: - SendMessage(hwnd, WM_LBUTTONUP, wParam, lParam); + case WM_CHAR: + bool isCtrl, isShift, isAlt; + KbdState(isShift, isCtrl, isAlt); + if (wParam == 0x03 && isCtrl) // Ctrl+C + return Utils::WMCopyHandler(m_log.GetHwnd(), nullptr, msg, wParam, lParam); + + SetFocus(m_message.GetHwnd()); + m_message.SendMsg(WM_CHAR, wParam, lParam); break; + } - case WM_MEASUREITEM: - { - MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam; - if (mis->CtlType == ODT_MENU) - return Menu_MeasureItem(lParam); - } - return FALSE; + return 0; +} - case WM_DRAWITEM: - { - DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam; - if (dis->CtlType == ODT_MENU) - return Menu_DrawItem(lParam); - } - return FALSE; +///////////////////////////////////////////////////////////////////////////////////////// +// subclassing for the message input control(a richedit text control) + +LRESULT CChatRoomDlg::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (m_bkeyProcessed && (msg == WM_KEYUP)) { + GetKeyboardState(kstate); + if (!(kstate[VK_CONTROL] & 0x80) && !(kstate[VK_SHIFT] & 0x80)) + m_bkeyProcessed = false; + return 0; + } + + switch (msg) { + case WM_NCCALCSIZE: + return CSkin::NcCalcRichEditFrame(m_message.GetHwnd(), this, ID_EXTBKINPUTAREA, msg, wParam, lParam, nullptr); + + case WM_NCPAINT: + return CSkin::DrawRichEditFrame(m_message.GetHwnd(), this, ID_EXTBKINPUTAREA, msg, wParam, lParam, nullptr); case WM_CONTEXTMENU: + POINT pt; + GetCursorPos(&pt); { - SESSION_INFO *si = dat->m_si; - if (si == nullptr) - break; + HMENU hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT)); + HMENU hSubMenu = GetSubMenu(hMenu, 2); + RemoveMenu(hSubMenu, 9, MF_BYPOSITION); + RemoveMenu(hSubMenu, 8, MF_BYPOSITION); + RemoveMenu(hSubMenu, 4, MF_BYPOSITION); - int height = 0; - TVHITTESTINFO hti; - hti.pt.x = GET_X_LPARAM(lParam); - hti.pt.y = GET_Y_LPARAM(lParam); - if (hti.pt.x == -1 && hti.pt.y == -1) { - int index = SendMessage(hwnd, LB_GETCURSEL, 0, 0); - int top = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0); - height = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0); - hti.pt.x = 4; - hti.pt.y = (index - top) * height + 1; + MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule); + EnableMenuItem(hSubMenu, IDM_PASTEFORMATTED, MF_BYCOMMAND | ((mi && mi->bBold) ? MF_ENABLED : MF_GRAYED)); + TranslateMenu(hSubMenu); + + CHARRANGE sel, all = { 0, -1 }; + m_message.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) { + EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(hSubMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED); } - else ScreenToClient(hwnd, &hti.pt); - int item = (DWORD)(SendMessage(hwnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y))); - if (HIWORD(item) == 1) - item = (DWORD)(-1); - else - item &= 0xFFFF; + MessageWindowPopupData mwpd = { sizeof(mwpd) }; + mwpd.uType = MSG_WINDOWPOPUP_SHOWING; + mwpd.uFlags = MSG_WINDOWPOPUP_INPUT; + mwpd.hContact = m_hContact; + mwpd.hwnd = m_message.GetHwnd(); + mwpd.hMenu = hSubMenu; + mwpd.pt = pt; + NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd); - USERINFO *ui = pci->SM_GetUserFromIndex(si->ptszID, si->pszModule, item); - if (ui) { - HMENU hMenu = 0; - USERINFO uinew; - memcpy(&uinew, ui, sizeof(USERINFO)); - if (hti.pt.x == -1 && hti.pt.y == -1) - hti.pt.y += height - 4; - ClientToScreen(hwnd, &hti.pt); + int iSelection = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_hwnd, nullptr); - UINT uID = CreateGCMenu(hwnd, &hMenu, 0, hti.pt, si, uinew.pszUID, uinew.pszNick); - switch (uID) { - case 0: - break; + mwpd.selection = iSelection; + mwpd.uType = MSG_WINDOWPOPUP_SELECTED; + NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd); - case 20020: // add to highlight... - { - THighLightEdit the = { THighLightEdit::CMD_ADD, si, ui }; - HWND hwndDlg = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ADDHIGHLIGHT), dat->m_pContainer->m_hwnd, CMUCHighlight::dlgProcAdd, (LPARAM)&the); - TranslateDialogDefault(hwndDlg); + switch (iSelection) { + case IDM_COPY: + m_message.SendMsg(WM_COPY, 0, 0); + break; + case IDM_CUT: + m_message.SendMsg(WM_CUT, 0, 0); + break; + case IDM_PASTE: + case IDM_PASTEFORMATTED: + m_message.SendMsg(EM_PASTESPECIAL, (iSelection == IDM_PASTE) ? CF_UNICODETEXT : 0, 0); + break; + case IDM_COPYALL: + m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); + m_message.SendMsg(WM_COPY, 0, 0); + m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + break; + case IDM_SELECTALL: + m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); + break; + } + DestroyMenu(hMenu); + } + return TRUE; - RECT rc, rcWnd; - GetClientRect(dat->m_pContainer->m_hwnd, &rcWnd); - GetWindowRect(hwndDlg, &rc); - SetWindowPos(hwndDlg, HWND_TOP, (rcWnd.right - (rc.right - rc.left)) / 2, (rcWnd.bottom - (rc.bottom - rc.top)) / 2, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); - } - break; + case WM_MOUSEWHEEL: + if (DM_MouseWheelHandler(wParam, lParam) == 0) + return 0; - case ID_MESS: - dat->DoEventHook(GC_USER_PRIVMESS, ui, nullptr, 0); - break; + m_iLastEnterTime = 0; + break; - default: - dat->DoEventHook(GC_USER_NICKLISTMENU, ui, nullptr, uID); - break; - } - DestroyGCMenu(&hMenu, 1); - return TRUE; - } + case WM_SYSKEYUP: + if (wParam == VK_MENU) { + ProcessHotkeysByMsgFilter(m_message.GetHwnd(), msg, wParam, lParam, IDC_MESSAGE); + return 0; } break; - case WM_MOUSEMOVE: - Chat_HoverMouse(dat->m_si, hwnd, lParam, ServiceExists("mToolTip/HideTip")); + case WM_SYSKEYDOWN: + m_bkeyProcessed = false; + if (ProcessHotkeysByMsgFilter(m_message.GetHwnd(), msg, wParam, lParam, IDC_MESSAGE)) { + m_bkeyProcessed = true; + return 0; + } break; - } - return mir_callNextSubclass(hwnd, NicklistSubclassProc, msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// calculate the required rectangle for a string using the given font. This is more -// precise than using GetTextExtentPoint...() -int GetTextPixelSize(wchar_t* pszText, HFONT hFont, bool bWidth) -{ - if (!pszText || !hFont) - return 0; + case WM_SYSCHAR: + if (m_bkeyProcessed) { + m_bkeyProcessed = false; // preceeding key event has been processed by miranda hotkey service + return 0; + } - HDC hdc = GetDC(nullptr); - HFONT hOldFont = (HFONT)SelectObject(hdc, hFont); + if ((wParam >= '0' && wParam <= '9') && (GetKeyState(VK_MENU) & 0x8000)) { // ALT-1 -> ALT-0 direct tab selection + BYTE bChar = (BYTE)wParam; + int iIndex = (bChar == '0') ? 10 : bChar - (BYTE)'0'; + SendMessage(m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_BY_INDEX, (LPARAM)iIndex); + return 0; + } + break; - RECT rc = { 0 }; - DrawText(hdc, pszText, -1, &rc, DT_CALCRECT); + case WM_CHAR: + bool isShift, isAlt, isCtrl; + KbdState(isShift, isCtrl, isAlt); - SelectObject(hdc, hOldFont); - ReleaseDC(nullptr, hdc); - return bWidth ? rc.right - rc.left : rc.bottom - rc.top; -} + if (PluginConfig.m_bSoundOnTyping && !isAlt && !isCtrl && !(m_pContainer->dwFlags & CNT_NOSOUND) && wParam != VK_ESCAPE && !(wParam == VK_TAB && PluginConfig.m_bAllowTab)) + SkinPlaySound("SoundOnTyping"); -static void __cdecl phase2(void * lParam) -{ - Thread_SetName("TabSRMM: phase2"); + if (isCtrl && !isAlt && !isShift) + switch (wParam) { + case 0x17: + PostMessage(m_hwnd, WM_CLOSE, 0, 1); + return 0; + } - SESSION_INFO *si = (SESSION_INFO*)lParam; - Sleep(30); - if (si && si->pDlg) - si->pDlg->RedrawLog2(); -} + break; -///////////////////////////////////////////////////////////////////////////////////////// -// the actual group chat session window procedure.Handles the entire chat session window -// which is usually a (tabbed) child of a container class window. + case WM_KEYDOWN: + KbdState(isShift, isCtrl, isAlt); -CChatRoomDlg::CChatRoomDlg(SESSION_INFO *si) - : CTabBaseDlg(IDD_CHANNEL, si), - m_btnOk(this, IDOK) -{ - m_szProto = GetContactProto(m_hContact); - m_bFilterEnabled = db_get_b(m_hContact, CHAT_MODULE, "FilterEnabled", m_bFilterEnabled) != 0; - Chat_SetFilters(m_si); + // sound on typing.. + if (PluginConfig.m_bSoundOnTyping && !isAlt && wParam == VK_DELETE) + SkinPlaySound("SoundOnTyping"); - m_btnOk.OnClick = Callback(this, &CChatRoomDlg::onClick_OK); - m_btnFilter.OnClick = Callback(this, &CChatRoomDlg::onClick_Filter); - m_btnNickList.OnClick = Callback(this, &CChatRoomDlg::onClick_ShowNickList); - - m_message.OnChange = Callback(this, &CChatRoomDlg::onChange_Message); -} + if (ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) + return true; -CThumbBase* CChatRoomDlg::tabCreateThumb(CProxyWindow *pProxy) const -{ - return new CThumbMUC(pProxy, m_si); -} + if (wParam == VK_INSERT && !isShift && !isCtrl && !isAlt) { + m_bInsertMode = !m_bInsertMode; + m_message.OnChange(&m_message); + } + if (wParam == VK_CAPITAL || wParam == VK_NUMLOCK) + m_message.OnChange(&m_message); -void CChatRoomDlg::tabClearLog() -{ - SESSION_INFO *s = pci->SM_FindSession(m_si->ptszID, m_si->pszModule); - if (s) { - ClearLog(); - pci->LM_RemoveAll(&s->pLog, &s->pLogEnd); - s->iEventCount = 0; - s->LastTime = 0; - m_si->iEventCount = 0; - m_si->LastTime = 0; - m_si->pLog = s->pLog; - m_si->pLogEnd = s->pLogEnd; - PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0); - } -} + if (isCtrl && isAlt && !isShift) { + switch (wParam) { + case VK_UP: + case VK_DOWN: + case VK_PRIOR: + case VK_NEXT: + case VK_HOME: + case VK_END: + WPARAM wp = 0; -void CChatRoomDlg::OnInitDialog() -{ - CTabBaseDlg::OnInitDialog(); + if (wParam == VK_UP) + wp = MAKEWPARAM(SB_LINEUP, 0); + else if (wParam == VK_PRIOR) + wp = MAKEWPARAM(SB_PAGEUP, 0); + else if (wParam == VK_NEXT) + wp = MAKEWPARAM(SB_PAGEDOWN, 0); + else if (wParam == VK_HOME) + wp = MAKEWPARAM(SB_TOP, 0); + else if (wParam == VK_END) { + DM_ScrollToBottom(0, 0); + return 0; + } + else if (wParam == VK_DOWN) + wp = MAKEWPARAM(SB_LINEDOWN, 0); - m_si->pDlg = this; - - m_iSplitterY = m_pContainer->settings->iSplitterY; - if (m_bIsAutosizingInput) - m_iSplitterY = GetDefaultMinimumInputHeight(); + SendDlgItemMessage(m_hwnd, IDC_LOG, WM_VSCROLL, wp, 0); + return 0; + } + } - // Typing support for GCW_PRIVMESS sessions - if (m_si->iType == GCW_PRIVMESS) { - m_nTypeMode = PROTOTYPE_SELFTYPING_OFF; - SetTimer(m_hwnd, TIMERID_TYPE, 1000, nullptr); - } + if (wParam == VK_RETURN) { + if (isShift) { + if (PluginConfig.m_bSendOnShiftEnter) { + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + break; + } + if ((isCtrl && !isShift) ^ (0 != PluginConfig.m_bSendOnEnter)) { + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + if (!PluginConfig.m_bSendOnEnter && !PluginConfig.m_bSendOnDblEnter) + break; + if (isCtrl) + break; - m_pPanel.getVisibility(); - m_pPanel.Configure(); + if (PluginConfig.m_bSendOnDblEnter) { + if (m_iLastEnterTime + 2 < time(nullptr)) { + m_iLastEnterTime = time(nullptr); + break; + } - m_log.SendMsg(EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback); - m_log.SendMsg(EM_AUTOURLDETECT, 1, 0); - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_PANELSPLITTER), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc); - FireEvent(MSG_WINDOW_EVT_OPENING, 0); + m_message.SendMsg(WM_KEYDOWN, VK_BACK, 0); + m_message.SendMsg(WM_KEYUP, VK_BACK, 0); + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + else m_iLastEnterTime = 0; - m_log.SendMsg(EM_SETEVENTMASK, 0, m_log.SendMsg(EM_GETEVENTMASK, 0, 0) | ENM_LINK | ENM_MOUSEEVENTS | ENM_KEYEVENTS); - m_log.SendMsg(EM_LIMITTEXT, 0x7FFFFFFF, 0); - m_log.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); + if ((wParam == VK_NEXT && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && !isShift)) { // CTRL-TAB (switch tab/window) + SendMessage(m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_NEXT, 0); + return TRUE; + } - m_message.SendMsg(EM_SETEVENTMASK, 0, ENM_REQUESTRESIZE | ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE); - m_message.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); + if ((wParam == VK_PRIOR && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && isShift)) { // CTRL_SHIFT-TAB (switch tab/window) + SendMessage(m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_PREV, 0); + return TRUE; + } + if (wParam == VK_TAB && !isCtrl && !isShift) { // tab-autocomplete + m_message.SendMsg(WM_SETREDRAW, FALSE, 0); + bool fCompleted = TabAutoComplete(); + m_message.SendMsg(WM_SETREDRAW, TRUE, 0); + RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); + if (!fCompleted && !PluginConfig.m_bAllowTab) { + if ((GetSendButtonState(GetHwnd()) != PBS_DISABLED)) + SetFocus(GetDlgItem(GetHwnd(), IDOK)); + else + SetFocus(GetDlgItem(GetHwnd(), IDC_LOG)); + } + return 0; + } + if (wParam != VK_RIGHT && wParam != VK_LEFT) { + mir_free(m_wszSearchQuery); + m_wszSearchQuery = nullptr; + mir_free(m_wszSearchResult); + m_wszSearchResult = nullptr; + } - m_pPanel.loadHeight(); + if (wParam == VK_F4 && isCtrl && !isAlt) { // ctrl-F4 (close tab) + SendMessage(m_hwnd, WM_COMMAND, MAKEWPARAM(IDC_CLOSE, BN_CLICKED), 0); + return 0; + } - if (PluginConfig.g_hMenuTrayUnread != 0 && m_hContact != 0 && m_szProto != nullptr) - UpdateTrayMenu(0, m_wStatus, m_szProto, m_wszStatus, m_hContact, FALSE); + if (wParam == VK_NEXT || wParam == VK_PRIOR) { + HWND htemp = m_hwnd; + SendDlgItemMessage(htemp, IDC_LOG, msg, wParam, lParam); + m_iLastEnterTime = 0; + return 0; + } - m_log.SendMsg(EM_HIDESELECTION, TRUE, 0); + if (wParam == VK_UP && isCtrl && !isAlt) { + char *lpPrevCmd = pci->SM_GetPrevCommand(m_si->ptszID, m_si->pszModule); - GetMYUIN(); - GetMyNick(); + if (!m_si->lpCurrentCommand || !m_si->lpCurrentCommand->last) { + // Next command is not defined. It means currently entered text is not saved in the history and it + // need to be saved in the window context. + char *enteredText = Message_GetFromStream(m_hwnd); + if (m_enteredText) + mir_free(m_enteredText); - HWND hwndBtn = CreateWindowEx(0, L"MButtonClass", L"", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0, 0, 6, DPISCALEY_S(20), m_hwnd, (HMENU)IDC_TOGGLESIDEBAR, g_hInst, nullptr); - CustomizeButton(hwndBtn); - SendMessage(hwndBtn, BUTTONSETASTHEMEDBTN, 1, 0); - SendMessage(hwndBtn, BUTTONSETCONTAINER, (LPARAM)m_pContainer, 0); - SendMessage(hwndBtn, BUTTONSETASFLATBTN, FALSE, 0); - SendMessage(hwndBtn, BUTTONSETASTOOLBARBUTTON, TRUE, 0); - SendMessage(hwndBtn, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Expand or collapse the side bar"), BATF_UNICODE); + m_enteredText = enteredText; + } - DM_InitTip(); - BB_InitDlgButtons(); - SendMessage(m_hwnd, WM_CBD_LOADICONS, 0, 0); + m_message.SendMsg(WM_SETREDRAW, FALSE, 0); - mir_subclassWindow(GetDlgItem(m_hwnd, IDC_SPLITTERX), SplitterSubclassProc); - mir_subclassWindow(GetDlgItem(m_hwnd, IDC_SPLITTERY), SplitterSubclassProc); - mir_subclassWindow(m_nickList.GetHwnd(), NicklistSubclassProc); - mir_subclassWindow(m_log.GetHwnd(), LogSubclassProc); + LOGFONTA lf; + LoadLogfont(FONTSECTION_IM, MSGFONTID_MESSAGEAREA, &lf, nullptr, FONTMODULE); - mir_subclassWindow(m_message.GetHwnd(), MessageSubclassProc); - m_message.SendMsg(EM_SUBCLASSED, 0, 0); + SETTEXTEX ste; + ste.flags = ST_DEFAULT; + ste.codepage = CP_ACP; + if (lpPrevCmd) + m_message.SendMsg(EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd); + else + m_message.SetText(L""); - UpdateOptions(); - UpdateStatusBar(); - UpdateTitle(); - m_hTabIcon = m_hTabStatusIcon; + GETTEXTLENGTHEX gtl = { 0 }; + gtl.flags = GTL_PRECISE; + gtl.codepage = CP_ACP; + int iLen = m_message.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + m_message.SendMsg(EM_SCROLLCARET, 0, 0); + m_message.SendMsg(WM_SETREDRAW, TRUE, 0); + RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); + m_message.SendMsg(EM_SETSEL, iLen, iLen); + m_iLastEnterTime = 0; + return 0; + } - RECT rc; - SendMessage(m_pContainer->m_hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); - SetWindowPos(m_hwnd, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), 0); - ShowWindow(m_hwnd, SW_SHOW); - UpdateNickList(); - m_pContainer->m_hwndActive = m_hwnd; - FireEvent(MSG_WINDOW_EVT_OPEN, 0); -} + if (wParam == VK_DOWN && isCtrl && !isAlt) { + m_message.SendMsg(WM_SETREDRAW, FALSE, 0); -void CChatRoomDlg::OnDestroy() -{ - // Typing support for GCW_PRIVMESS sessions - if (m_si->iType == GCW_PRIVMESS) - if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) - DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF); + SETTEXTEX ste; + ste.flags = ST_DEFAULT; + ste.codepage = CP_ACP; - if (pcli->pfnGetEvent(m_si->hContact, 0)) - pcli->pfnRemoveEvent(m_si->hContact, GC_FAKE_EVENT); - m_si->wState &= ~STATE_TALK; - m_si->pDlg = nullptr; - m_si = nullptr; + char *lpPrevCmd = pci->SM_GetNextCommand(m_si->ptszID, m_si->pszModule); + if (lpPrevCmd) + m_message.SendMsg(EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd); + else if (m_enteredText) { + // If we cannot load the message from history, load the last edited text. + m_message.SendMsg(EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)m_enteredText); + mir_free(m_enteredText); + m_enteredText = nullptr; + } - FireEvent(MSG_WINDOW_EVT_CLOSING, 0); + GETTEXTLENGTHEX gtl = { 0 }; + gtl.flags = GTL_PRECISE; + gtl.codepage = CP_ACP; + int iLen = m_message.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); + m_message.SendMsg(EM_SCROLLCARET, 0, 0); + m_message.SendMsg(WM_SETREDRAW, TRUE, 0); + RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); + m_message.SendMsg(EM_SETSEL, iLen, iLen); + m_iLastEnterTime = 0; + return 0; + } + // fall through - DM_FreeTheme(); + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_KILLFOCUS: + m_iLastEnterTime = 0; + break; - UpdateTrayMenuState(this, FALSE); // remove me from the tray menu (if still there) - if (PluginConfig.g_hMenuTrayUnread) - DeleteMenu(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)m_hContact, MF_BYCOMMAND); + case WM_KEYUP: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + RefreshButtonStatus(); + break; - if (m_hwndTip) - DestroyWindow(m_hwndTip); + case WM_INPUTLANGCHANGE: + if (PluginConfig.m_bAutoLocaleSupport && GetFocus() == m_message.GetHwnd() && m_pContainer->m_hwndActive == m_hwnd && GetForegroundWindow() == m_pContainer->m_hwnd && GetActiveWindow() == m_pContainer->m_hwnd) { + DM_SaveLocale(wParam, lParam); + m_message.SendMsg(EM_SETLANGOPTIONS, 0, (LPARAM)m_message.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + return 1; + } + break; - int i = GetTabIndexFromHWND(m_hwndParent, m_hwnd); - if (i >= 0) { - SendMessage(m_hwndParent, WM_USER + 100, 0, 0); // clean up tooltip - TabCtrl_DeleteItem(m_hwndParent, i); - m_pContainer->UpdateTabs(); - m_iTabID = -1; - } - if (m_pWnd) { - delete m_pWnd; - m_pWnd = 0; - } - if (m_sbCustom) { - delete m_sbCustom; - m_sbCustom = 0; + case WM_ERASEBKGND: + return !CSkin::m_skinEnabled; } - M.RemoveWindow(m_hwnd); - - FireEvent(MSG_WINDOW_EVT_CLOSE, 0); - - m_pContainer->ClearMargins(); - PostMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 1); - - if (m_pContainer->dwFlags & CNT_SIDEBAR) - m_pContainer->SideBar->removeSession(this); - mir_free(m_enteredText); - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0); + return 0; } -void CChatRoomDlg::onClick_OK(CCtrlButton*) -{ - if (GetSendButtonState(m_hwnd) == PBS_DISABLED) - return; - - MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule); - if (mi == nullptr) - return; - - ptrA pszRtf(Message_GetFromStream(m_message.GetHwnd())); - pci->SM_AddCommand(m_si->ptszID, m_si->pszModule, pszRtf); +///////////////////////////////////////////////////////////////////////////////////////// +// subclassing for the nickname list control.It is an ownerdrawn listbox - CMStringW ptszText(ptrW(mir_utf8decodeW(pszRtf))); - if (ptszText.IsEmpty()) - return; +LRESULT CChatRoomDlg::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_NCCALCSIZE: + if (CSkin::m_DisableScrollbars) { + RECT lpRect; + GetClientRect(m_nickList.GetHwnd(), &lpRect); + LONG itemHeight = m_nickList.SendMsg(LB_GETITEMHEIGHT, 0, 0); + g_cLinesPerPage = (lpRect.bottom - lpRect.top) / itemHeight; + } + return CSkin::NcCalcRichEditFrame(m_nickList.GetHwnd(), this, ID_EXTBKUSERLIST, msg, wParam, lParam, nullptr); - DoRtfToTags(ptszText, mi->nColorCount, mi->crColors); - ptszText.Trim(); - ptszText.Replace(L"%", L"%%"); + case WM_NCPAINT: + return CSkin::DrawRichEditFrame(m_nickList.GetHwnd(), this, ID_EXTBKUSERLIST, msg, wParam, lParam, nullptr); - if (mi->bAckMsg) { - Utils::enableDlgControl(m_hwnd, IDC_MESSAGE, false); - m_message.SendMsg(EM_SETREADONLY, TRUE, 0); - } - else SetDlgItemText(m_hwnd, IDC_MESSAGE, L""); + case WM_ERASEBKGND: + { + HDC dc = (HDC)wParam; + if (dc) { + int index = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0); + if (index == LB_ERR || m_si->nUsersInNicklist <= 0) + return 0; - Utils::enableDlgControl(m_hwnd, IDOK, false); + int items = m_si->nUsersInNicklist - index; + int height = m_nickList.SendMsg(LB_GETITEMHEIGHT, 0, 0); - // Typing support for GCW_PRIVMESS sessions - if (m_si->iType == GCW_PRIVMESS) - if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) - DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF); + if (height != LB_ERR) { + RECT rc = { 0 }; + GetClientRect(m_nickList.GetHwnd(), &rc); - bool fSound = true; - if (ptszText[0] == '/' || m_si->iType == GCW_SERVER) - fSound = false; - DoEventHook(GC_USER_MESSAGE, nullptr, ptszText, 0); - mi->idleTimeStamp = time(0); - mi->lastIdleCheck = 0; - UpdateStatusBar(); - if (m_pContainer) - if (fSound && !nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND)) - SkinPlaySound("ChatSent"); + if (rc.bottom - rc.top > items * height) { + rc.top = items * height; + FillRect(dc, &rc, pci->hListBkgBrush); + } + } + } + } + return 1; - SetFocus(m_message.GetHwnd()); -} + case WM_MOUSEWHEEL: + if (CSkin::m_DisableScrollbars) { + UINT uScroll; + short zDelta = (short)HIWORD(wParam); + if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uScroll, 0)) + uScroll = 3; /* default value */ -void CChatRoomDlg::onClick_Filter(CCtrlButton *pButton) -{ - if (!pButton->Enabled()) - return; + if (uScroll == WHEEL_PAGESCROLL) + uScroll = g_cLinesPerPage; + if (uScroll == 0) + return 0; - if (m_iLogFilterFlags == 0 && !m_bFilterEnabled) { - MessageBox(0, TranslateT("The filter cannot be enabled, because there are no event types selected either global or for this chat room"), TranslateT("Event filter error"), MB_OK); - m_bFilterEnabled = false; - } - else m_bFilterEnabled = !m_bFilterEnabled; + zDelta += g_iWheelCarryover; /* Accumulate wheel motion */ - m_btnFilter.SendMsg(BUTTONSETOVERLAYICON, (LPARAM)(m_bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled), 0); + int dLines = zDelta * (int)uScroll / WHEEL_DELTA; - if (m_bFilterEnabled && M.GetByte(CHAT_MODULE, "RightClickFilter", 0) == 0) { - ShowFilterMenu(); - return; - } - RedrawLog(); - UpdateTitle(); - db_set_b(m_si->hContact, CHAT_MODULE, "FilterEnabled", m_bFilterEnabled); -} + //Record the unused portion as the next carryover. + g_iWheelCarryover = zDelta - dLines * WHEEL_DELTA / (int)uScroll; -void CChatRoomDlg::onClick_ShowNickList(CCtrlButton *pButton) -{ - if (!pButton->Enabled() || m_si->iType == GCW_SERVER) - return; + // scrolling. + while (abs(dLines)) { + if (dLines > 0) { + m_nickList.SendMsg(WM_VSCROLL, SB_LINEUP, 0); + dLines--; + } + else { + m_nickList.SendMsg(WM_VSCROLL, SB_LINEDOWN, 0); + dLines++; + } + } + return 0; + } + break; - m_bNicklistEnabled = !m_bNicklistEnabled; + case WM_KEYDOWN: + if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) + PostMessage(m_hwnd, WM_CLOSE, 0, 1); + return TRUE; + } - SendMessage(m_hwnd, WM_SIZE, 0, 0); - if (CSkin::m_skinEnabled) - InvalidateRect(m_hwnd, nullptr, TRUE); - ScrollToBottom(); -} + if (wParam == VK_ESCAPE || wParam == VK_UP || wParam == VK_DOWN || wParam == VK_NEXT || wParam == VK_PRIOR || wParam == VK_TAB || wParam == VK_HOME || wParam == VK_END) { + m_wszSearch[0] = 0; + m_iSearchItem = -1; + } + break; -void CChatRoomDlg::onChange_Message(CCtrlEdit*) -{ - if (m_pContainer->m_hwndActive == m_hwnd) - UpdateReadChars(); - m_dwLastActivity = GetTickCount(); - m_pContainer->dwLastActivity = m_dwLastActivity; - m_btnOk.SendMsg(BUTTONSETASNORMAL, GetRichTextLength(m_message.GetHwnd()) != 0, 0); - m_btnOk.Enable(GetRichTextLength(m_message.GetHwnd()) != 0); + case WM_SETFOCUS: + case WM_KILLFOCUS: + m_wszSearch[0] = 0; + m_iSearchItem = -1; + break; - // Typing support for GCW_PRIVMESS sessions - if (m_si->iType == GCW_PRIVMESS) { - if (!(GetKeyState(VK_CONTROL) & 0x8000)) { - m_nLastTyping = GetTickCount(); - if (GetWindowTextLength(m_message.GetHwnd())) { - if (m_nTypeMode == PROTOTYPE_SELFTYPING_OFF) { - if (!(m_dwFlags & MWF_INITMODE)) - DM_NotifyTyping(PROTOTYPE_SELFTYPING_ON); + case WM_CHAR: + case WM_UNICHAR: + // simple incremental search for the user (nick) - list control + // typing esc or movement keys will clear the current search string + if (wParam == 27 && m_wszSearch[0]) { // escape - reset everything + m_wszSearch[0] = 0; + m_iSearchItem = -1; + break; + } + if (wParam == '\b' && m_wszSearch[0]) // backspace + m_wszSearch[mir_wstrlen(m_wszSearch) - 1] = '\0'; + else if (wParam < ' ') + break; + else { + if (mir_wstrlen(m_wszSearch) >= _countof(m_wszSearch) - 2) { + MessageBeep(MB_OK); + break; + } + wchar_t szNew[2]; + szNew[0] = (wchar_t)wParam; + szNew[1] = '\0'; + mir_wstrcat(m_wszSearch, szNew); + } + if (m_wszSearch[0]) { + // iterate over the (sorted) list of nicknames and search for the + // string we have + int i, iItems = m_nickList.SendMsg(LB_GETCOUNT, 0, 0); + for (i = 0; i < iItems; i++) { + USERINFO *ui = pci->UM_FindUserFromIndex(m_si->pUsers, i); + if (ui) { + if (!wcsnicmp(ui->pszNick, m_wszSearch, mir_wstrlen(m_wszSearch))) { + m_nickList.SendMsg(LB_SETSEL, FALSE, -1); + m_nickList.SendMsg(LB_SETSEL, TRUE, i); + m_iSearchItem = i; + InvalidateRect(m_nickList.GetHwnd(), nullptr, FALSE); + return 0; + } } } - else if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) - DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF); + if (i == iItems) { + MessageBeep(MB_OK); + m_wszSearch[mir_wstrlen(m_wszSearch) - 1] = '\0'; + return 0; + } } - } -} + break; -///////////////////////////////////////////////////////////////////////////////////////// + case WM_RBUTTONDOWN: + { + int iCounts = m_nickList.SendMsg(LB_GETSELCOUNT, 0, 0); + if (iCounts != LB_ERR && iCounts > 1) + return 0; + m_nickList.SendMsg(WM_LBUTTONDOWN, wParam, lParam); + } + break; -void CChatRoomDlg::AddLog() -{ - if (PluginConfig.m_bUseDividers) { - if (PluginConfig.m_bDividersUsePopupConfig) { - if (!MessageWindowOpened(0, (LPARAM)m_hwnd)) - DM_AddDivider(); + case WM_RBUTTONUP: + m_nickList.SendMsg(WM_LBUTTONUP, wParam, lParam); + break; + + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam; + if (mis->CtlType == ODT_MENU) + return Menu_MeasureItem(lParam); } - else { - bool bInactive = (GetForegroundWindow() != m_pContainer->m_hwnd || GetActiveWindow() != m_pContainer->m_hwnd); - if (bInactive) - DM_AddDivider(); - else if (m_pContainer->m_hwndActive != m_hwnd) - DM_AddDivider(); + return FALSE; + + case WM_DRAWITEM: + { + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam; + if (dis->CtlType == ODT_MENU) + return Menu_DrawItem(lParam); } - } + return FALSE; - CSrmmBaseDialog::AddLog(); -} + case WM_CONTEXTMENU: + { + SESSION_INFO *si = m_si; + if (si == nullptr) + break; -void CChatRoomDlg::CloseTab() -{ - int iTabs = TabCtrl_GetItemCount(m_hwndParent); - if (iTabs == 1 && CMimAPI::m_shutDown == 0) { - SendMessage(m_pContainer->m_hwnd, WM_CLOSE, 0, 1); - return; - } + int height = 0; + TVHITTESTINFO hti; + hti.pt.x = GET_X_LPARAM(lParam); + hti.pt.y = GET_Y_LPARAM(lParam); + if (hti.pt.x == -1 && hti.pt.y == -1) { + int index = m_nickList.SendMsg(LB_GETCURSEL, 0, 0); + int top = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0); + height = m_nickList.SendMsg(LB_GETITEMHEIGHT, 0, 0); + hti.pt.x = 4; + hti.pt.y = (index - top) * height + 1; + } + else ScreenToClient(m_nickList.GetHwnd(), &hti.pt); - m_pContainer->iChilds--; - int i = GetTabIndexFromHWND(m_hwndParent, m_hwnd); + int item = (DWORD)(m_nickList.SendMsg(LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y))); + if (HIWORD(item) == 1) + item = (DWORD)(-1); + else + item &= 0xFFFF; - // after closing a tab, we need to activate the tab to the left side of - // the previously open tab. - // normally, this tab has the same index after the deletion of the formerly active tab - // unless, of course, we closed the last (rightmost) tab. - if (!m_pContainer->bDontSmartClose && iTabs > 1) { - if (i == iTabs - 1) - i--; - else - i++; - TabCtrl_SetCurSel(m_hwndParent, i); + USERINFO *ui = pci->SM_GetUserFromIndex(si->ptszID, si->pszModule, item); + if (ui) { + HMENU hMenu = 0; + USERINFO uinew; + memcpy(&uinew, ui, sizeof(USERINFO)); + if (hti.pt.x == -1 && hti.pt.y == -1) + hti.pt.y += height - 4; + ClientToScreen(m_nickList.GetHwnd(), &hti.pt); - TCITEM item = {}; - item.mask = TCIF_PARAM; - TabCtrl_GetItem(m_hwndParent, i, &item); // retrieve dialog hwnd for the now active tab... - m_pContainer->m_hwndActive = (HWND)item.lParam; + UINT uID = CreateGCMenu(m_nickList.GetHwnd(), &hMenu, 0, hti.pt, si, uinew.pszUID, uinew.pszNick); + switch (uID) { + case 0: + break; - RECT rc; - SendMessage(m_pContainer->m_hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); - SetWindowPos(m_pContainer->m_hwndActive, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), SWP_SHOWWINDOW); - ShowWindow((HWND)item.lParam, SW_SHOW); - SetForegroundWindow(m_pContainer->m_hwndActive); - SetFocus(m_pContainer->m_hwndActive); - SendMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 0); - } + case 20020: // add to highlight... + { + THighLightEdit the = { THighLightEdit::CMD_ADD, si, ui }; + HWND hwndDlg = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ADDHIGHLIGHT), m_pContainer->m_hwnd, CMUCHighlight::dlgProcAdd, (LPARAM)&the); + TranslateDialogDefault(hwndDlg); - if (iTabs == 1) - SendMessage(m_pContainer->m_hwnd, WM_CLOSE, 0, 1); - else { - PostMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 0); - DestroyWindow(m_hwnd); - } -} + RECT rc, rcWnd; + GetClientRect(m_pContainer->m_hwnd, &rcWnd); + GetWindowRect(hwndDlg, &rc); + SetWindowPos(hwndDlg, HWND_TOP, (rcWnd.right - (rc.right - rc.left)) / 2, (rcWnd.bottom - (rc.bottom - rc.top)) / 2, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); + } + break; -void CChatRoomDlg::RedrawLog() -{ - m_si->LastTime = 0; - if (m_si->pLog) { - LOGINFO *pLog = m_si->pLog; - if (m_si->iEventCount > 60) { - int index = 0; - while (index < 59) { - if (pLog->next == nullptr) + case ID_MESS: + DoEventHook(GC_USER_PRIVMESS, ui, nullptr, 0); break; - pLog = pLog->next; - if ((m_si->iType != GCW_CHATROOM && m_si->iType != GCW_PRIVMESS) || !m_bFilterEnabled || (m_iLogFilterFlags & pLog->iType) != 0) - index++; + + default: + DoEventHook(GC_USER_NICKLISTMENU, ui, nullptr, uID); + break; + } + DestroyGCMenu(&hMenu, 1); + return TRUE; } - StreamInEvents(pLog, TRUE); - mir_forkthread(phase2, m_si); } - else StreamInEvents(m_si->pLogEnd, TRUE); + break; + + case WM_MOUSEMOVE: + Chat_HoverMouse(m_si, m_nickList.GetHwnd(), lParam, ServiceExists("mToolTip/HideTip")); + break; } - else ClearLog(); + return 0; } -void CChatRoomDlg::ScrollToBottom() +///////////////////////////////////////////////////////////////////////////////////////// +// subclassing for the message filter dialog (set and configure event filters for the +// current session + +static UINT _eventorder[] = { - DM_ScrollToBottom(0, 0); -} + GC_EVENT_ACTION, + GC_EVENT_MESSAGE, + GC_EVENT_NICK, + GC_EVENT_JOIN, + GC_EVENT_PART, + GC_EVENT_TOPIC, + GC_EVENT_ADDSTATUS, + GC_EVENT_INFORMATION, + GC_EVENT_QUIT, + GC_EVENT_KICK, + GC_EVENT_NOTICE +}; -void CChatRoomDlg::ShowFilterMenu() +INT_PTR CALLBACK CChatRoomDlg::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - m_hwndFilter = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), m_pContainer->m_hwnd, FilterWndProc, (LPARAM)this); - TranslateDialogDefault(m_hwndFilter); + CChatRoomDlg *pDlg = (CChatRoomDlg*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (uMsg) { + case WM_INITDIALOG: + pDlg = (CChatRoomDlg*)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + { + DWORD dwMask = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "FilterMask", 0); + DWORD dwFlags = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "FilterFlags", 0); - RECT rcFilter, rcLog; - GetClientRect(m_hwndFilter, &rcFilter); - GetWindowRect(m_log.GetHwnd(), &rcLog); + DWORD dwPopupMask = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "PopupMask", 0); + DWORD dwPopupFlags = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "PopupFlags", 0); - POINT pt; - pt.x = rcLog.right; pt.y = rcLog.bottom; - ScreenToClient(m_pContainer->m_hwnd, &pt); + DWORD dwTrayMask = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconMask", 0); + DWORD dwTrayFlags = db_get_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconFlags", 0); - SetWindowPos(m_hwndFilter, HWND_TOP, pt.x - rcFilter.right, pt.y - rcFilter.bottom, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); -} + for (int i = 0; i < _countof(_eventorder); i++) { + CheckDlgButton(hwndDlg, IDC_1 + i, dwMask & _eventorder[i] ? (dwFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); + CheckDlgButton(hwndDlg, IDC_P1 + i, dwPopupMask & _eventorder[i] ? (dwPopupFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); + CheckDlgButton(hwndDlg, IDC_T1 + i, dwTrayMask & _eventorder[i] ? (dwTrayFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); + } + } + return FALSE; -void CChatRoomDlg::UpdateNickList() -{ - int i = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0); - m_nickList.SendMsg(LB_SETCOUNT, m_si->nUsersInNicklist, 0); - m_nickList.SendMsg(LB_SETTOPINDEX, i, 0); - UpdateTitle(); - m_hTabIcon = m_hTabStatusIcon; -} + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + SetTextColor((HDC)wParam, RGB(60, 60, 150)); + SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); -void CChatRoomDlg::UpdateOptions() -{ - MODULEINFO *pInfo = m_si ? pci->MM_FindModule(m_si->pszModule) : nullptr; - if (pInfo) { - m_btnBold.Enable(pInfo->bBold); - m_btnItalic.Enable(pInfo->bItalics); - m_btnUnderline.Enable(pInfo->bUnderline); - m_btnColor.Enable(pInfo->bColor); - m_btnBkColor.Enable(pInfo->bBkgColor); - if (m_si->iType == GCW_CHATROOM) - m_btnChannelMgr.Enable(pInfo->bChanMgr); - } - m_log.SendMsg(EM_SETBKGNDCOLOR, 0, M.GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR)); + case WM_CLOSE: + if (wParam == 1 && lParam == 1) { + int iFlags = 0, i; + DWORD dwMask = 0; - DM_InitRichEdit(); - m_btnOk.SendMsg(BUTTONSETASNORMAL, TRUE, 0); + for (i = 0; i < _countof(_eventorder); i++) { + int result = IsDlgButtonChecked(hwndDlg, IDC_1 + i); + dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); + iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); + } - m_nickList.SetItemHeight(0, g_Settings.iNickListFontHeight); - InvalidateRect(m_nickList.GetHwnd(), nullptr, TRUE); + if (iFlags & GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; - m_btnFilter.SendMsg(BUTTONSETOVERLAYICON, (LPARAM)(m_bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled), 0); - SendMessage(m_hwnd, WM_SIZE, 0, 0); - RedrawLog2(); -} + if (pDlg) { + if (dwMask == 0) { + db_unset(pDlg->m_hContact, CHAT_MODULE, "FilterFlags"); + db_unset(pDlg->m_hContact, CHAT_MODULE, "FilterMask"); + } + else { + db_set_dw(pDlg->m_hContact, CHAT_MODULE, "FilterFlags", iFlags); + db_set_dw(pDlg->m_hContact, CHAT_MODULE, "FilterMask", dwMask); + } + } -void CChatRoomDlg::UpdateStatusBar() -{ - if (m_pContainer->m_hwndActive != m_hwnd || m_pContainer->hwndStatus == 0 || CMimAPI::m_shutDown || m_wszStatusBar[0]) - return; + dwMask = iFlags = 0; - if (m_si->pszModule == nullptr) - return; + for (i = 0; i < _countof(_eventorder); i++) { + int result = IsDlgButtonChecked(hwndDlg, IDC_P1 + i); + dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); + iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); + } - //Mad: strange rare crash here... - MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule); - if (!mi) - return; + if (iFlags & GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; - if (!mi->ptszModDispName) - return; + if (pDlg) { + if (dwMask == 0) { + db_unset(pDlg->m_hContact, CHAT_MODULE, "PopupFlags"); + db_unset(pDlg->m_hContact, CHAT_MODULE, "PopupMask"); + } + else { + db_set_dw(pDlg->m_hContact, CHAT_MODULE, "PopupFlags", iFlags); + db_set_dw(pDlg->m_hContact, CHAT_MODULE, "PopupMask", dwMask); + } + } - int x = 12; - x += GetTextPixelSize(mi->ptszModDispName, (HFONT)SendMessage(m_pContainer->hwndStatus, WM_GETFONT, 0, 0), TRUE); - x += GetSystemMetrics(SM_CXSMICON); + dwMask = iFlags = 0; - wchar_t szFinalStatusBarText[512]; - if (m_pPanel.isActive()) { - time_t now = time(0); - DWORD diff = (now - mi->idleTimeStamp) / 60; + for (i = 0; i < _countof(_eventorder); i++) { + int result = IsDlgButtonChecked(hwndDlg, IDC_T1 + i); + dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); + iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); + } + if (iFlags & GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; - if ((diff >= 1 && diff != mi->lastIdleCheck)) { - mi->lastIdleCheck = diff; - if (diff > 59) { - DWORD hours = diff / 60; - DWORD minutes = diff % 60; - mir_snwprintf(mi->tszIdleMsg, TranslateT(", %d %s, %d %s idle"), - hours, hours > 1 ? TranslateT("hours") : TranslateT("hour"), - minutes, minutes > 1 ? TranslateT("minutes") : TranslateT("minute")); + if (pDlg) { + if (dwMask == 0) { + db_unset(pDlg->m_hContact, CHAT_MODULE, "TrayIconFlags"); + db_unset(pDlg->m_hContact, CHAT_MODULE, "TrayIconMask"); + } + else { + db_set_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconFlags", iFlags); + db_set_dw(pDlg->m_hContact, CHAT_MODULE, "TrayIconMask", dwMask); + } + Chat_SetFilters(pDlg->m_si); + if (pDlg->m_iLogFilterFlags == 0 && pDlg->m_bFilterEnabled) + pDlg->onClick_Filter(&pDlg->m_btnFilter); + if (pDlg->m_bFilterEnabled) + pDlg->RedrawLog(); } - else mir_snwprintf(mi->tszIdleMsg, TranslateT(", %d %s idle"), diff, diff > 1 ? TranslateT("minutes") : TranslateT("minute")); } - mir_snwprintf(szFinalStatusBarText, TranslateT("%s on %s%s"), m_wszMyNickname, mi->ptszModDispName, mi->tszIdleMsg); - } - else { - if (m_si->ptszStatusbarText) - mir_snwprintf(szFinalStatusBarText, L"%s %s", mi->ptszModDispName, m_si->ptszStatusbarText); - else - wcsncpy_s(szFinalStatusBarText, mi->ptszModDispName, _TRUNCATE); - } - SendMessage(m_pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szFinalStatusBarText); - tabUpdateStatusBar(); - m_pPanel.Invalidate(); - if (m_pWnd) - m_pWnd->Invalidate(); -} - -void CChatRoomDlg::UpdateTitle() -{ - m_wStatus = m_si->wStatus; - - const wchar_t *szNick = m_cache->getNick(); - if (mir_wstrlen(szNick) > 0) { - if (M.GetByte("cuttitle", 0)) - CutContactName(szNick, m_wszTitle, _countof(m_wszTitle)); - else - wcsncpy_s(m_wszTitle, szNick, _TRUNCATE); - } - - wchar_t szTemp[100]; - HICON hIcon = 0; - - switch (m_si->iType) { - case GCW_CHATROOM: - hIcon = Skin_LoadProtoIcon(m_si->pszModule, (m_wStatus <= ID_STATUS_OFFLINE) ? ID_STATUS_OFFLINE : m_wStatus); - mir_snwprintf(szTemp, - (m_si->nUsersInNicklist == 1) ? TranslateT("%s: chat room (%u user%s)") : TranslateT("%s: chat room (%u users%s)"), - szNick, m_si->nUsersInNicklist, m_bFilterEnabled ? TranslateT(", event filter active") : L""); - break; - case GCW_PRIVMESS: - hIcon = Skin_LoadProtoIcon(m_si->pszModule, (m_wStatus <= ID_STATUS_OFFLINE) ? ID_STATUS_OFFLINE : m_wStatus); - if (m_si->nUsersInNicklist == 1) - mir_snwprintf(szTemp, TranslateT("%s: message session"), szNick); - else - mir_snwprintf(szTemp, TranslateT("%s: message session (%u users)"), szNick, m_si->nUsersInNicklist); - break; - case GCW_SERVER: - mir_snwprintf(szTemp, L"%s: Server", szNick); - hIcon = LoadIconEx("window"); + DestroyWindow(hwndDlg); break; - } - - if (m_pWnd) { - m_pWnd->updateTitle(m_wszTitle); - m_pWnd->updateIcon(hIcon); - } - m_hTabStatusIcon = hIcon; - - if (m_cache->getStatus() != m_cache->getOldStatus()) { - wcsncpy_s(m_wszStatus, pcli->pfnGetStatusModeDescription(m_wStatus, 0), _TRUNCATE); - TCITEM item = {}; - item.mask = TCIF_TEXT; - item.pszText = m_wszTitle; - TabCtrl_SetItem(m_hwndParent, m_iTabID, &item); - } - SetWindowText(m_hwnd, szTemp); - if (m_pContainer->m_hwndActive == m_hwnd) { - m_pContainer->UpdateTitle(0, this); - UpdateStatusBar(); + case WM_DESTROY: + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + break; } + return FALSE; } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/TabSRMM/src/msgdialog.cpp b/plugins/TabSRMM/src/msgdialog.cpp index 32ebdcf0ee..ba1b37c796 100644 --- a/plugins/TabSRMM/src/msgdialog.cpp +++ b/plugins/TabSRMM/src/msgdialog.cpp @@ -428,339 +428,6 @@ void TSAPI SetDialogToType(HWND hwndDlg) dat->m_pPanel.Configure(); } -static LRESULT CALLBACK MessageLogSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HWND hwndParent = GetParent(hwnd); - CSrmmWindow *mwdat = (CSrmmWindow*)GetWindowLongPtr(hwndParent, GWLP_USERDATA); - bool isCtrl, isShift, isAlt; - - switch (msg) { - case WM_KILLFOCUS: - if (wParam != (WPARAM)hwnd && 0 != wParam) { - CHARRANGE cr; - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&cr); - if (cr.cpMax != cr.cpMin) { - cr.cpMin = cr.cpMax; - SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr); - } - } - break; - - case WM_CHAR: - mwdat->KbdState(isShift, isCtrl, isAlt); - if (wParam == 0x03 && isCtrl) // Ctrl+C - return Utils::WMCopyHandler(hwnd, MessageLogSubclassProc, msg, wParam, lParam); - if (wParam == 0x11 && isCtrl) - SendMessage(mwdat->GetHwnd(), WM_COMMAND, IDC_QUOTE, 0); - break; - - case WM_SYSKEYUP: - if (wParam == VK_MENU) { - ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_LOG); - return 0; - } - break; - - case WM_SYSKEYDOWN: - mwdat->m_bkeyProcessed = false; - if (ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_LOG)) { - mwdat->m_bkeyProcessed = true; - return 0; - } - break; - - case WM_SYSCHAR: - if (mwdat->m_bkeyProcessed) { - mwdat->m_bkeyProcessed = false; - return 0; - } - break; - - case WM_KEYDOWN: - mwdat->KbdState(isShift, isCtrl, isAlt); - if (wParam == VK_INSERT && isCtrl) - return Utils::WMCopyHandler(hwnd, MessageLogSubclassProc, msg, wParam, lParam); - break; - - case WM_COPY: - return Utils::WMCopyHandler(hwnd, MessageLogSubclassProc, msg, wParam, lParam); - - case WM_NCCALCSIZE: - return CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, MessageLogSubclassProc); - - case WM_NCPAINT: - return CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, MessageLogSubclassProc); - - case WM_CONTEXTMENU: - POINT pt; - - if (lParam == 0xFFFFFFFF) { - CHARRANGE sel; - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)sel.cpMax); - ClientToScreen(hwnd, &pt); - } - else { - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - } - - ShowPopupMenu(mwdat, IDC_LOG, hwnd, pt); - return TRUE; - } - - return mir_callNextSubclass(hwnd, MessageLogSubclassProc, msg, wParam, lParam); -} - -static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - bool isCtrl, isShift, isAlt; - HWND hwndParent = GetParent(hwnd); - CSrmmWindow *mwdat = (CSrmmWindow*)GetWindowLongPtr(hwndParent, GWLP_USERDATA); - if (mwdat == nullptr) - return 0; - - // prevent the rich edit from switching text direction or keyboard layout when - // using hotkeys with ctrl-shift or alt-shift modifiers - if (mwdat->m_bkeyProcessed && (msg == WM_KEYUP)) { - GetKeyboardState(mwdat->kstate); - if (mwdat->kstate[VK_CONTROL] & 0x80 || mwdat->kstate[VK_SHIFT] & 0x80) - return 0; - - mwdat->m_bkeyProcessed = false; - return 0; - } - - switch (msg) { - case WM_NCCALCSIZE: - return CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, MessageEditSubclassProc); - - case WM_NCPAINT: - return CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, MessageEditSubclassProc); - - case WM_DROPFILES: - SendMessage(hwndParent, WM_DROPFILES, (WPARAM)wParam, (LPARAM)lParam); - return 0; - - case WM_CHAR: - mwdat->KbdState(isShift, isCtrl, isAlt); - - if (PluginConfig.m_bSoundOnTyping && !isAlt && !isCtrl && !(mwdat->m_pContainer->dwFlags & CNT_NOSOUND) && wParam != VK_ESCAPE && !(wParam == VK_TAB && PluginConfig.m_bAllowTab)) - SkinPlaySound("SoundOnTyping"); - - if (isCtrl && !isAlt) { - switch (wParam) { - case 0x02: // bold - if (mwdat->m_SendFormat) - SendMessage(hwndParent, WM_COMMAND, MAKELONG(IDC_SRMM_BOLD, IDC_MESSAGE), 0); - return 0; - case 0x09: - if (mwdat->m_SendFormat) - SendMessage(hwndParent, WM_COMMAND, MAKELONG(IDC_SRMM_ITALICS, IDC_MESSAGE), 0); - return 0; - case 21: - if (mwdat->m_SendFormat) - SendMessage(hwndParent, WM_COMMAND, MAKELONG(IDC_SRMM_UNDERLINE, IDC_MESSAGE), 0); - return 0; - case 0x0b: - SetWindowText(hwnd, L""); - return 0; - } - } - break; - - case WM_MOUSEWHEEL: - if (mwdat->DM_MouseWheelHandler(wParam, lParam) == 0) - return 0; - break; - - case EM_PASTESPECIAL: - case WM_PASTE: - if (OpenClipboard(hwnd)) { - HANDLE hClip = GetClipboardData(CF_TEXT); - if (hClip) { - if ((int)mir_strlen((char*)hClip) > mwdat->m_nMax) { - wchar_t szBuffer[512]; - if (M.GetByte("autosplit", 0)) - mir_snwprintf(szBuffer, TranslateT("WARNING: The message you are trying to paste exceeds the message size limit for the active protocol. It will be sent in chunks of max %d characters"), mwdat->m_nMax - 10); - else - mir_snwprintf(szBuffer, TranslateT("The message you are trying to paste exceeds the message size limit for the active protocol. Only the first %d characters will be sent."), mwdat->m_nMax); - SendMessage(hwndParent, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)szBuffer); - } - } - else if (hClip = GetClipboardData(CF_BITMAP)) - mwdat->SendHBitmapAsFile((HBITMAP)hClip); - - CloseClipboard(); - } - break; - - case WM_KEYDOWN: - mwdat->KbdState(isShift, isCtrl, isAlt); - - if (PluginConfig.m_bSoundOnTyping && !isAlt && !(mwdat->m_pContainer->dwFlags & CNT_NOSOUND) && wParam == VK_DELETE) - SkinPlaySound("SoundOnTyping"); - - if (wParam == VK_INSERT && !isShift && !isCtrl && !isAlt) { - mwdat->m_bInsertMode = !mwdat->m_bInsertMode; - SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd); - } - if (wParam == VK_CAPITAL || wParam == VK_NUMLOCK) - SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd); - - if (wParam == VK_RETURN) { - if (mwdat->m_bEditNotesActive) - break; - - if (isShift) { - if (PluginConfig.m_bSendOnShiftEnter) { - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - else break; - } - if ((isCtrl && !isShift) ^ (0 != PluginConfig.m_bSendOnEnter)) { - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - if (PluginConfig.m_bSendOnEnter || PluginConfig.m_bSendOnDblEnter) { - if (isCtrl) - break; - - if (PluginConfig.m_bSendOnDblEnter) { - LONG_PTR lastEnterTime = GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (lastEnterTime + 2 < time(nullptr)) { - lastEnterTime = time(nullptr); - SetWindowLongPtr(hwnd, GWLP_USERDATA, lastEnterTime); - break; - } - else { - SendMessage(hwnd, WM_KEYDOWN, VK_BACK, 0); - SendMessage(hwnd, WM_KEYUP, VK_BACK, 0); - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - } - PostMessage(hwndParent, WM_COMMAND, IDOK, 0); - return 0; - } - else break; - } - else SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); - - if (isCtrl && !isAlt && !isShift) { - if (!isShift && (wParam == VK_UP || wParam == VK_DOWN)) { // input history scrolling (ctrl-up / down) - SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); - if (mwdat) - mwdat->m_cache->inputHistoryEvent(wParam); - return 0; - } - } - if (isCtrl && isAlt && !isShift) { - switch (wParam) { - case VK_UP: - case VK_DOWN: - case VK_PRIOR: - case VK_NEXT: - case VK_HOME: - case VK_END: - WPARAM wp = 0; - - SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); - if (wParam == VK_UP) - wp = MAKEWPARAM(SB_LINEUP, 0); - else if (wParam == VK_PRIOR) - wp = MAKEWPARAM(SB_PAGEUP, 0); - else if (wParam == VK_NEXT) - wp = MAKEWPARAM(SB_PAGEDOWN, 0); - else if (wParam == VK_HOME) - wp = MAKEWPARAM(SB_TOP, 0); - else if (wParam == VK_END) { - mwdat->DM_ScrollToBottom(0, 0); - return 0; - } - else if (wParam == VK_DOWN) - wp = MAKEWPARAM(SB_LINEDOWN, 0); - - if (mwdat->m_hwndIEView == 0 && mwdat->m_hwndHPP == 0) - SendDlgItemMessage(hwndParent, IDC_LOG, WM_VSCROLL, wp, 0); - else - SendMessage(mwdat->m_hwndIWebBrowserControl, WM_VSCROLL, wp, 0); - return 0; - } - } - - case WM_SYSKEYDOWN: - mwdat->m_bkeyProcessed = false; - if (ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_MESSAGE)) { - mwdat->m_bkeyProcessed = true; - return 0; - } - break; - - case WM_SYSKEYUP: - if (wParam == VK_MENU) { - ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_MESSAGE); - return 0; - } - break; - - case WM_SYSCHAR: - if (mwdat->m_bkeyProcessed) { - mwdat->m_bkeyProcessed = false; - return 0; - } - - mwdat->KbdState(isShift, isCtrl, isAlt); - if ((wParam >= '0' && wParam <= '9') && isAlt) { // ALT-1 -> ALT-0 direct tab selection - BYTE bChar = (BYTE)wParam; - int iIndex; - - if (bChar == '0') - iIndex = 10; - else - iIndex = bChar - (BYTE)'0'; - SendMessage(mwdat->m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_BY_INDEX, (LPARAM)iIndex); - return 0; - } - break; - - case WM_INPUTLANGCHANGE: - if (PluginConfig.m_bAutoLocaleSupport && GetFocus() == hwnd && mwdat->m_pContainer->m_hwndActive == hwndParent && GetForegroundWindow() == mwdat->m_pContainer->m_hwnd && GetActiveWindow() == mwdat->m_pContainer->m_hwnd) { - mwdat->DM_SaveLocale(wParam, lParam); - SendMessage(hwnd, EM_SETLANGOPTIONS, 0, (LPARAM)SendMessage(hwnd, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); - return 1; - } - break; - - case WM_ERASEBKGND: - return(CSkin::m_skinEnabled ? 0 : 1); - - // sent by smileyadd when the smiley selection window dies - // just grab the focus :) - case WM_USER + 100: - SetFocus(hwnd); - break; - - case WM_CONTEXTMENU: - POINT pt; - if (lParam == 0xFFFFFFFF) { - CHARRANGE sel; - SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); - SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)sel.cpMax); - ClientToScreen(hwnd, &pt); - } - else { - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - } - - ShowPopupMenu(mwdat, IDC_MESSAGE, hwnd, pt); - return TRUE; - } - return mir_callNextSubclass(hwnd, MessageEditSubclassProc, msg, wParam, lParam); -} - ///////////////////////////////////////////////////////////////////////////////////////// // subclasses the avatar display controls, needed for skinning and to prevent // it from flickering during resize/move operations. @@ -1114,7 +781,6 @@ void CSrmmWindow::OnInitDialog() m_log.SendMsg(EM_EXLIMITTEXT, 0, 0x80000000); // subclassing stuff - mir_subclassWindow(m_message.GetHwnd(), MessageEditSubclassProc); mir_subclassWindow(GetDlgItem(m_hwnd, IDC_CONTACTPIC), AvatarSubclassProc); mir_subclassWindow(GetDlgItem(m_hwnd, IDC_SPLITTERY), SplitterSubclassProc); mir_subclassWindow(GetDlgItem(m_hwnd, IDC_MULTISPLITTER), SplitterSubclassProc); @@ -1161,11 +827,6 @@ void CSrmmWindow::OnInitDialog() } SendMessage(m_pContainer->m_hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); - { - WNDCLASS wndClass = { 0 }; - GetClassInfo(g_hInst, L"RICHEDIT50W", &wndClass); - mir_subclassWindowFull(m_log.GetHwnd(), MessageLogSubclassProc, wndClass.lpfnWndProc); - } SetWindowPos(m_hwnd, 0, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), m_bActivate ? 0 : SWP_NOZORDER | SWP_NOACTIVATE); LoadSplitter(); @@ -1312,6 +973,8 @@ void CSrmmWindow::OnDestroy() ieWindow.hwnd = m_hwndHPP; CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow); } + + CSuper::OnDestroy(); } void CSrmmWindow::ReplayQueue() @@ -2204,6 +1867,334 @@ int CSrmmWindow::OnFilter(MSGFILTER *pFilter) return 0; } +///////////////////////////////////////////////////////////////////////////////////////// + +LRESULT CSrmmWindow::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) +{ + bool isCtrl, isShift, isAlt; + + switch (msg) { + case WM_KILLFOCUS: + if (wParam != (WPARAM)m_log.GetHwnd() && 0 != wParam) { + CHARRANGE cr; + m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)&cr); + if (cr.cpMax != cr.cpMin) { + cr.cpMin = cr.cpMax; + m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&cr); + } + } + break; + + case WM_CHAR: + KbdState(isShift, isCtrl, isAlt); + if (wParam == 0x03 && isCtrl) // Ctrl+C + return Utils::WMCopyHandler(m_log.GetHwnd(), nullptr, msg, wParam, lParam); + if (wParam == 0x11 && isCtrl) + SendMessage(GetHwnd(), WM_COMMAND, IDC_QUOTE, 0); + break; + + case WM_SYSKEYUP: + if (wParam == VK_MENU) { + ProcessHotkeysByMsgFilter(m_log.GetHwnd(), msg, wParam, lParam, IDC_LOG); + return 0; + } + break; + + case WM_SYSKEYDOWN: + m_bkeyProcessed = false; + if (ProcessHotkeysByMsgFilter(m_log.GetHwnd(), msg, wParam, lParam, IDC_LOG)) { + m_bkeyProcessed = true; + return 0; + } + break; + + case WM_SYSCHAR: + if (m_bkeyProcessed) { + m_bkeyProcessed = false; + return 0; + } + break; + + case WM_KEYDOWN: + KbdState(isShift, isCtrl, isAlt); + if (wParam == VK_INSERT && isCtrl) + return Utils::WMCopyHandler(m_log.GetHwnd(), nullptr, msg, wParam, lParam); + break; + + case WM_COPY: + return Utils::WMCopyHandler(m_log.GetHwnd(), nullptr, msg, wParam, lParam); + + case WM_NCCALCSIZE: + return CSkin::NcCalcRichEditFrame(m_log.GetHwnd(), this, ID_EXTBKHISTORY, msg, wParam, lParam, nullptr); + + case WM_NCPAINT: + return CSkin::DrawRichEditFrame(m_log.GetHwnd(), this, ID_EXTBKHISTORY, msg, wParam, lParam, nullptr); + + case WM_CONTEXTMENU: + POINT pt; + + if (lParam == 0xFFFFFFFF) { + CHARRANGE sel; + m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel); + m_log.SendMsg(EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)sel.cpMax); + ClientToScreen(m_log.GetHwnd(), &pt); + } + else { + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + } + + ShowPopupMenu(this, IDC_LOG, m_log.GetHwnd(), pt); + return TRUE; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +LRESULT CSrmmWindow::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) +{ + bool isCtrl, isShift, isAlt; + + // prevent the rich edit from switching text direction or keyboard layout when + // using hotkeys with ctrl-shift or alt-shift modifiers + if (m_bkeyProcessed && (msg == WM_KEYUP)) { + GetKeyboardState(kstate); + if (kstate[VK_CONTROL] & 0x80 || kstate[VK_SHIFT] & 0x80) + return 0; + + m_bkeyProcessed = false; + return 0; + } + + switch (msg) { + case WM_NCCALCSIZE: + return CSkin::NcCalcRichEditFrame(m_message.GetHwnd(), this, ID_EXTBKINPUTAREA, msg, wParam, lParam, nullptr); + + case WM_NCPAINT: + return CSkin::DrawRichEditFrame(m_message.GetHwnd(), this, ID_EXTBKINPUTAREA, msg, wParam, lParam, nullptr); + + case WM_DROPFILES: + SendMessage(m_hwnd, WM_DROPFILES, (WPARAM)wParam, (LPARAM)lParam); + return 0; + + case WM_CHAR: + KbdState(isShift, isCtrl, isAlt); + + if (PluginConfig.m_bSoundOnTyping && !isAlt && !isCtrl && !(m_pContainer->dwFlags & CNT_NOSOUND) && wParam != VK_ESCAPE && !(wParam == VK_TAB && PluginConfig.m_bAllowTab)) + SkinPlaySound("SoundOnTyping"); + + if (isCtrl && !isAlt) { + switch (wParam) { + case 0x02: // bold + if (m_SendFormat) + SendMessage(m_hwnd, WM_COMMAND, MAKELONG(IDC_SRMM_BOLD, IDC_MESSAGE), 0); + return 0; + case 0x09: + if (m_SendFormat) + SendMessage(m_hwnd, WM_COMMAND, MAKELONG(IDC_SRMM_ITALICS, IDC_MESSAGE), 0); + return 0; + case 21: + if (m_SendFormat) + SendMessage(m_hwnd, WM_COMMAND, MAKELONG(IDC_SRMM_UNDERLINE, IDC_MESSAGE), 0); + return 0; + case 0x0b: + m_message.SetText(L""); + return 0; + } + } + break; + + case WM_MOUSEWHEEL: + if (DM_MouseWheelHandler(wParam, lParam) == 0) + return 0; + break; + + case EM_PASTESPECIAL: + case WM_PASTE: + if (OpenClipboard(m_message.GetHwnd())) { + HANDLE hClip = GetClipboardData(CF_TEXT); + if (hClip) { + if ((int)mir_strlen((char*)hClip) > m_nMax) { + wchar_t szBuffer[512]; + if (M.GetByte("autosplit", 0)) + mir_snwprintf(szBuffer, TranslateT("WARNING: The message you are trying to paste exceeds the message size limit for the active protocol. It will be sent in chunks of max %d characters"), m_nMax - 10); + else + mir_snwprintf(szBuffer, TranslateT("The message you are trying to paste exceeds the message size limit for the active protocol. Only the first %d characters will be sent."), m_nMax); + SendMessage(m_hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)szBuffer); + } + } + else if (hClip = GetClipboardData(CF_BITMAP)) + SendHBitmapAsFile((HBITMAP)hClip); + + CloseClipboard(); + } + break; + + case WM_KEYDOWN: + KbdState(isShift, isCtrl, isAlt); + + if (PluginConfig.m_bSoundOnTyping && !isAlt && !(m_pContainer->dwFlags & CNT_NOSOUND) && wParam == VK_DELETE) + SkinPlaySound("SoundOnTyping"); + + if (wParam == VK_INSERT && !isShift && !isCtrl && !isAlt) { + m_bInsertMode = !m_bInsertMode; + m_message.OnChange(&m_message); + } + if (wParam == VK_CAPITAL || wParam == VK_NUMLOCK) + m_message.OnChange(&m_message); + + if (wParam == VK_RETURN) { + if (m_bEditNotesActive) + break; + + if (isShift) { + if (PluginConfig.m_bSendOnShiftEnter) { + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + else break; + } + if ((isCtrl && !isShift) ^ (0 != PluginConfig.m_bSendOnEnter)) { + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + if (PluginConfig.m_bSendOnEnter || PluginConfig.m_bSendOnDblEnter) { + if (isCtrl) + break; + + if (PluginConfig.m_bSendOnDblEnter) { + if (m_iLastEnterTime + 2 < time(nullptr)) { + m_iLastEnterTime = time(nullptr); + break; + } + else { + m_message.SendMsg(WM_KEYDOWN, VK_BACK, 0); + m_message.SendMsg(WM_KEYUP, VK_BACK, 0); + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + } + PostMessage(m_hwnd, WM_COMMAND, IDOK, 0); + return 0; + } + else break; + } + else m_iLastEnterTime = 0; + + if (isCtrl && !isAlt && !isShift) { + if (!isShift && (wParam == VK_UP || wParam == VK_DOWN)) { // input history scrolling (ctrl-up / down) + m_iLastEnterTime = 0; + m_cache->inputHistoryEvent(wParam); + return 0; + } + } + if (isCtrl && isAlt && !isShift) { + switch (wParam) { + case VK_UP: + case VK_DOWN: + case VK_PRIOR: + case VK_NEXT: + case VK_HOME: + case VK_END: + WPARAM wp = 0; + + m_iLastEnterTime = 0; + if (wParam == VK_UP) + wp = MAKEWPARAM(SB_LINEUP, 0); + else if (wParam == VK_PRIOR) + wp = MAKEWPARAM(SB_PAGEUP, 0); + else if (wParam == VK_NEXT) + wp = MAKEWPARAM(SB_PAGEDOWN, 0); + else if (wParam == VK_HOME) + wp = MAKEWPARAM(SB_TOP, 0); + else if (wParam == VK_END) { + DM_ScrollToBottom(0, 0); + return 0; + } + else if (wParam == VK_DOWN) + wp = MAKEWPARAM(SB_LINEDOWN, 0); + + if (m_hwndIEView == 0 && m_hwndHPP == 0) + SendDlgItemMessage(m_hwnd, IDC_LOG, WM_VSCROLL, wp, 0); + else + SendMessage(m_hwndIWebBrowserControl, WM_VSCROLL, wp, 0); + return 0; + } + } + + case WM_SYSKEYDOWN: + m_bkeyProcessed = false; + if (ProcessHotkeysByMsgFilter(m_message.GetHwnd(), msg, wParam, lParam, IDC_MESSAGE)) { + m_bkeyProcessed = true; + return 0; + } + break; + + case WM_SYSKEYUP: + if (wParam == VK_MENU) { + ProcessHotkeysByMsgFilter(m_message.GetHwnd(), msg, wParam, lParam, IDC_MESSAGE); + return 0; + } + break; + + case WM_SYSCHAR: + if (m_bkeyProcessed) { + m_bkeyProcessed = false; + return 0; + } + + KbdState(isShift, isCtrl, isAlt); + if ((wParam >= '0' && wParam <= '9') && isAlt) { // ALT-1 -> ALT-0 direct tab selection + BYTE bChar = (BYTE)wParam; + int iIndex; + + if (bChar == '0') + iIndex = 10; + else + iIndex = bChar - (BYTE)'0'; + SendMessage(m_pContainer->m_hwnd, DM_SELECTTAB, DM_SELECT_BY_INDEX, (LPARAM)iIndex); + return 0; + } + break; + + case WM_INPUTLANGCHANGE: + if (PluginConfig.m_bAutoLocaleSupport && GetFocus() == m_message.GetHwnd() && m_pContainer->m_hwndActive == m_hwnd && GetForegroundWindow() == m_pContainer->m_hwnd && GetActiveWindow() == m_pContainer->m_hwnd) { + DM_SaveLocale(wParam, lParam); + m_message.SendMsg(EM_SETLANGOPTIONS, 0, (LPARAM)m_message.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + return 1; + } + break; + + case WM_ERASEBKGND: + return(CSkin::m_skinEnabled ? 0 : 1); + + // sent by smileyadd when the smiley selection window dies + // just grab the focus :) + case WM_USER + 100: + SetFocus(m_message.GetHwnd()); + break; + + case WM_CONTEXTMENU: + POINT pt; + if (lParam == 0xFFFFFFFF) { + CHARRANGE sel; + m_message.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel); + m_message.SendMsg(EM_POSFROMCHAR, (WPARAM)&pt, (LPARAM)sel.cpMax); + ClientToScreen(m_message.GetHwnd(), &pt); + } + else { + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + } + + ShowPopupMenu(this, IDC_MESSAGE, m_message.GetHwnd(), pt); + return TRUE; + } + return 0; +} + ///////////////////////////////////////////////////////////////////////////////////////// // dialog procedure diff --git a/plugins/TabSRMM/src/msgs.h b/plugins/TabSRMM/src/msgs.h index c2f7822141..308429b22c 100644 --- a/plugins/TabSRMM/src/msgs.h +++ b/plugins/TabSRMM/src/msgs.h @@ -237,6 +237,7 @@ struct SESSION_INFO; class CTabBaseDlg : public CSrmmBaseDialog { + typedef CSrmmBaseDialog CSuper; friend class CInfoPanel; protected: @@ -440,11 +441,16 @@ public: class CSrmmWindow : public CTabBaseDlg { + typedef CTabBaseDlg CSuper; + virtual CThumbBase* tabCreateThumb(CProxyWindow *pProxy) const override; virtual void tabClearLog() override; CCtrlButton m_btnOk, m_btnAdd, m_btnQuote, m_btnCancelAdd; + virtual LRESULT WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) override; + virtual LRESULT WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) override; + void LoadContactAvatar(); void LoadOwnAvatar(); void MsgWindowUpdateState(UINT msg); @@ -482,19 +488,27 @@ public: class CChatRoomDlg : public CTabBaseDlg { + typedef CTabBaseDlg CSuper; + HWND m_hwndFilter; CCtrlButton m_btnOk; - static LRESULT CALLBACK MessageSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - static LRESULT CALLBACK NicklistSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + virtual LRESULT WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) override; + virtual LRESULT WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) override; + virtual LRESULT WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam) override; + static INT_PTR CALLBACK FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); virtual CThumbBase* tabCreateThumb(CProxyWindow *pProxy) const override; virtual void tabClearLog() override; -public: + bool TabAutoComplete(); + int m_iSearchItem; + BOOL m_iSavedSpaces; wchar_t m_wszSearch[255]; + wchar_t *m_wszSearchQuery, *m_wszSearchResult; + SESSION_INFO *m_pLastSession; public: CChatRoomDlg(SESSION_INFO*); @@ -661,7 +675,6 @@ struct TIconDescW #define TM_USER (WM_USER+300) -#define EM_SUBCLASSED (TM_USER+0x101) #define EM_SEARCHSCROLLER (TM_USER+0x103) #define EM_VALIDATEBOTTOM (TM_USER+0x104) #define EM_THEMECHANGED (TM_USER+0x105) diff --git a/plugins/TabSRMM/src/themes.cpp b/plugins/TabSRMM/src/themes.cpp index 112fd63be2..749e08ab01 100644 --- a/plugins/TabSRMM/src/themes.cpp +++ b/plugins/TabSRMM/src/themes.cpp @@ -1930,8 +1930,8 @@ UINT CSkin::NcCalcRichEditFrame(HWND hwnd, const CTabBaseDlg *mwdat, UINT skinID ShowScrollBar(hwnd, SB_VERT, FALSE); } - LRESULT orig = mir_callNextSubclass(hwnd, MyWndProc, msg, wParam, lParam); - if (0 == mwdat) + LRESULT orig = (MyWndProc == nullptr) ? WVR_REDRAW : mir_callNextSubclass(hwnd, MyWndProc, msg, wParam, lParam); + if (mwdat == nullptr) return orig; if (CSkin::m_skinEnabled) { @@ -1970,8 +1970,8 @@ UINT CSkin::NcCalcRichEditFrame(HWND hwnd, const CTabBaseDlg *mwdat, UINT skinID UINT CSkin::DrawRichEditFrame(HWND hwnd, const CTabBaseDlg *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc) { // do default processing (otherwise, NO scrollbar as it is painted in NC_PAINT) - LRESULT result = mir_callNextSubclass(hwnd, OldWndProc, msg, wParam, lParam); - if (0 == mwdat) + LRESULT result = (OldWndProc == nullptr) ? 0 : mir_callNextSubclass(hwnd, OldWndProc, msg, wParam, lParam); + if (mwdat == nullptr) return result; BOOL isEditNotesReason = ((mwdat->m_bEditNotesActive) && (skinID == ID_EXTBKINPUTAREA)); @@ -2023,8 +2023,7 @@ UINT CSkin::DrawRichEditFrame(HWND hwnd, const CTabBaseDlg *mwdat, UINT skinID, FillRect(hdc, &rcWindow, br); DeleteObject(br); } - else - DrawThemeBackground(mwdat->m_hTheme, hdc, 1, 1, &rcWindow, &rcWindow); + else DrawThemeBackground(mwdat->m_hTheme, hdc, 1, 1, &rcWindow, &rcWindow); } ReleaseDC(hwnd, hdc); return result; diff --git a/plugins/TabSRMM/src/utils.cpp b/plugins/TabSRMM/src/utils.cpp index a2cac5183f..d9dec206a3 100644 --- a/plugins/TabSRMM/src/utils.cpp +++ b/plugins/TabSRMM/src/utils.cpp @@ -982,7 +982,7 @@ size_t Utils::CopyToClipBoard(const wchar_t *str, const HWND hwndOwner) LRESULT Utils::WMCopyHandler(HWND hwnd, WNDPROC oldWndProc, UINT msg, WPARAM wParam, LPARAM lParam) { - LRESULT result = mir_callNextSubclass(hwnd, oldWndProc, msg, wParam, lParam); + LRESULT result = (oldWndProc == nullptr) ? 0 : mir_callNextSubclass(hwnd, oldWndProc, msg, wParam, lParam); ptrA szFromStream(Message_GetFromStream(hwnd, SF_TEXT | SFF_SELECTION)); if (szFromStream != nullptr) { -- cgit v1.2.3