From 7a948f1ef804ecd9971b0869e0591c22944fa6da Mon Sep 17 00:00:00 2001 From: George Hazan Date: Wed, 2 Oct 2019 20:42:44 +0300 Subject: merge with SrmmLogContainer --- src/core/stdmsg/src/chat_window.cpp | 51 ++++---- src/core/stdmsg/src/msgdialog.cpp | 170 ++++-------------------- src/core/stdmsg/src/msglog.cpp | 253 ++++++++++++++++++++++++++---------- src/core/stdmsg/src/msgs.h | 34 +++-- src/core/stdmsg/src/srmm.cpp | 3 + src/core/stdmsg/src/stdafx.h | 3 + src/core/stdmsg/src/tabs.cpp | 2 +- 7 files changed, 269 insertions(+), 247 deletions(-) (limited to 'src/core/stdmsg') diff --git a/src/core/stdmsg/src/chat_window.cpp b/src/core/stdmsg/src/chat_window.cpp index a33d411064..a2f9f2e364 100644 --- a/src/core/stdmsg/src/chat_window.cpp +++ b/src/core/stdmsg/src/chat_window.cpp @@ -62,7 +62,7 @@ void CMsgDialog::UpdateOptions() Window_SetIcon_IcoLib(m_pOwner->GetHwnd(), g_plugin.getIconHandle(IDI_CHANMGR)); - m_log.SendMsg(EM_SETBKGNDCOLOR, 0, g_Settings.crLogBackground); + m_pLog->UpdateOptions(); CHARFORMAT2 cf; cf.cbSize = sizeof(CHARFORMAT2); @@ -111,18 +111,19 @@ void CMsgDialog::UpdateStatusBar() ///////////////////////////////////////////////////////////////////////////////////////// -void CMsgDialog::StreamInEvents(LOGINFO *lin, bool bRedraw) +void CLogWindow::LogEvents(LOGINFO *lin, bool bRedraw) { - if (m_hwnd == nullptr || lin == nullptr || m_si == nullptr) + auto *si = m_pDlg.m_si; + if (lin == nullptr || si == nullptr) return; - if (!bRedraw && m_si->iType == GCW_CHATROOM && m_bFilterEnabled && (m_iLogFilterFlags & lin->iType) == 0) + if (!bRedraw && si->iType == GCW_CHATROOM && m_pDlg.m_bFilterEnabled && (m_pDlg.m_iLogFilterFlags & lin->iType) == 0) return; LOGSTREAMDATA streamData; memset(&streamData, 0, sizeof(streamData)); - streamData.hwnd = m_log.GetHwnd(); - streamData.si = m_si; + streamData.hwnd = m_rtf.GetHwnd(); + streamData.si = si; streamData.lin = lin; streamData.bStripFormat = FALSE; @@ -135,20 +136,20 @@ void CMsgDialog::StreamInEvents(LOGINFO *lin, bool bRedraw) SCROLLINFO scroll; scroll.cbSize = sizeof(SCROLLINFO); scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; - GetScrollInfo(m_log.GetHwnd(), SB_VERT, &scroll); + GetScrollInfo(m_rtf.GetHwnd(), SB_VERT, &scroll); POINT point = {}; - m_log.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&point); + m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&point); // do not scroll to bottom if there is a selection CHARRANGE oldsel, sel; - m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldsel); + m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldsel); if (oldsel.cpMax != oldsel.cpMin) - m_log.SendMsg(WM_SETREDRAW, FALSE, 0); + m_rtf.SendMsg(WM_SETREDRAW, FALSE, 0); //set the insertion point at the bottom - sel.cpMin = sel.cpMax = m_log.GetRichTextLength(); - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength(); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); // fix for the indent... must be a M$ bug if (sel.cpMax == 0) @@ -163,14 +164,14 @@ void CMsgDialog::StreamInEvents(LOGINFO *lin, bool bRedraw) g_chatApi.logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); ReleaseDC(nullptr, hdc); - m_log.SendMsg(WM_SETREDRAW, FALSE, 0); + m_rtf.SendMsg(WM_SETREDRAW, FALSE, 0); bFlag = true; } // stream in the event(s) streamData.lin = lin; streamData.bRedraw = bRedraw; - m_log.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream); + m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream); // do smileys if (g_dat.bSmileyInstalled && (bRedraw || (lin->ptszText && lin->iType != GC_EVENT_JOIN && lin->iType != GC_EVENT_NICK && lin->iType != GC_EVENT_ADDSTATUS && lin->iType != GC_EVENT_REMOVESTATUS))) { @@ -182,11 +183,11 @@ void CMsgDialog::StreamInEvents(LOGINFO *lin, bool bRedraw) SMADD_RICHEDIT3 sm = {}; sm.cbSize = sizeof(sm); - sm.hwndRichEditControl = m_log.GetHwnd(); - sm.Protocolname = m_si->pszModule; + sm.hwndRichEditControl = m_rtf.GetHwnd(); + sm.Protocolname = si->pszModule; sm.rangeToReplace = bRedraw ? nullptr : &newsel; sm.disableRedraw = TRUE; - sm.hContact = m_si->hContact; + sm.hContact = si->hContact; CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm); } @@ -194,21 +195,21 @@ void CMsgDialog::StreamInEvents(LOGINFO *lin, bool bRedraw) if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50) ScrollToBottom(); else - m_log.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point); + m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point); // do we need to restore the selection if (oldsel.cpMax != oldsel.cpMin) { - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldsel); - m_log.SendMsg(WM_SETREDRAW, TRUE, 0); - InvalidateRect(m_log.GetHwnd(), nullptr, TRUE); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldsel); + m_rtf.SendMsg(WM_SETREDRAW, TRUE, 0); + InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE); } // need to invalidate the window if (bFlag) { - sel.cpMin = sel.cpMax = m_log.GetRichTextLength(); - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); - m_log.SendMsg(WM_SETREDRAW, TRUE, 0); - InvalidateRect(m_log.GetHwnd(), nullptr, TRUE); + sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength(); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + m_rtf.SendMsg(WM_SETREDRAW, TRUE, 0); + InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE); } } diff --git a/src/core/stdmsg/src/msgdialog.cpp b/src/core/stdmsg/src/msgdialog.cpp index d1e6bfdb9c..7081150531 100644 --- a/src/core/stdmsg/src/msgdialog.cpp +++ b/src/core/stdmsg/src/msgdialog.cpp @@ -143,9 +143,6 @@ bool CMsgDialog::OnInitDialog() int nMax = CallProtoService(m_szProto, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, m_hContact); if (nMax) m_message.SendMsg(EM_EXLIMITTEXT, 0, nMax); - - // get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF - m_log.SendMsg(EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0); } m_wOldStatus = m_wStatus; @@ -157,9 +154,6 @@ bool CMsgDialog::OnInitDialog() m_iSplitterY = g_plugin.getDword(g_dat.bSavePerContact ? m_hContact : 0, "splitterPos", m_minEditInit.bottom - m_minEditInit.top); UpdateSizeBar(); - m_log.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_SCROLL); - m_log.SendMsg(EM_AUTOURLDETECT, TRUE, 0); - m_message.SendMsg(EM_SETEVENTMASK, 0, ENM_CHANGE); if (isChat()) { @@ -384,7 +378,7 @@ void CMsgDialog::onClick_NickList(CCtrlButton *pButton) m_bNicklistEnabled = !m_bNicklistEnabled; pButton->SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bNicklistEnabled ? IDI_NICKLIST : IDI_NICKLIST2, FALSE)); - ScrollToBottom(); + m_pLog->ScrollToBottom(); Resize(); } @@ -479,17 +473,21 @@ int CMsgDialog::Resizer(UTILRESIZECONTROL *urc) urc->rcItem.top = 2; urc->rcItem.left = 0; urc->rcItem.right = bNick ? urc->dlgNewSize.cx - m_iSplitterX : urc->dlgNewSize.cx; - LBL_CalcBottom: urc->rcItem.bottom = urc->dlgNewSize.cy - m_iSplitterY; if (!bToolbar) urc->rcItem.bottom += 20; + m_rcLog = urc->rcItem; return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; case IDC_SRMM_NICKLIST: urc->rcItem.top = 2; urc->rcItem.right = urc->dlgNewSize.cx; urc->rcItem.left = urc->dlgNewSize.cx - m_iSplitterX + 2; - goto LBL_CalcBottom; +LBL_CalcBottom: + urc->rcItem.bottom = urc->dlgNewSize.cy - m_iSplitterY; + if (!bToolbar) + urc->rcItem.bottom += 20; + return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; case IDC_SPLITTERX: urc->rcItem.top = 1; @@ -517,6 +515,7 @@ int CMsgDialog::Resizer(UTILRESIZECONTROL *urc) if (!g_dat.bShowButtons) urc->rcItem.top = 2; urc->rcItem.bottom = urc->dlgNewSize.cy - m_iSplitterY; + m_rcLog = urc->rcItem; return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; case IDC_SPLITTERY: @@ -605,10 +604,8 @@ INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_SIZE: if (!IsIconic(m_hwnd)) { - bool bottomScroll; if (isChat()) { - bottomScroll = false; bool bSend = g_dat.bSendButton; bool bNick = m_si->iType != GCW_SERVER && m_bNicklistEnabled; @@ -632,29 +629,18 @@ INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) } } else { - bottomScroll = true; SetupStatusBar(); - - if (GetWindowLongPtr(m_log.GetHwnd(), GWL_STYLE) & WS_VSCROLL) { - SCROLLINFO si = {}; - si.cbSize = sizeof(si); - si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; - GetScrollInfo(m_log.GetHwnd(), SB_VERT, &si); - bottomScroll = (si.nPos + (int)si.nPage + 5) >= si.nMax; - } } CSuper::DlgProc(uMsg, wParam, lParam); // call built-in resizer SetButtonsPos(m_hwnd, isChat()); + m_pLog->Resize(); InvalidateRect(m_pOwner->m_hwndStatus, nullptr, true); RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); RedrawWindow(m_btnOk.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); if (g_dat.bShowAvatar && m_avatarPic) RedrawWindow(m_avatar.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); - - if (bottomScroll) - ScrollToBottom(); } return TRUE; @@ -682,21 +668,15 @@ INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) } if (hDbEvent != m_hDbEventFirst && db_event_next(m_hContact, hDbEvent) == 0) - StreamInEvents(hDbEvent, 1, 1); + m_pLog->LogEvents(hDbEvent, 1, 1); else RemakeLog(); // Flash window *only* for messages, not for custom events if (isMessage && !isSent) { if (isActive) { - if (GetWindowLongPtr(m_log.GetHwnd(), GWL_STYLE) & WS_VSCROLL) { - SCROLLINFO si = {}; - si.cbSize = sizeof(si); - si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; - GetScrollInfo(m_log.GetHwnd(), SB_VERT, &si); - if ((si.nPos + (int)si.nPage + 5) < si.nMax) - StartFlash(); - } + if (m_pLog->AtBottom()) + StartFlash(); } else StartFlash(); } @@ -928,11 +908,11 @@ INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) case DM_UPDATETITLE: if (lParam != 0) { if (isChat()) { - if (lParam != m_hContact) + if ((MCONTACT)lParam != m_hContact) break; } else { - bool bIsMe = (lParam == m_hContact) || (m_bIsMeta && db_mc_getMeta(lParam) == m_hContact); + bool bIsMe = ((MCONTACT)lParam == m_hContact) || (m_bIsMeta && db_mc_getMeta(lParam) == m_hContact); if (!bIsMe) break; } @@ -951,7 +931,7 @@ INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_LBUTTONDBLCLK: if (LOWORD(lParam) < 30) - ScrollToBottom(); + m_pLog->ScrollToBottom(); break; case WM_ACTIVATE: @@ -971,84 +951,6 @@ INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) ///////////////////////////////////////////////////////////////////////////////////////// -static const CHARRANGE rangeAll = { 0, -1 }; - -LRESULT CMsgDialog::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) -{ - CHARRANGE sel; - - switch(msg) { - case WM_CONTEXTMENU: - // we display context menu here only for private chats, group chats are processed by the core - if (!isChat()) { - POINT pt; - GetCursorPos(&pt); - - SetFocus(m_log.GetHwnd()); - - HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXT)); - HMENU hSubMenu = GetSubMenu(hMenu, 0); - TranslateMenu(hSubMenu); - - CHARRANGE all = { 0, -1 }; - m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel); - if (sel.cpMin == sel.cpMax) - EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); - - switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_hwnd, nullptr)) { - case IDM_COPY: - m_log.SendMsg(WM_COPY, 0, 0); - break; - case IDM_COPYALL: - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); - m_log.SendMsg(WM_COPY, 0, 0); - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); - break; - case IDM_SELECTALL: - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); - break; - case IDM_CLEAR: - ClearLog(); - m_hDbEventFirst = 0; - break; - } - DestroyMenu(hSubMenu); - DestroyMenu(hMenu); - return TRUE; - } - break; - - case WM_LBUTTONUP: - if (isChat()) { - m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)& sel); - if (sel.cpMin != sel.cpMax) { - m_log.SendMsg(WM_COPY, 0, 0); - sel.cpMin = sel.cpMax; - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)& sel); - } - SetFocus(m_message.GetHwnd()); - } - break; - - case WM_KEYDOWN: - bool isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; - bool isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - bool isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; - - if (wParam == 0x57 && isCtrl && !isAlt) { // ctrl-w (close window) - CloseTab(); - return TRUE; - } - - if (ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) - return FALSE; - } - - return CSuper::WndProc_Log(msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - LRESULT CMsgDialog::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { @@ -1065,11 +967,13 @@ LRESULT CMsgDialog::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam) ///////////////////////////////////////////////////////////////////////////////////////// +static const CHARRANGE rangeAll = { 0, -1 }; + LRESULT CMsgDialog::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_MOUSEWHEEL: - m_log.SendMsg(WM_MOUSEWHEEL, wParam, lParam); + LOG()->WndProc(msg, wParam, lParam); m_iLastEnterTime = 0; return TRUE; @@ -1302,7 +1206,7 @@ LRESULT CMsgDialog::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) } if (wParam == VK_NEXT || wParam == VK_PRIOR) { - m_log.SendMsg(msg, wParam, lParam); + ((CLogWindow *)m_pLog)->WndProc(msg, wParam, lParam); m_iLastEnterTime = 0; return TRUE; } @@ -1375,21 +1279,6 @@ bool CMsgDialog::IsActive() const return bRes; } -void CMsgDialog::ScrollToBottom() -{ - if (GetWindowLongPtr(m_log.GetHwnd(), GWL_STYLE) & WS_VSCROLL) { - SCROLLINFO si = {}; - si.cbSize = sizeof(si); - si.fMask = SIF_PAGE | SIF_RANGE; - GetScrollInfo(m_log.GetHwnd(), SB_VERT, &si); - - si.fMask = SIF_POS; - si.nPos = si.nMax - si.nPage; - SetScrollInfo(m_log.GetHwnd(), SB_VERT, &si, TRUE); - m_log.SendMsg(WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); - } -} - void CMsgDialog::StartFlash() { ::SetTimer(m_hwnd, TIMERID_FLASHWND, 900, nullptr); @@ -1493,9 +1382,8 @@ void CMsgDialog::OnOptionsApplied(bool bUpdateAvatar) UpdateTitle(); Resize(); - COLORREF colour = g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR); - m_log.SendMsg(EM_SETBKGNDCOLOR, 0, colour); - m_message.SendMsg(EM_SETBKGNDCOLOR, 0, colour); + m_pLog->UpdateOptions(); + m_message.SendMsg(EM_SETBKGNDCOLOR, 0, g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR)); // avatar stuff m_avatarPic = nullptr; @@ -1520,19 +1408,7 @@ void CMsgDialog::OnOptionsApplied(bool bUpdateAvatar) cf.dwMask = CFM_COLOR; m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (WPARAM)&cf); - // configure message history for proper RTL formatting - PARAFORMAT2 pf2; - memset(&pf2, 0, sizeof(pf2)); - pf2.cbSize = sizeof(pf2); - - pf2.wEffects = PFE_RTLPARA; - pf2.dwMask = PFM_RTLPARA; - ClearLog(); - m_log.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2); - pf2.wEffects = 0; - m_log.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2); - m_log.SendMsg(EM_SETLANGOPTIONS, 0, m_log.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); - + m_pLog->Clear(); RemakeLog(); FixTabIcons(); } @@ -1621,7 +1497,7 @@ void CMsgDialog::NotifyTyping(int mode) void CMsgDialog::RemakeLog() { - StreamInEvents(m_hDbEventFirst, -1, 0); + m_pLog->LogEvents(m_hDbEventFirst, -1, 0); } void CMsgDialog::ProcessFileDrop(HDROP hDrop) diff --git a/src/core/stdmsg/src/msglog.cpp b/src/core/stdmsg/src/msglog.cpp index b48c2365cd..bb21d6c782 100644 --- a/src/core/stdmsg/src/msglog.cpp +++ b/src/core/stdmsg/src/msglog.cpp @@ -393,75 +393,141 @@ static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG return 0; } -void CMsgDialog::StreamInEvents(MEVENT hDbEventFirst, int count, bool bAppend) +#define RTFPICTHEADERMAXSIZE 78 +void LoadMsgLogIcons(void) +{ + HBRUSH hBkgBrush = CreateSolidBrush(g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR)); + + BITMAPINFOHEADER bih = { sizeof(bih) }; + bih.biBitCount = 24; + bih.biCompression = BI_RGB; + bih.biHeight = 10; + bih.biPlanes = 1; + bih.biWidth = 10; + int widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4; + + RECT rc; + rc.top = rc.left = 0; + rc.right = bih.biWidth; + rc.bottom = bih.biHeight; + + HDC hdc = GetDC(nullptr); + HBITMAP hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight); + HDC hdcMem = CreateCompatibleDC(hdc); + PBYTE pBmpBits = (PBYTE)mir_alloc(widthBytes * bih.biHeight); + + for (int i = 0; i < _countof(pLogIconBmpBits); i++) { + HICON hIcon = IcoLib_GetIconByHandle(iconList[i].hIcolib); + size_t size = RTFPICTHEADERMAXSIZE + (bih.biSize + widthBytes * bih.biHeight) * 2; + pLogIconBmpBits[i] = (char*)mir_alloc(size); + size_t rtfHeaderSize = mir_snprintf(pLogIconBmpBits[i], size, "{\\pict\\dibitmap0\\wbmbitspixel%u\\wbmplanes1\\wbmwidthbytes%u\\picw%u\\pich%u ", bih.biBitCount, widthBytes, bih.biWidth, bih.biHeight); + HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); + FillRect(hdcMem, &rc, hBkgBrush); + DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, nullptr, DI_NORMAL); + IcoLib_ReleaseIcon(hIcon); + + SelectObject(hdcMem, hoBmp); + GetDIBits(hdc, hBmp, 0, bih.biHeight, pBmpBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS); + + char *szDest = pLogIconBmpBits[i] + rtfHeaderSize; + bin2hex(&bih, sizeof(bih), szDest); szDest += sizeof(bih) * 2; + bin2hex(pBmpBits, widthBytes * bih.biHeight, szDest); szDest += widthBytes * bih.biHeight * 2; + mir_strcpy(szDest, "}"); + } + mir_free(pBmpBits); + DeleteDC(hdcMem); + DeleteObject(hBmp); + ReleaseDC(nullptr, hdc); + DeleteObject(hBkgBrush); +} + +void FreeMsgLogIcons(void) +{ + for (auto &it : pLogIconBmpBits) + mir_free(it); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CLogWindow::Attach() +{ + CSuper::Attach(); + + // get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF + m_rtf.SendMsg(EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0); + m_rtf.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_SCROLL); + m_rtf.SendMsg(EM_AUTOURLDETECT, TRUE, 0); +} + +void CLogWindow::LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) { CHARRANGE oldSel, sel; BOOL bottomScroll = TRUE; POINT scrollPos; - m_log.SendMsg(WM_SETREDRAW, FALSE, 0); - m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldSel); + m_rtf.SendMsg(WM_SETREDRAW, FALSE, 0); + m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldSel); LogStreamData streamData = {}; - streamData.hContact = m_hContact; + streamData.hContact = m_pDlg.m_hContact; streamData.hDbEvent = hDbEventFirst; - streamData.dlgDat = this; + streamData.dlgDat = &m_pDlg; streamData.eventsToInsert = count; - streamData.isEmpty = !bAppend || GetWindowTextLength(m_log.GetHwnd()) == 0; + streamData.isEmpty = !bAppend || GetWindowTextLength(m_rtf.GetHwnd()) == 0; EDITSTREAM stream = {}; stream.pfnCallback = LogStreamInEvents; stream.dwCookie = (DWORD_PTR)&streamData; if (!streamData.isEmpty) { - bottomScroll = (GetFocus() != m_log.GetHwnd()); - if (bottomScroll && (GetWindowLongPtr(m_log.GetHwnd(), GWL_STYLE) & WS_VSCROLL)) { + bottomScroll = (GetFocus() != m_rtf.GetHwnd()); + if (bottomScroll && (GetWindowLongPtr(m_rtf.GetHwnd(), GWL_STYLE) & WS_VSCROLL)) { SCROLLINFO si = {}; si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; - GetScrollInfo(m_log.GetHwnd(), SB_VERT, &si); + GetScrollInfo(m_rtf.GetHwnd(), SB_VERT, &si); bottomScroll = (si.nPos + (int)si.nPage) >= si.nMax; } if (!bottomScroll) - m_log.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&scrollPos); + m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&scrollPos); } FINDTEXTEXA fi; if (bAppend) { sel.cpMin = sel.cpMax = -1; - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); fi.chrg.cpMin = 0; } else { GETTEXTLENGTHEX gtxl = { 0 }; gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS; gtxl.codepage = 1200; - fi.chrg.cpMin = m_log.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)>xl, 0); + fi.chrg.cpMin = m_rtf.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)>xl, 0); - sel.cpMin = sel.cpMax = m_log.GetRichTextLength(); - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength(); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); } mir_strcpy(szSep2, bAppend ? "\\par\\sl0" : "\\sl1000"); mir_strcpy(szSep2_RTL, bAppend ? "\\rtlpar\\rtlmark\\par\\sl1000" : "\\sl1000"); - m_log.SendMsg(EM_STREAMIN, bAppend ? SFF_SELECTION | SF_RTF : SF_RTF, (LPARAM)&stream); + m_rtf.SendMsg(EM_STREAMIN, bAppend ? SFF_SELECTION | SF_RTF : SF_RTF, (LPARAM)&stream); if (bottomScroll) { sel.cpMin = sel.cpMax = -1; - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); } else { - m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldSel); - m_log.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&scrollPos); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldSel); + m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&scrollPos); } if (g_dat.bSmileyInstalled) { SMADD_RICHEDIT3 smre; smre.cbSize = sizeof(SMADD_RICHEDIT3); - smre.hwndRichEditControl = m_log.GetHwnd(); + smre.hwndRichEditControl = m_rtf.GetHwnd(); - MCONTACT hContact = db_mc_getSrmmSub(m_hContact); - smre.Protocolname = (hContact != 0) ? GetContactProto(hContact) : m_szProto; + MCONTACT hContact = db_mc_getSrmmSub(m_pDlg.m_hContact); + smre.Protocolname = (hContact != 0) ? GetContactProto(hContact) : m_pDlg.m_szProto; if (fi.chrg.cpMin > 0) { sel.cpMin = fi.chrg.cpMin; @@ -471,70 +537,125 @@ void CMsgDialog::StreamInEvents(MEVENT hDbEventFirst, int count, bool bAppend) else smre.rangeToReplace = nullptr; smre.disableRedraw = TRUE; - smre.hContact = m_hContact; + smre.hContact = m_pDlg.m_hContact; smre.flags = 0; CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&smre); } - m_log.SendMsg(WM_SETREDRAW, TRUE, 0); + m_rtf.SendMsg(WM_SETREDRAW, TRUE, 0); if (bottomScroll) { ScrollToBottom(); - RedrawWindow(m_log.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); + RedrawWindow(m_rtf.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); } - m_hDbEventLast = streamData.hDbEventLast; + m_pDlg.m_hDbEventLast = streamData.hDbEventLast; } -#define RTFPICTHEADERMAXSIZE 78 -void LoadMsgLogIcons(void) +void CLogWindow::LogEvents(DBEVENTINFO*, bool) { - HBRUSH hBkgBrush = CreateSolidBrush(g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR)); +} - BITMAPINFOHEADER bih = { sizeof(bih) }; - bih.biBitCount = 24; - bih.biCompression = BI_RGB; - bih.biHeight = 10; - bih.biPlanes = 1; - bih.biWidth = 10; - int widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4; +void CLogWindow::UpdateOptions() +{ + if (m_pDlg.isChat()) + m_rtf.SendMsg(EM_SETBKGNDCOLOR, 0, g_Settings.crLogBackground); + else { + // configure message history for proper RTL formatting + PARAFORMAT2 pf2; + memset(&pf2, 0, sizeof(pf2)); + pf2.cbSize = sizeof(pf2); - RECT rc; - rc.top = rc.left = 0; - rc.right = bih.biWidth; - rc.bottom = bih.biHeight; + pf2.wEffects = PFE_RTLPARA; + pf2.dwMask = PFM_RTLPARA; + m_rtf.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2); - HDC hdc = GetDC(nullptr); - HBITMAP hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight); - HDC hdcMem = CreateCompatibleDC(hdc); - PBYTE pBmpBits = (PBYTE)mir_alloc(widthBytes * bih.biHeight); + pf2.wEffects = 0; + m_rtf.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2); - for (int i = 0; i < _countof(pLogIconBmpBits); i++) { - HICON hIcon = IcoLib_GetIconByHandle(iconList[i].hIcolib); - size_t size = RTFPICTHEADERMAXSIZE + (bih.biSize + widthBytes * bih.biHeight) * 2; - pLogIconBmpBits[i] = (char*)mir_alloc(size); - size_t rtfHeaderSize = mir_snprintf(pLogIconBmpBits[i], size, "{\\pict\\dibitmap0\\wbmbitspixel%u\\wbmplanes1\\wbmwidthbytes%u\\picw%u\\pich%u ", bih.biBitCount, widthBytes, bih.biWidth, bih.biHeight); - HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); - FillRect(hdcMem, &rc, hBkgBrush); - DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, nullptr, DI_NORMAL); - IcoLib_ReleaseIcon(hIcon); + m_rtf.SendMsg(EM_SETLANGOPTIONS, 0, m_rtf.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + m_rtf.SendMsg(EM_SETBKGNDCOLOR, 0, g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR)); + } +} - SelectObject(hdcMem, hoBmp); - GetDIBits(hdc, hBmp, 0, bih.biHeight, pBmpBits, (BITMAPINFO*)&bih, DIB_RGB_COLORS); +///////////////////////////////////////////////////////////////////////////////////////// - char *szDest = pLogIconBmpBits[i] + rtfHeaderSize; - bin2hex(&bih, sizeof(bih), szDest); szDest += sizeof(bih) * 2; - bin2hex(pBmpBits, widthBytes * bih.biHeight, szDest); szDest += widthBytes * bih.biHeight * 2; - mir_strcpy(szDest, "}"); +static const CHARRANGE rangeAll = { 0, -1 }; + +INT_PTR CLogWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + CHARRANGE sel; + + switch (msg) { + case WM_CONTEXTMENU: + // we display context menu here only for private chats, group chats are processed by the core + if (!m_pDlg.isChat()) { + POINT pt; + GetCursorPos(&pt); + + SetFocus(m_rtf.GetHwnd()); + + HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXT)); + HMENU hSubMenu = GetSubMenu(hMenu, 0); + TranslateMenu(hSubMenu); + + CHARRANGE all = { 0, -1 }; + m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) + EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); + + switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_pDlg.m_hwnd, nullptr)) { + case IDM_COPY: + m_rtf.SendMsg(WM_COPY, 0, 0); + break; + case IDM_COPYALL: + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); + m_rtf.SendMsg(WM_COPY, 0, 0); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + break; + case IDM_SELECTALL: + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); + break; + case IDM_CLEAR: + Clear(); + m_pDlg.m_hDbEventFirst = 0; + break; + } + DestroyMenu(hSubMenu); + DestroyMenu(hMenu); + return TRUE; + } + break; + + case WM_LBUTTONUP: + if (m_pDlg.isChat()) { + m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin != sel.cpMax) { + m_rtf.SendMsg(WM_COPY, 0, 0); + sel.cpMin = sel.cpMax; + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + } + SetFocus(m_pDlg.m_message.GetHwnd()); + } + break; + + case WM_KEYDOWN: + bool isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; + bool isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; + bool isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; + + if (wParam == 0x57 && isCtrl && !isAlt) { // ctrl-w (close window) + m_pDlg.CloseTab(); + return TRUE; + } + + if (m_pDlg.ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) + return FALSE; } - mir_free(pBmpBits); - DeleteDC(hdcMem); - DeleteObject(hBmp); - ReleaseDC(nullptr, hdc); - DeleteObject(hBkgBrush); + + return CSuper::WndProc(msg, wParam, lParam); } -void FreeMsgLogIcons(void) +CSrmmLogWindow *logBuilder(CMsgDialog &pDlg) { - for (auto &it : pLogIconBmpBits) - mir_free(it); + return new CLogWindow(pDlg); } diff --git a/src/core/stdmsg/src/msgs.h b/src/core/stdmsg/src/msgs.h index 5a876ac547..ed2a647fe8 100644 --- a/src/core/stdmsg/src/msgs.h +++ b/src/core/stdmsg/src/msgs.h @@ -32,10 +32,29 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define EVENTTYPE_JABBER_CHATSTATES 2000 #define EVENTTYPE_JABBER_PRESENCE 2001 +class CLogWindow : public CRtfLogWindow +{ + typedef CRtfLogWindow CSuper; + +public: + CLogWindow(CMsgDialog &pDlg) : + CSuper(pDlg) + {} + + void Attach() override; + void LogEvents(MEVENT hDbEventFirst, int count, bool bAppend) override; + void LogEvents(DBEVENTINFO *dbei, bool bAppend); + void LogEvents(struct LOGINFO *, bool) override; + void UpdateOptions() override; + + INT_PTR WndProc(UINT msg, WPARAM wParam, LPARAM lParam) override; +}; + class CMsgDialog : public CSrmmBaseDialog { - typedef CSrmmBaseDialog CSuper; + friend class CLogWindow; friend class CTabbedWindow; + typedef CSrmmBaseDialog CSuper; void Init(void); void NotifyTyping(int mode); @@ -43,14 +62,12 @@ class CMsgDialog : public CSrmmBaseDialog void ShowAvatar(void); void ShowTime(bool bForce); void SetupStatusBar(void); - void StreamInEvents(MEVENT hDbEventFirst, int count, bool bAppend); void UpdateIcon(WPARAM wParam); void UpdateLastMessage(void); void UpdateSizeBar(void); static INT_PTR CALLBACK FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -protected: CCtrlBase m_avatar; CCtrlButton m_btnOk; @@ -63,6 +80,7 @@ protected: int m_iSplitterX, m_iSplitterY; SIZE m_minEditBoxSize; RECT m_minEditInit; + RECT m_rcLog; // tab autocomplete int m_iTabStart = 0; @@ -93,7 +111,6 @@ public: int Resizer(UTILRESIZECONTROL *urc) override; INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override; - LRESULT WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) override; LRESULT WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) override; LRESULT WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam) override; @@ -115,11 +132,14 @@ public: void UpdateReadChars(void); - __forceinline MCONTACT getActiveContact() const - { + __forceinline MCONTACT getActiveContact() const { return (m_bIsMeta) ? db_mc_getSrmmSub(m_hContact) : m_hContact; } + __forceinline CLogWindow* LOG() { + return ((CLogWindow *)m_pLog); + } + MEVENT m_hDbEventFirst, m_hDbEventLast; int m_avatarWidth = 0, m_avatarHeight = 0; @@ -137,9 +157,7 @@ public: void CloseTab() override; bool IsActive() const override; void LoadSettings() override; - void ScrollToBottom() override; void SetStatusText(const wchar_t *, HICON) override; - void StreamInEvents(LOGINFO *lin, bool bRedraw) override; void ShowFilterMenu() override; void UpdateNickList() override; void UpdateOptions() override; diff --git a/src/core/stdmsg/src/srmm.cpp b/src/core/stdmsg/src/srmm.cpp index ebd0e2519d..6dad345b8d 100644 --- a/src/core/stdmsg/src/srmm.cpp +++ b/src/core/stdmsg/src/srmm.cpp @@ -52,6 +52,8 @@ extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_SRMM, int CMPlugin::Load() { + hLogger = RegisterSrmmLog("built-in", L"StdMsg internal log", &logBuilder); + Load_ChatModule(); return LoadSendRecvMessageModule(); } @@ -60,6 +62,7 @@ int CMPlugin::Load() int CMPlugin::Unload() { + UnregisterSrmmLog(hLogger); SplitmsgShutdown(); Unload_ChatModule(); return 0; diff --git a/src/core/stdmsg/src/stdafx.h b/src/core/stdmsg/src/stdafx.h index 918f63a017..ea7ed72a3e 100644 --- a/src/core/stdmsg/src/stdafx.h +++ b/src/core/stdmsg/src/stdafx.h @@ -155,6 +155,8 @@ struct CMPlugin : public PLUGIN { CMPlugin(); + HANDLE hLogger; + int Load() override; int Unload() override; }; @@ -171,6 +173,7 @@ void Load_ChatModule(void); // log.cpp char* Log_CreateRtfHeader(void); +CSrmmLogWindow *logBuilder(CMsgDialog &pDlg); // window.cpp SESSION_INFO* SM_GetPrevWindow(SESSION_INFO *si); diff --git a/src/core/stdmsg/src/tabs.cpp b/src/core/stdmsg/src/tabs.cpp index 8366c2d441..e9ae93b50e 100644 --- a/src/core/stdmsg/src/tabs.cpp +++ b/src/core/stdmsg/src/tabs.cpp @@ -515,7 +515,7 @@ INT_PTR CTabbedWindow::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) if (!((rc.right - rc.left) == oldSizeX && (rc.bottom - rc.top) == oldSizeY)) { CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; if (pDlg != nullptr) { - pDlg->ScrollToBottom(); + pDlg->m_pLog->ScrollToBottom(); pDlg->Resize(); } } -- cgit v1.2.3