From 6fbc81e2ceefe04b2ac05b2ecadd74ec7575090b Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 3 Sep 2019 22:58:14 +0300 Subject: StdMsg: chat & groupchat window classes merged together into new class CMsgDialog --- src/core/stdmsg/res/resource.rc | 15 +- src/core/stdmsg/src/chat_manager.cpp | 2 +- src/core/stdmsg/src/chat_window.cpp | 699 +--------- src/core/stdmsg/src/msgdialog.cpp | 2354 +++++++++++++++++++--------------- src/core/stdmsg/src/msglog.cpp | 4 +- src/core/stdmsg/src/msgs.h | 164 +-- src/core/stdmsg/src/resource.h | 1 - src/core/stdmsg/src/tabs.cpp | 12 +- 8 files changed, 1417 insertions(+), 1834 deletions(-) (limited to 'src/core/stdmsg') diff --git a/src/core/stdmsg/res/resource.rc b/src/core/stdmsg/res/resource.rc index 06ee86b66e..b878d99041 100644 --- a/src/core/stdmsg/res/resource.rc +++ b/src/core/stdmsg/res/resource.rc @@ -93,7 +93,9 @@ BEGIN DEFPUSHBUTTON "&Send",IDOK,212,111,39,29 PUSHBUTTON "Close",IDCANCEL,197,0,54,15,NOT WS_VISIBLE CONTROL "",IDC_SRMM_LOG,"RichEdit50W",WS_VSCROLL | WS_TABSTOP | 0x844,1,16,250,91,WS_EX_STATICEDGE + CONTROL "",IDC_SPLITTERX,"Static",SS_ENHMETAFILE,172,23,10,73 CONTROL "",IDC_SPLITTERY,"Static",SS_ENHMETAFILE,0,108,251,2 + LISTBOX IDC_SRMM_NICKLIST,182,2,69,94,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_NODATA | NOT WS_BORDER | WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE CONTROL "",IDC_AVATAR,"Button",BS_OWNERDRAW | NOT WS_VISIBLE,1,127,6,13 END @@ -148,19 +150,6 @@ BEGIN CONTROL "Show balloon popup",IDC_NOTIFYBALLOON,"Button",BS_AUTORADIOBUTTON,44,219,206,10 END -IDD_CHANNEL DIALOGEX 0, 0, 252, 140 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "",IDC_SRMM_MESSAGE,"RichEdit50W",WS_VSCROLL | WS_TABSTOP | 0x3144,0,128,127,28,WS_EX_STATICEDGE - PUSHBUTTON "&Send",IDOK,136,126,115,28,WS_DISABLED - CONTROL "",IDC_SRMM_LOG,"RichEdit50W",WS_VSCROLL | WS_TABSTOP | 0x2844,8,2,164,94,WS_EX_STATICEDGE - CONTROL "",IDC_SPLITTERX,"Static",SS_ENHMETAFILE,172,23,10,73 - CONTROL "",IDC_SPLITTERY,"Static",SS_ENHMETAFILE,0,102,251,6 - LISTBOX IDC_SRMM_NICKLIST,182,2,69,94,LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_NODATA | NOT WS_BORDER | WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE -END - IDD_CONTAINER DIALOGEX 0, 0, 275, 200 STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME FONT 8, "MS Shell Dlg", 0, 0, 0x1 diff --git a/src/core/stdmsg/src/chat_manager.cpp b/src/core/stdmsg/src/chat_manager.cpp index 634532b411..b75508ac48 100644 --- a/src/core/stdmsg/src/chat_manager.cpp +++ b/src/core/stdmsg/src/chat_manager.cpp @@ -177,7 +177,7 @@ static void ShowRoom(SESSION_INFO *si) PostMessage(pContainer->GetHwnd(), WM_SIZE, 0, 0); } else { - CMsgDialog *pDlg = pContainer->m_pEmbed = new CChatRoomDlg(pContainer, si); + CMsgDialog *pDlg = pContainer->m_pEmbed = new CMsgDialog(pContainer, si); pContainer->Create(); pDlg->SetParent(pContainer->GetHwnd()); pDlg->Create(); diff --git a/src/core/stdmsg/src/chat_window.cpp b/src/core/stdmsg/src/chat_window.cpp index 569ff940ca..6205fd01b5 100644 --- a/src/core/stdmsg/src/chat_window.cpp +++ b/src/core/stdmsg/src/chat_window.cpp @@ -22,173 +22,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "stdafx.h" -static HKL hkl = nullptr; - -static wchar_t szTrimString[] = L":;,.!?\'\"><()[]- \r\n"; - ///////////////////////////////////////////////////////////////////////////////////////// -CChatRoomDlg::CChatRoomDlg(CTabbedWindow *pOwner, SESSION_INFO *si) : - CSuper(pOwner, IDD_CHANNEL, si) -{ - m_btnOk.OnClick = Callback(this, &CChatRoomDlg::onClick_Ok); - - m_btnFilter.OnClick = Callback(this, &CChatRoomDlg::onClick_Filter); - m_btnNickList.OnClick = Callback(this, &CChatRoomDlg::onClick_NickList); - - m_splitterX.OnChange = Callback(this, &CChatRoomDlg::onSplitterX); - m_splitterY.OnChange = Callback(this, &CChatRoomDlg::onSplitterY); - - m_iSplitterX = g_Settings.iSplitterX; - m_iSplitterY = g_Settings.iSplitterY; -} - -bool CChatRoomDlg::OnInitDialog() -{ - CSuper::OnInitDialog(); - m_si->pDlg = this; - - NotifyEvent(MSG_WINDOW_EVT_OPENING); - - if (g_Settings.bTabsEnable) - SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, GetWindowLongPtr(m_hwnd, GWL_EXSTYLE) | WS_EX_APPWINDOW); - else - OnActivate(); - - m_log.SendMsg(EM_AUTOURLDETECT, 1, 0); - - int mask = (int)m_log.SendMsg(EM_GETEVENTMASK, 0, 0); - m_log.SendMsg(EM_SETEVENTMASK, 0, mask | ENM_LINK | ENM_MOUSEEVENTS); - m_log.SendMsg(EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0); - m_log.SendMsg(EM_HIDESELECTION, TRUE, 0); - - UpdateOptions(); - UpdateStatusBar(); - UpdateTitle(); - - NotifyEvent(MSG_WINDOW_EVT_OPEN); - return true; -} - -void CChatRoomDlg::OnDestroy() -{ - NotifyEvent(MSG_WINDOW_EVT_CLOSING); - - m_si->pDlg = nullptr; - m_si->wState &= ~STATE_TALK; - - NotifyEvent(MSG_WINDOW_EVT_CLOSE); - - CSuper::OnDestroy(); -} - -void CChatRoomDlg::OnActivate() -{ - WINDOWPLACEMENT wp = {}; - wp.length = sizeof(wp); - GetWindowPlacement(m_hwnd, &wp); - g_Settings.iX = wp.rcNormalPosition.left; - g_Settings.iY = wp.rcNormalPosition.top; - g_Settings.iWidth = wp.rcNormalPosition.right - wp.rcNormalPosition.left; - g_Settings.iHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; - - UpdateTitle(); - g_chatApi.SetActiveSession(m_si); - UpdateStatusBar(); - - StopFlash(); - if (db_get_w(m_hContact, m_si->pszModule, "ApparentMode", 0) != 0) - db_set_w(m_hContact, m_si->pszModule, "ApparentMode", 0); - if (g_clistApi.pfnGetEvent(m_hContact, 0)) - g_clistApi.pfnRemoveEvent(m_hContact, GC_FAKE_EVENT); -} - -void CChatRoomDlg::onClick_Filter(CCtrlButton *pButton) -{ - if (!pButton->Enabled()) - return; - - m_bFilterEnabled = !m_bFilterEnabled; - m_btnFilter.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bFilterEnabled ? IDI_FILTER : IDI_FILTER2, FALSE)); - if (m_bFilterEnabled && db_get_b(0, CHAT_MODULE, "RightClickFilter", 0) == 0) - ShowFilterMenu(); - else - RedrawLog(); -} - -void CChatRoomDlg::onClick_NickList(CCtrlButton *pButton) -{ - if (!pButton->Enabled() || m_si->iType == GCW_SERVER) - return; - - m_bNicklistEnabled = !m_bNicklistEnabled; - pButton->SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bNicklistEnabled ? IDI_NICKLIST : IDI_NICKLIST2, FALSE)); - - ScrollToBottom(); - Resize(); -} - -void CChatRoomDlg::onClick_Ok(CCtrlButton *pButton) -{ - if (!pButton->Enabled()) - return; - - ptrA pszRtf(m_message.GetRichTextRtf()); - if (pszRtf == nullptr) - return; - - g_chatApi.SM_AddCommand(m_si->ptszID, m_si->pszModule, pszRtf); - - CMStringW ptszText(ptrW(mir_utf8decodeW(pszRtf))); - g_chatApi.DoRtfToTags(ptszText, 0, nullptr); - ptszText.Trim(); - ptszText.Replace(L"%", L"%%"); - - if (m_si->pMI->bAckMsg) { - EnableWindow(m_message.GetHwnd(), FALSE); - m_message.SendMsg(EM_SETREADONLY, TRUE, 0); - } - else m_message.SetText(L""); - - EnableWindow(m_btnOk.GetHwnd(), FALSE); - - Chat_DoEventHook(m_si, GC_USER_MESSAGE, nullptr, ptszText, 0); - - SetFocus(m_message.GetHwnd()); -} - -void CChatRoomDlg::onSplitterX(CSplitter *pSplitter) -{ - RECT rc; - GetClientRect(m_hwnd, &rc); - - m_iSplitterX = rc.right - pSplitter->GetPos() + 1; - if (m_iSplitterX < 35) - m_iSplitterX = 35; - if (m_iSplitterX > rc.right - rc.left - 35) - m_iSplitterX = rc.right - rc.left - 35; - g_Settings.iSplitterX = m_iSplitterX; -} - -void CChatRoomDlg::onSplitterY(CSplitter *pSplitter) -{ - RECT rc; - GetClientRect(m_hwnd, &rc); - - m_iSplitterY = rc.bottom - pSplitter->GetPos() + 1; - if (!IsWindowVisible(m_btnBold.GetHwnd())) - m_iSplitterY += 19; - - if (m_iSplitterY < 63) - m_iSplitterY = 63; - if (m_iSplitterY > rc.bottom - rc.top - 40) - m_iSplitterY = rc.bottom - rc.top - 40; - g_Settings.iSplitterY = m_iSplitterY; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CChatRoomDlg::LoadSettings() +void CMsgDialog::LoadSettings() { m_clrInputBG = db_get_dw(0, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW)); m_clrInputFG = g_Settings.MessageAreaColor; @@ -203,7 +39,7 @@ static void __cdecl phase2(SESSION_INFO *si) si->pDlg->RedrawLog2(); } -void CChatRoomDlg::RedrawLog() +void CMsgDialog::RedrawLog() { m_si->LastTime = 0; if (m_si->pLog) { @@ -228,7 +64,7 @@ void CChatRoomDlg::RedrawLog() ///////////////////////////////////////////////////////////////////////////////////////// -void CChatRoomDlg::ShowFilterMenu() +void CMsgDialog::ShowFilterMenu() { HWND hwnd = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER), m_hwnd, FilterWndProc, (LPARAM)this); TranslateDialogDefault(hwnd); @@ -238,7 +74,7 @@ void CChatRoomDlg::ShowFilterMenu() SetWindowPos(hwnd, HWND_TOP, rc.left - 85, (IsWindowVisible(m_btnFilter.GetHwnd()) || IsWindowVisible(m_btnBold.GetHwnd())) ? rc.top - 206 : rc.top - 186, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); } -void CChatRoomDlg::UpdateNickList() +void CMsgDialog::UpdateNickList() { int i = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0); m_nickList.SendMsg(LB_SETCOUNT, m_si->getUserList().getCount(), 0); @@ -247,7 +83,7 @@ void CChatRoomDlg::UpdateNickList() UpdateTitle(); } -void CChatRoomDlg::UpdateOptions() +void CMsgDialog::UpdateOptions() { m_btnNickList.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bNicklistEnabled ? IDI_NICKLIST : IDI_NICKLIST2, FALSE)); m_btnFilter.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bFilterEnabled ? IDI_FILTER : IDI_FILTER2, FALSE)); @@ -297,7 +133,7 @@ void CChatRoomDlg::UpdateOptions() RedrawLog2(); } -void CChatRoomDlg::UpdateStatusBar() +void CMsgDialog::UpdateStatusBar() { wchar_t *ptszDispName = m_si->pMI->ptszModDispName; int x = 12; @@ -315,34 +151,9 @@ void CChatRoomDlg::UpdateStatusBar() SendMessage(m_pOwner->m_hwndStatus, SB_SETTIPTEXT, 1, (LPARAM)(m_si->ptszStatusbarText ? m_si->ptszStatusbarText : L"")); } -void CChatRoomDlg::UpdateTitle() -{ - int nUsers = m_si->getUserList().getCount(); - - wchar_t szTemp[100]; - switch (m_si->iType) { - case GCW_CHATROOM: - mir_snwprintf(szTemp, - (nUsers == 1) ? TranslateT("%s: chat room (%u user)") : TranslateT("%s: chat room (%u users)"), - m_si->ptszName, nUsers); - break; - case GCW_PRIVMESS: - mir_snwprintf(szTemp, - (nUsers == 1) ? TranslateT("%s: message session") : TranslateT("%s: message session (%u users)"), - m_si->ptszName, nUsers); - break; - case GCW_SERVER: - mir_snwprintf(szTemp, L"%s: Server", m_si->ptszName); - break; - } - - if (this == m_pOwner->CurrPage()) - SetWindowText(m_pOwner->GetHwnd(), szTemp); -} - ///////////////////////////////////////////////////////////////////////////////////////// -void CChatRoomDlg::StreamInEvents(LOGINFO *lin, bool bRedraw) +void CMsgDialog::StreamInEvents(LOGINFO *lin, bool bRedraw) { if (m_hwnd == nullptr || lin == nullptr || m_si == nullptr) return; @@ -445,67 +256,12 @@ void CChatRoomDlg::StreamInEvents(LOGINFO *lin, bool bRedraw) ///////////////////////////////////////////////////////////////////////////////////////// -int CChatRoomDlg::Resizer(UTILRESIZECONTROL *urc) +INT_PTR CALLBACK CMsgDialog::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - bool bControl = db_get_b(0, CHAT_MODULE, "ShowTopButtons", 1) != 0; - bool bFormat = db_get_b(0, CHAT_MODULE, "ShowFormatButtons", 1) != 0; - bool bToolbar = bFormat || bControl; - bool bSend = db_get_b(0, CHAT_MODULE, "ShowSend", 0) != 0; - bool bNick = m_si->iType != GCW_SERVER && m_bNicklistEnabled; - - switch (urc->wId) { - case IDOK: - urc->rcItem.left = bSend ? 315 : urc->dlgNewSize.cx; - urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 23; - urc->rcItem.bottom = urc->dlgNewSize.cy - 1; - return RD_ANCHORX_RIGHT | RD_ANCHORY_CUSTOM; - - case IDC_SRMM_LOG: - 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; - 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; - - case IDC_SPLITTERX: - urc->rcItem.top = 1; - urc->rcItem.left = urc->dlgNewSize.cx - m_iSplitterX; - urc->rcItem.right = urc->rcItem.left + 2; - goto LBL_CalcBottom; - - case IDC_SPLITTERY: - urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY; - if (!bToolbar) - urc->rcItem.top += 20; - urc->rcItem.bottom = urc->rcItem.top + 2; - return RD_ANCHORX_WIDTH | RD_ANCHORY_CUSTOM; - - case IDC_SRMM_MESSAGE: - urc->rcItem.right = bSend ? urc->dlgNewSize.cx - 64 : urc->dlgNewSize.cx; - urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 22; - urc->rcItem.bottom = urc->dlgNewSize.cy - 1; - return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM; - } - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CALLBACK CChatRoomDlg::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - static CChatRoomDlg *pDlg = nullptr; + static CMsgDialog *pDlg = nullptr; switch (uMsg) { case WM_INITDIALOG: - pDlg = (CChatRoomDlg*)lParam; + pDlg = (CMsgDialog*)lParam; CheckDlgButton(hwndDlg, IDC_1, pDlg->m_iLogFilterFlags & GC_EVENT_ACTION ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg, IDC_2, pDlg->m_iLogFilterFlags & GC_EVENT_MESSAGE ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg, IDC_3, pDlg->m_iLogFilterFlags & GC_EVENT_NICK ? BST_CHECKED : BST_UNCHECKED); @@ -569,438 +325,3 @@ INT_PTR CALLBACK CChatRoomDlg::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wPa return FALSE; } - -///////////////////////////////////////////////////////////////////////////////////////// - -LRESULT CChatRoomDlg::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) -{ - CHARRANGE sel; - - switch (msg) { - case WM_MOUSEWHEEL: - m_log.SendMsg(WM_MOUSEWHEEL, wParam, lParam); - m_iLastEnterTime = 0; - return TRUE; - - case EM_REPLACESEL: - PostMessage(m_message.GetHwnd(), EM_ACTIVATE, 0, 0); - break; - - case EM_ACTIVATE: - SetActiveWindow(m_hwnd); - break; - - case WM_CHAR: - if (GetWindowLongPtr(m_message.GetHwnd(), GWL_STYLE) & ES_READONLY) - break; - { - BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000; - BOOL isAlt = GetKeyState(VK_MENU) & 0x8000; - if (wParam == 9 && isCtrl && !isAlt) // ctrl-i (italics) - return TRUE; - - if (wParam == VK_SPACE && isCtrl && !isAlt) // ctrl-space (paste clean text) - return TRUE; - - if (wParam == '\n' || wParam == '\r') { - if ((isCtrl && g_dat.bSendOnCtrlEnter) || (!isCtrl && g_dat.bSendOnEnter)) { - m_btnOk.Click(); - return 0; - } - if (g_dat.bSendOnDblEnter) { - if (m_iLastEnterTime + 2 < time(0)) - m_iLastEnterTime = time(0); - else { - m_message.SendMsg(WM_KEYDOWN, VK_BACK, 0); - m_message.SendMsg(WM_KEYUP, VK_BACK, 0); - m_btnOk.Click(); - return 0; - } - } - } - else m_iLastEnterTime = 0; - - if (wParam == 1 && isCtrl && !isAlt) { //ctrl-a - m_message.SendMsg(EM_SETSEL, 0, -1); - return 0; - } - } - 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 == VK_RETURN) { - m_szTabSave[0] = '\0'; - if ((isCtrl && g_dat.bSendOnCtrlEnter) || (!isCtrl && g_dat.bSendOnEnter)) - return 0; - - if (g_dat.bSendOnDblEnter) - if (m_iLastEnterTime + 2 >= time(0)) - return 0; - - break; - } - - if (wParam == VK_TAB && isShift && !isCtrl) { // SHIFT-TAB (go to nick list) - SetFocus(m_nickList.GetHwnd()); - return TRUE; - } - - if (wParam == VK_TAB && !isCtrl && !isShift) { // tab-autocomplete - TabAutoComplete(); - return 0; - } - - if (m_szTabSave[0] != '\0' && wParam != VK_RIGHT && wParam != VK_LEFT && wParam != VK_SPACE && wParam != VK_RETURN && wParam != VK_BACK && wParam != VK_DELETE) { - if (g_Settings.bAddColonToAutoComplete && m_iTabStart == 0) - SendMessageA(m_message.GetHwnd(), EM_REPLACESEL, FALSE, (LPARAM) ": "); - - m_szTabSave[0] = '\0'; - } - - if (ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) - return TRUE; - - if (wParam == VK_NEXT || wParam == VK_PRIOR) { - m_log.SendMsg(msg, wParam, lParam); - m_iLastEnterTime = 0; - return TRUE; - } - - if (wParam == VK_UP && isCtrl && !isAlt) { - char* lpPrevCmd = g_chatApi.SM_GetPrevCommand(m_si->ptszID, m_si->pszModule); - - m_message.SendMsg(WM_SETREDRAW, FALSE, 0); - - if (lpPrevCmd) { - SETTEXTEX ste; - ste.flags = ST_DEFAULT; - ste.codepage = CP_ACP; - m_message.SendMsg(EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd); - } - else m_message.SetText(L""); - - GETTEXTLENGTHEX gtl = {}; - 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 TRUE; - } - - if (wParam == VK_DOWN && isCtrl && !isAlt) { - char *lpPrevCmd = g_chatApi.SM_GetNextCommand(m_si->ptszID, m_si->pszModule); - m_message.SendMsg(WM_SETREDRAW, FALSE, 0); - - if (lpPrevCmd) { - SETTEXTEX ste; - ste.flags = ST_DEFAULT; - ste.codepage = CP_ACP; - m_message.SendMsg(EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd); - } - else m_message.SetText(L""); - - GETTEXTLENGTHEX gtl = {}; - 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 TRUE; - } - } - __fallthrough; - - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_KILLFOCUS: - m_iLastEnterTime = 0; - break; - - case WM_RBUTTONDOWN: - { - HMENU hSubMenu = GetSubMenu(g_hMenu, 0); - TranslateMenu(hSubMenu); - m_message.SendMsg(EM_EXGETSEL, 0, (LPARAM)&sel); - - EnableMenuItem(hSubMenu, ID_MESSAGE_UNDO, m_message.SendMsg(EM_CANUNDO, 0, 0) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hSubMenu, ID_MESSAGE_REDO, m_message.SendMsg(EM_CANREDO, 0, 0) ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hSubMenu, ID_MESSAGE_COPY, sel.cpMax != sel.cpMin ? MF_ENABLED : MF_GRAYED); - EnableMenuItem(hSubMenu, ID_MESSAGE_CUT, sel.cpMax != sel.cpMin ? MF_ENABLED : MF_GRAYED); - - m_iLastEnterTime = 0; - - POINT pt; - pt.x = (short)LOWORD(lParam); - pt.y = (short)HIWORD(lParam); - ClientToScreen(m_message.GetHwnd(), &pt); - - CHARRANGE all = { 0, -1 }; - UINT uID = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_message.GetHwnd(), nullptr); - switch (uID) { - case 0: - break; - - case ID_MESSAGE_UNDO: - m_message.SendMsg(EM_UNDO, 0, 0); - break; - - case ID_MESSAGE_REDO: - m_message.SendMsg(EM_REDO, 0, 0); - break; - - case ID_MESSAGE_COPY: - m_message.SendMsg(WM_COPY, 0, 0); - break; - - case ID_MESSAGE_CUT: - m_message.SendMsg(WM_CUT, 0, 0); - break; - - case ID_MESSAGE_PASTE: - m_message.SendMsg(EM_PASTESPECIAL, CF_TEXT, 0); - break; - - case ID_MESSAGE_SELECTALL: - m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); - break; - - case ID_MESSAGE_CLEAR: - m_message.SetText(L""); - break; - } - PostMessage(m_message.GetHwnd(), WM_KEYUP, 0, 0); - } - break; - - case WM_KEYUP: - case WM_LBUTTONUP: - case WM_RBUTTONUP: - case WM_MBUTTONUP: - RefreshButtonStatus(); - break; - } - - return CSuper::WndProc_Message(msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -LRESULT CChatRoomDlg::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_LBUTTONUP: - CHARRANGE sel; - 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: - if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) - CloseTab(); - return TRUE; - } - break; - } - - return CSuper::WndProc_Log(msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -LRESULT CChatRoomDlg::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_KEYDOWN: - if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) - CloseTab(); - return TRUE; - } - break; - } - - return CSuper::WndProc_Nicklist(msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CChatRoomDlg::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) { - case WM_CBD_LOADICONS: - Srmm_UpdateToolbarIcons(m_hwnd); - break; - - case WM_CBD_UPDATED: - SetButtonsPos(m_hwnd, true); - break; - - case WM_SIZE: - if (wParam == SIZE_MAXIMIZED) - ScrollToBottom(); - - if (!IsIconic(m_hwnd)) { - bool bSend = db_get_b(0, CHAT_MODULE, "ShowSend", 0) != 0; - bool bFormat = db_get_b(0, CHAT_MODULE, "ShowFormatButtons", 1) != 0; - bool bControl = db_get_b(0, CHAT_MODULE, "ShowTopButtons", 1) != 0; - bool bNick = m_si->iType != GCW_SERVER && m_bNicklistEnabled; - - m_btnBold.Show(bFormat); - m_btnItalic.Show(bFormat); - m_btnUnderline.Show(bFormat); - - m_btnColor.Show(bFormat); - m_btnBkColor.Show(bFormat); - m_btnHistory.Show(bControl); - m_btnNickList.Show(bControl); - m_btnFilter.Show(bControl); - m_btnChannelMgr.Show(bControl); - m_btnOk.Show(bSend); - m_splitterX.Show(bNick); - if (m_si->iType != GCW_SERVER) - m_nickList.Show(m_bNicklistEnabled); - else - m_nickList.Hide(); - - if (m_si->iType == GCW_SERVER) { - m_btnNickList.Enable(false); - m_btnFilter.Enable(false); - m_btnChannelMgr.Enable(false); - } - else { - m_btnNickList.Enable(true); - m_btnFilter.Enable(true); - if (m_si->iType == GCW_CHATROOM) - m_btnChannelMgr.Enable(m_si->pMI->bChanMgr); - } - - CSuper::DlgProc(uMsg, wParam, lParam); // call built-in resizer - SetButtonsPos(m_hwnd, true); - - InvalidateRect(m_pOwner->m_hwndStatus, nullptr, true); - RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); - RedrawWindow(m_btnOk.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); - } - return TRUE; - - case WM_CTLCOLORLISTBOX: - SetBkColor((HDC)wParam, g_Settings.crUserListBGColor); - return (INT_PTR)g_chatApi.hListBkgBrush; - - case WM_MEASUREITEM: - { - MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam; - if (mis->CtlType == ODT_MENU) - return Menu_MeasureItem(lParam); - - int ih = Chat_GetTextPixelSize(L"AQGgl'", g_Settings.UserListFont, FALSE); - int ih2 = Chat_GetTextPixelSize(L"AQGg'", g_Settings.UserListHeadingsFont, FALSE); - int font = ih > ih2 ? ih : ih2; - int height = db_get_b(0, CHAT_MODULE, "NicklistRowDist", 12); - - // make sure we have space for icon! - if (g_Settings.bShowContactStatus) - font = font > 16 ? font : 16; - - mis->itemHeight = height > font ? height : font; - } - return TRUE; - - case WM_DRAWITEM: - { - DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam; - if (dis->CtlType == ODT_MENU) - return Menu_DrawItem(lParam); - - if (dis->CtlID == IDC_SRMM_NICKLIST) { - int index = dis->itemID; - USERINFO *ui = g_chatApi.SM_GetUserFromIndex(m_si->ptszID, m_si->pszModule, index); - if (ui) { - int x_offset = 2; - - int height = dis->rcItem.bottom - dis->rcItem.top; - if (height & 1) - height++; - - int offset = (height == 10) ? 0 : height / 2 - 4; - HFONT hFont = (ui->iStatusEx == 0) ? g_Settings.UserListFont : g_Settings.UserListHeadingsFont; - HFONT hOldFont = (HFONT)SelectObject(dis->hDC, hFont); - SetBkMode(dis->hDC, TRANSPARENT); - - if (dis->itemAction == ODA_FOCUS && dis->itemState & ODS_SELECTED) - FillRect(dis->hDC, &dis->rcItem, g_chatApi.hListSelectedBkgBrush); - else //if (dis->itemState & ODS_INACTIVE) - FillRect(dis->hDC, &dis->rcItem, g_chatApi.hListBkgBrush); - - if (g_Settings.bShowContactStatus && g_Settings.bContactStatusFirst && ui->ContactStatus) { - HICON hIcon = Skin_LoadProtoIcon(m_si->pszModule, ui->ContactStatus); - DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, nullptr, DI_NORMAL); - x_offset += 18; - } - DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset, g_chatApi.SM_GetStatusIcon(m_si, ui), 10, 10, 0, nullptr, DI_NORMAL); - x_offset += 12; - if (g_Settings.bShowContactStatus && !g_Settings.bContactStatusFirst && ui->ContactStatus) { - HICON hIcon = Skin_LoadProtoIcon(m_si->pszModule, ui->ContactStatus); - DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, nullptr, DI_NORMAL); - x_offset += 18; - } - - SetTextColor(dis->hDC, ui->iStatusEx == 0 ? g_Settings.crUserListColor : g_Settings.crUserListHeadingsColor); - TextOut(dis->hDC, dis->rcItem.left + x_offset, dis->rcItem.top, ui->pszNick, (int)mir_wstrlen(ui->pszNick)); - SelectObject(dis->hDC, hOldFont); - } - return TRUE; - } - } - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->code) { - case EN_MSGFILTER: - if (((LPNMHDR)lParam)->idFrom == IDC_SRMM_LOG && ((MSGFILTER *)lParam)->msg == WM_RBUTTONUP) { - SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE); - return TRUE; - } - } - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_SRMM_MESSAGE: - EnableWindow(m_btnOk.GetHwnd(), m_message.GetRichTextLength() != 0); - break; - } - break; - - case WM_KEYDOWN: - SetFocus(m_message.GetHwnd()); - break; - - case DM_UPDATETITLE: - if (lParam == 0 || lParam == (LPARAM)m_hContact) - UpdateTitle(); - break; - - case WM_LBUTTONDBLCLK: - if (LOWORD(lParam) < 30) - ScrollToBottom(); - break; - } - - return CSuper::DlgProc(uMsg, wParam, lParam); -} diff --git a/src/core/stdmsg/src/msgdialog.cpp b/src/core/stdmsg/src/msgdialog.cpp index bfd017866c..6db387d095 100644 --- a/src/core/stdmsg/src/msgdialog.cpp +++ b/src/core/stdmsg/src/msgdialog.cpp @@ -67,265 +67,63 @@ static void SetEditorText(HWND hwnd, const wchar_t *txt) ///////////////////////////////////////////////////////////////////////////////////////// -CMsgDialog::CMsgDialog(CTabbedWindow *pOwner, int iDialogId, SESSION_INFO *si) : - CSuper(g_plugin, iDialogId, si), +CMsgDialog::CMsgDialog(CTabbedWindow *pOwner, MCONTACT hContact) : + CSuper(g_plugin, IDD_MSG), m_btnOk(this, IDOK), m_avatar(this, IDC_AVATAR), m_splitterX(this, IDC_SPLITTERX), m_splitterY(this, IDC_SPLITTERY), m_cmdList(20), + m_bNoActivate(g_dat.bDoNotStealFocus), m_pOwner(pOwner) { m_szTabSave[0] = 0; m_autoClose = 0; m_forceResizable = true; + m_hContact = hContact; g_arDialogs.insert(this); -} - -bool CMsgDialog::OnInitDialog() -{ - m_szProto = GetContactProto(m_hContact); - - return CSuper::OnInitDialog(); -} - -void CMsgDialog::OnDestroy() -{ - if (g_arDialogs.remove(this) == -1) - DebugBreak(); - - CSuper::OnDestroy(); -} - -void CMsgDialog::CloseTab() -{ - if (g_Settings.bTabsEnable) { - m_pOwner->RemoveTab(this); - Close(); - } - else SendMessage(m_hwndParent, WM_CLOSE, 0, 0); -} - -INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) { - case WM_ACTIVATE: - if (LOWORD(wParam) != WA_ACTIVE) - break; - - SetFocus(m_message.GetHwnd()); - __fallthrough; - - case WM_MOUSEACTIVATE: - OnActivate(); - break; - - case WM_TIMER: - if (wParam == TIMERID_FLASHWND) { - FixTabIcons(); - if (!g_dat.nFlashMax || m_nFlash < 2 * g_dat.nFlashMax) - FlashWindow(m_pOwner->GetHwnd(), TRUE); - m_nFlash++; - } - break; - } - - return CSuper::DlgProc(uMsg, wParam, lParam); -} - -LRESULT CMsgDialog::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_KEYDOWN) { - bool isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; - bool isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - bool isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; - if (ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) - return FALSE; - } - - return CSuper::WndProc_Log(msg, wParam, lParam); -} - -LRESULT CMsgDialog::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_KEYDOWN) { - bool isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; - bool isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - bool isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; - - if (g_Settings.bTabsEnable) { - if (wParam <= '9' && wParam >= '1' && isCtrl && !isAlt) { // CTRL + 1 -> 9 (switch tab) - m_pOwner->SwitchTab(wParam - '1'); - return TRUE; - } - - if (wParam <= VK_NUMPAD9 && wParam >= VK_NUMPAD1 && isCtrl && !isAlt) { // CTRL + 1 -> 9 (switch tab) - m_pOwner->SwitchTab(wParam - VK_NUMPAD1); - return TRUE; - } - - if (wParam == VK_TAB && isCtrl && !isShift) { // CTRL-TAB (switch tab/window) - m_pOwner->SwitchNextTab(); - return TRUE; - } - - if (wParam == VK_TAB && isCtrl && isShift) { // CTRL_SHIFT-TAB (switch tab/window) - m_pOwner->SwitchPrevTab(); - return TRUE; - } - - if (wParam == 0x57 && isCtrl && !isAlt) { // ctrl-w (close window) - CloseTab(); - return TRUE; - } - } - - if (isChat()) { - if (wParam == 0x46 && isCtrl && !isAlt) { // ctrl-f (toggle filter) - m_btnFilter.Click(); - return TRUE; - } - - if (wParam == 0x4e && isCtrl && !isAlt) { // ctrl-n (nicklist) - m_btnNickList.Click(); - return TRUE; - } - - if (wParam == 0x4f && isCtrl && !isAlt) { // ctrl-o (options) - m_btnChannelMgr.Click(); - return TRUE; - } - - if ((wParam == 45 && isShift || wParam == 0x56 && isCtrl) && !isAlt) { // ctrl-v (paste clean text) - m_message.SendMsg(EM_PASTESPECIAL, CF_TEXT, 0); - return TRUE; - } - } - } - - return CSuper::WndProc_Message(msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CMsgDialog::GetImageId() const -{ - if (m_nFlash & 1) - return 0; - return g_clistApi.pfnIconFromStatusMode(m_szProto, GetStatus(), m_hContact); + m_btnOk.OnClick = Callback(this, &CMsgDialog::onClick_Ok); + m_splitterY.OnChange = Callback(this, &CMsgDialog::onSplitterY); } -bool CMsgDialog::IsActive() const -{ - bool bRes = m_pOwner->IsActive(); - if (g_Settings.bTabsEnable && bRes) - bRes &= m_pOwner->m_tab.GetActivePage() == this; - - 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); -} - -void CMsgDialog::StopFlash() -{ - if (::KillTimer(m_hwnd, TIMERID_FLASHWND)) { - ::FlashWindow(m_pOwner->GetHwnd(), FALSE); - - m_nFlash = 0; - FixTabIcons(); - } -} - -void CMsgDialog::TabAutoComplete() +CMsgDialog::CMsgDialog(CTabbedWindow *pOwner, SESSION_INFO *si) : + CSuper(g_plugin, IDD_MSG, si), + m_btnOk(this, IDOK), + m_avatar(this, IDC_AVATAR), + m_splitterX(this, IDC_SPLITTERX), + m_splitterY(this, IDC_SPLITTERY), + m_cmdList(20), + m_bNoActivate(g_dat.bDoNotStealFocus), + m_pOwner(pOwner) { - LRESULT lResult = (LRESULT)m_message.SendMsg(EM_GETSEL, 0, 0); - - m_message.SendMsg(WM_SETREDRAW, FALSE, 0); - m_iTabStart = LOWORD(lResult); - int end = HIWORD(lResult); - m_message.SendMsg(EM_SETSEL, end, end); - - GETTEXTLENGTHEX gtl = {}; - gtl.flags = GTL_PRECISE; - gtl.codepage = CP_ACP; - int iLen = m_message.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)& gtl, 0); - if (iLen > 0) { - wchar_t *pszText = (wchar_t *)mir_alloc(sizeof(wchar_t) * (iLen + 100)); - - GETTEXTEX gt = {}; - gt.cb = iLen + 99; - gt.flags = GT_DEFAULT; - gt.codepage = 1200; - m_message.SendMsg(EM_GETTEXTEX, (WPARAM)& gt, (LPARAM)pszText); + m_szTabSave[0] = 0; + m_autoClose = 0; + m_forceResizable = true; + m_si->pDlg = this; - while (m_iTabStart > 0 && pszText[m_iTabStart - 1] != ' ' && pszText[m_iTabStart - 1] != 13 && pszText[m_iTabStart - 1] != VK_TAB) - m_iTabStart--; - while (end < iLen && pszText[end] != ' ' && pszText[end] != 13 && pszText[end - 1] != VK_TAB) - end++; + g_arDialogs.insert(this); - if (m_szTabSave[0] == '\0') - mir_wstrncpy(m_szTabSave, pszText + m_iTabStart, end - m_iTabStart + 1); + m_iSplitterX = g_Settings.iSplitterX; + m_iSplitterY = g_Settings.iSplitterY; - wchar_t *pszSelName = (wchar_t *)mir_alloc(sizeof(wchar_t) * (end - m_iTabStart + 1)); - mir_wstrncpy(pszSelName, pszText + m_iTabStart, end - m_iTabStart + 1); + m_btnOk.OnClick = Callback(this, &CMsgDialog::onClick_Ok); - wchar_t *pszName = g_chatApi.UM_FindUserAutoComplete(m_si, m_szTabSave, pszSelName); - if (pszName == nullptr) { - pszName = m_szTabSave; - m_message.SendMsg(EM_SETSEL, m_iTabStart, end); - if (end != m_iTabStart) - m_message.SendMsg(EM_REPLACESEL, FALSE, (LPARAM)pszName); - m_szTabSave[0] = '\0'; - } - else { - m_message.SendMsg(EM_SETSEL, m_iTabStart, end); - if (end != m_iTabStart) - m_message.SendMsg(EM_REPLACESEL, FALSE, (LPARAM)pszName); - } - mir_free(pszText); - mir_free(pszSelName); - } + m_btnFilter.OnClick = Callback(this, &CMsgDialog::onClick_Filter); + m_btnNickList.OnClick = Callback(this, &CMsgDialog::onClick_NickList); - m_message.SendMsg(WM_SETREDRAW, TRUE, 0); - RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); + m_splitterX.OnChange = Callback(this, &CMsgDialog::onSplitterX); + m_splitterY.OnChange = Callback(this, &CMsgDialog::onSplitterY); } ///////////////////////////////////////////////////////////////////////////////////////// -CSrmmWindow::CSrmmWindow(CTabbedWindow *pOwner, MCONTACT hContact) : - CSuper(pOwner, IDD_MSG), - m_bNoActivate(g_dat.bDoNotStealFocus) -{ - m_hContact = hContact; - - m_btnOk.OnClick = Callback(this, &CSrmmWindow::onClick_Ok); - m_splitterY.OnChange = Callback(this, &CSrmmWindow::OnSplitterMoved); -} - -bool CSrmmWindow::OnInitDialog() +bool CMsgDialog::OnInitDialog() { CSuper::OnInitDialog(); + m_szProto = GetContactProto(m_hContact); m_bIsMeta = db_mc_isMeta(m_hContact) != 0; m_hTimeZone = TimeZone_CreateByContact(m_hContact, nullptr, TZF_KNOWNONLY); m_wMinute = 61; @@ -342,10 +140,17 @@ bool CSrmmWindow::OnInitDialog() // avatar stuff m_limitAvatarH = g_dat.bLimitAvatarHeight ? g_dat.iAvatarHeight : 0; - if (m_hContact && m_szProto != nullptr) + if (m_hContact && m_szProto != nullptr) { m_wStatus = db_get_w(m_hContact, m_szProto, "Status", ID_STATUS_OFFLINE); - else - m_wStatus = ID_STATUS_OFFLINE; + + 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; m_cmdListInd = -1; m_nTypeMode = PROTOTYPE_SELFTYPING_OFF; @@ -355,21 +160,24 @@ bool CSrmmWindow::OnInitDialog() m_iSplitterY = g_plugin.getDword(g_dat.bSavePerContact ? m_hContact : 0, "splitterPos", m_minEditInit.bottom - m_minEditInit.top); UpdateSizeBar(); - m_avatar.Enable(false); - m_log.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_SCROLL); m_log.SendMsg(EM_AUTOURLDETECT, TRUE, 0); - if (m_hContact && m_szProto) { - int nMax = CallProtoService(m_szProto, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, m_hContact); - if (nMax) - m_message.SendMsg(EM_EXLIMITTEXT, 0, nMax); + if (isChat()) { + m_avatar.Hide(); - // 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); + OnActivate(); + UpdateOptions(); + UpdateStatusBar(); + UpdateTitle(); + + NotifyEvent(MSG_WINDOW_EVT_OPEN); } + else { + m_avatar.Disable(); + m_nickList.Hide(); + m_splitterX.Hide(); - if (m_hContact) { // This finds the first message to display, it works like shit m_hDbEventFirst = db_event_firstUnread(m_hContact); switch (g_dat.iLoadHistory) { @@ -416,69 +224,71 @@ bool CSrmmWindow::OnInitDialog() } break; } - } - MEVENT hdbEvent = db_event_last(m_hContact); - if (hdbEvent) { - bool bUpdate = false; - do { - DBEVENTINFO dbei = {}; - db_event_get(hdbEvent, &dbei); - if ((dbei.eventType == EVENTTYPE_MESSAGE) && !(dbei.flags & DBEF_SENT)) { - m_lastMessage = dbei.timestamp; - bUpdate = true; - break; - } - } - while (hdbEvent = db_event_prev(m_hContact, hdbEvent)); + MEVENT hdbEvent = db_event_last(m_hContact); + if (hdbEvent) { + bool bUpdate = false; + do { + DBEVENTINFO dbei = {}; + db_event_get(hdbEvent, &dbei); + if ((dbei.eventType == EVENTTYPE_MESSAGE) && !(dbei.flags & DBEF_SENT)) { + m_lastMessage = dbei.timestamp; + bUpdate = true; + break; + } + } while (hdbEvent = db_event_prev(m_hContact, hdbEvent)); - if (bUpdate) - UpdateLastMessage(); - } + if (bUpdate) + UpdateLastMessage(); + } - OnOptionsApplied(false); + OnOptionsApplied(false); + + // restore saved msg if any... + if (m_hContact) { + DBVARIANT dbv; + if (!db_get_ws(m_hContact, SRMSGMOD, DBSAVEDMSG, &dbv)) { + if (dbv.pwszVal[0]) { + m_message.SetText(dbv.pwszVal); + m_btnOk.Enable(true); + UpdateReadChars(); + PostMessage(m_message.GetHwnd(), EM_SETSEL, -1, -1); + } + db_free(&dbv); + } + } + m_message.SendMsg(EM_SETEVENTMASK, 0, ENM_CHANGE); - // restore saved msg if any... - if (m_hContact) { - DBVARIANT dbv; - if (!db_get_ws(m_hContact, SRMSGMOD, DBSAVEDMSG, &dbv)) { - if (dbv.pwszVal[0]) { - m_message.SetText(dbv.pwszVal); - m_btnOk.Enable(true); - UpdateReadChars(); - PostMessage(m_message.GetHwnd(), EM_SETSEL, -1, -1); + int flag = m_bNoActivate ? RWPF_HIDDEN : 0; + if (Utils_RestoreWindowPosition(m_hwnd, g_dat.bSavePerContact ? m_hContact : 0, SRMMMOD, "", flag)) { + if (g_dat.bSavePerContact) { + if (Utils_RestoreWindowPosition(m_hwnd, 0, SRMMMOD, "", flag | RWPF_NOMOVE)) + SetWindowPos(m_hwnd, nullptr, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); } - db_free(&dbv); + else SetWindowPos(m_hwnd, nullptr, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); } - } - m_message.SendMsg(EM_SETEVENTMASK, 0, ENM_CHANGE); - int flag = m_bNoActivate ? RWPF_HIDDEN : 0; - if (Utils_RestoreWindowPosition(m_hwnd, g_dat.bSavePerContact ? m_hContact : 0, SRMMMOD, "", flag)) { - if (g_dat.bSavePerContact) { - if (Utils_RestoreWindowPosition(m_hwnd, 0, SRMMMOD, "", flag | RWPF_NOMOVE)) - SetWindowPos(m_hwnd, nullptr, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); + if (m_bNoActivate) { + SetWindowPos(m_hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW); + StartFlash(); + } + else { + SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + SetForegroundWindow(m_hwnd); + SetFocus(m_message.GetHwnd()); } - else SetWindowPos(m_hwnd, nullptr, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); - } - if (m_bNoActivate) { - SetWindowPos(m_hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW); - StartFlash(); - } - else { - SetWindowPos(m_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - SetForegroundWindow(m_hwnd); - SetFocus(m_message.GetHwnd()); + UpdateAvatar(); } - UpdateAvatar(); NotifyEvent(MSG_WINDOW_EVT_OPEN); return true; } -void CSrmmWindow::OnDestroy() +void CMsgDialog::OnDestroy() { + g_arDialogs.remove(this); + NotifyEvent(MSG_WINDOW_EVT_CLOSING); // save string from the editor @@ -507,7 +317,7 @@ void CSrmmWindow::OnDestroy() WINDOWPLACEMENT wp = { sizeof(wp) }; GetWindowPlacement(m_hwnd, &wp); - if (!m_windowWasCascaded) { + if (!m_bWindowCascaded) { g_plugin.setDword(hContact, "x", wp.rcNormalPosition.left); g_plugin.setDword(hContact, "y", wp.rcNormalPosition.top); } @@ -516,6 +326,11 @@ void CSrmmWindow::OnDestroy() NotifyEvent(MSG_WINDOW_EVT_CLOSE); + if (isChat()) { + m_si->pDlg = nullptr; + m_si->wState &= ~STATE_TALK; + } + Window_FreeIcon_IcoLib(m_hwnd); CSuper::OnDestroy(); @@ -526,527 +341,756 @@ void CSrmmWindow::OnDestroy() db_delete_contact(m_hContact); } -void CSrmmWindow::OnActivate() +///////////////////////////////////////////////////////////////////////////////////////// + +void CMsgDialog::OnActivate() { - SetupStatusBar(); UpdateTitle(); - UpdateLastMessage(); StopFlash(); - FixTabIcons(); + + if (isChat()) { + g_chatApi.SetActiveSession(m_si); + UpdateStatusBar(); + + if (db_get_w(m_hContact, m_si->pszModule, "ApparentMode", 0) != 0) + db_set_w(m_hContact, m_si->pszModule, "ApparentMode", 0); + if (g_clistApi.pfnGetEvent(m_hContact, 0)) + g_clistApi.pfnRemoveEvent(m_hContact, GC_FAKE_EVENT); + } + else { + SetupStatusBar(); + UpdateLastMessage(); + FixTabIcons(); + } } -///////////////////////////////////////////////////////////////////////////////////////// +void CMsgDialog::onClick_Filter(CCtrlButton *pButton) +{ + if (!pButton->Enabled()) + return; + + m_bFilterEnabled = !m_bFilterEnabled; + m_btnFilter.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bFilterEnabled ? IDI_FILTER : IDI_FILTER2, FALSE)); + if (m_bFilterEnabled && db_get_b(0, CHAT_MODULE, "RightClickFilter", 0) == 0) + ShowFilterMenu(); + else + RedrawLog(); +} -void CSrmmWindow::onClick_Ok(CCtrlButton *pButton) +void CMsgDialog::onClick_NickList(CCtrlButton *pButton) +{ + if (!pButton->Enabled() || m_si->iType == GCW_SERVER) + return; + + m_bNicklistEnabled = !m_bNicklistEnabled; + pButton->SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bNicklistEnabled ? IDI_NICKLIST : IDI_NICKLIST2, FALSE)); + + ScrollToBottom(); + Resize(); +} + +void CMsgDialog::onClick_Ok(CCtrlButton *pButton) { if (!pButton->Enabled()) return; ptrA msgText(m_message.GetRichTextRtf(true)); - ptrW temp(mir_utf8decodeW(msgText)); - if (!temp[0]) + if (msgText == nullptr) return; - int sendId = SendMessageDirect(rtrimw(temp), m_hContact); - if (sendId) { - m_cmdList.insert(temp.detach()); + if (isChat()) { + g_chatApi.SM_AddCommand(m_si->ptszID, m_si->pszModule, msgText); + + CMStringW ptszText(ptrW(mir_utf8decodeW(msgText))); + g_chatApi.DoRtfToTags(ptszText, 0, nullptr); + ptszText.Trim(); + ptszText.Replace(L"%", L"%%"); - m_cmdListInd = -1; - if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) - NotifyTyping(PROTOTYPE_SELFTYPING_OFF); + if (m_si->pMI->bAckMsg) { + EnableWindow(m_message.GetHwnd(), FALSE); + m_message.SendMsg(EM_SETREADONLY, TRUE, 0); + } + else m_message.SetText(L""); + + m_btnOk.Disable(); + + Chat_DoEventHook(m_si, GC_USER_MESSAGE, nullptr, ptszText, 0); - m_btnOk.Enable(false); SetFocus(m_message.GetHwnd()); + } + else { + ptrW temp(mir_utf8decodeW(msgText)); + if (!temp[0]) + return; + + int sendId = SendMessageDirect(rtrimw(temp), m_hContact); + if (sendId) { + m_cmdList.insert(temp.detach()); + + m_cmdListInd = -1; + if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) + NotifyTyping(PROTOTYPE_SELFTYPING_OFF); + + m_btnOk.Enable(false); + SetFocus(m_message.GetHwnd()); - m_message.SetText(L""); + m_message.SetText(L""); - if (!g_Settings.bTabsEnable) { - if (g_dat.bAutoClose) - ::PostMessage(m_hwndParent, WM_CLOSE, 0, 0); - else if (g_dat.bAutoMin) - ::ShowWindow(m_hwndParent, SW_MINIMIZE); + if (!g_Settings.bTabsEnable) { + if (g_dat.bAutoClose) + ::PostMessage(m_hwndParent, WM_CLOSE, 0, 0); + else if (g_dat.bAutoMin) + ::ShowWindow(m_hwndParent, SW_MINIMIZE); + } } } } ///////////////////////////////////////////////////////////////////////////////////////// -void CSrmmWindow::OnOptionsApplied(bool bUpdateAvatar) +int CMsgDialog::Resizer(UTILRESIZECONTROL *urc) { - CustomButtonData *cbd; - for (int i = 0; cbd = Srmm_GetNthButton(i); i++) { - HWND hwndButton = GetDlgItem(m_hwnd, cbd->m_dwButtonCID); - if (hwndButton == nullptr) - continue; + if (isChat()) { + bool bControl = db_get_b(0, CHAT_MODULE, "ShowTopButtons", 1) != 0; + bool bFormat = db_get_b(0, CHAT_MODULE, "ShowFormatButtons", 1) != 0; + bool bToolbar = bFormat || bControl; + bool bSend = db_get_b(0, CHAT_MODULE, "ShowSend", 0) != 0; + bool bNick = m_si->iType != GCW_SERVER && m_bNicklistEnabled; + + switch (urc->wId) { + case IDOK: + urc->rcItem.left = bSend ? 315 : urc->dlgNewSize.cx; + urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 23; + urc->rcItem.bottom = urc->dlgNewSize.cy - 1; + return RD_ANCHORX_RIGHT | RD_ANCHORY_CUSTOM; - bool bShow = false; - if (m_hContact && g_dat.bShowButtons) { - if (cbd->m_dwButtonCID == IDC_ADD) { - bShow = 0 != db_get_b(m_hContact, "CList", "NotOnList", 0); - cbd->m_bHidden = !bShow; - } - else bShow = true; + case IDC_SRMM_LOG: + 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; + 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; + + case IDC_SPLITTERX: + urc->rcItem.top = 1; + urc->rcItem.left = urc->dlgNewSize.cx - m_iSplitterX; + urc->rcItem.right = urc->rcItem.left + 2; + goto LBL_CalcBottom; + + case IDC_SPLITTERY: + urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY; + if (!bToolbar) + urc->rcItem.top += 20; + urc->rcItem.bottom = urc->rcItem.top + 2; + return RD_ANCHORX_WIDTH | RD_ANCHORY_CUSTOM; + + case IDC_SRMM_MESSAGE: + urc->rcItem.right = bSend ? urc->dlgNewSize.cx - 64 : urc->dlgNewSize.cx; + urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 22; + urc->rcItem.bottom = urc->dlgNewSize.cy - 1; + return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM; } - ShowWindow(hwndButton, (bShow) ? SW_SHOW : SW_HIDE); } + else { + switch (urc->wId) { + case IDC_SRMM_LOG: + if (!g_dat.bShowButtons) + urc->rcItem.top = 2; + urc->rcItem.bottom = urc->dlgNewSize.cy - m_iSplitterY; + return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; - ShowWindow(GetDlgItem(m_hwnd, IDCANCEL), SW_HIDE); - m_splitterY.Show(); - - m_btnOk.Show(g_dat.bSendButton); - m_btnOk.Enable(GetWindowTextLength(m_message.GetHwnd()) != 0); - - if (m_avatarPic == nullptr || !g_dat.bShowAvatar) - m_avatar.Hide(); - - UpdateIcon(0); - UpdateTitle(); - Resize(); + case IDC_SPLITTERY: + urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY; + urc->rcItem.bottom = urc->rcItem.top + 3; + return RD_ANCHORX_WIDTH | RD_ANCHORY_CUSTOM; - COLORREF colour = g_plugin.getDword(SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR); - m_log.SendMsg(EM_SETBKGNDCOLOR, 0, colour); - m_message.SendMsg(EM_SETBKGNDCOLOR, 0, colour); + case IDC_SRMM_MESSAGE: + urc->rcItem.right = (g_dat.bSendButton) ? urc->dlgNewSize.cx - 64 : urc->dlgNewSize.cx; + if (g_dat.bShowAvatar && m_avatarPic) + urc->rcItem.left = m_avatarWidth + 4; + + urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 3; + urc->rcItem.bottom = urc->dlgNewSize.cy - 1; + return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; + + case IDCANCEL: + case IDOK: + urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 3; + urc->rcItem.bottom = urc->dlgNewSize.cy - 1; + return RD_ANCHORX_RIGHT | RD_ANCHORY_CUSTOM; + + case IDC_AVATAR: + urc->rcItem.top = urc->rcItem.bottom - (m_avatarHeight + 2); + urc->rcItem.right = urc->rcItem.left + (m_avatarWidth + 2); + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + } + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +} - // avatar stuff - m_avatarPic = nullptr; - m_limitAvatarH = 0; - if (CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_AVATARS) - m_limitAvatarH = g_dat.bLimitAvatarHeight ? g_dat.iAvatarHeight : 0; +///////////////////////////////////////////////////////////////////////////////////////// - if (bUpdateAvatar) - UpdateAvatar(); +INT_PTR CMsgDialog::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + ENLINK *pLink; + CHARRANGE sel; + RECT rc; - InvalidateRect(m_message.GetHwnd(), nullptr, FALSE); + switch (uMsg) { + case WM_CONTEXTMENU: + if (m_pOwner->m_hwndStatus == (HWND)wParam) { + POINT pt, pt2; + GetCursorPos(&pt); + pt2.x = pt.x; pt2.y = pt.y; + ScreenToClient(m_pOwner->m_hwndStatus, &pt); - LOGFONT lf; - CHARFORMAT cf = {}; - if (m_hFont) - DeleteObject(m_hFont); - LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, &lf, &cf.crTextColor); - m_hFont = CreateFontIndirect(&lf); - m_message.SendMsg(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(TRUE, 0)); + // no popup menu for status icons - this is handled via NM_RCLICK notification and the plugins that added the icons + SendMessage(m_pOwner->m_hwndStatus, SB_GETRECT, SendMessage(m_pOwner->m_hwndStatus, SB_GETPARTS, 0, 0) - 1, (LPARAM)& rc); + if (pt.x >= rc.left) + break; - cf.cbSize = sizeof(CHARFORMAT); - cf.dwMask = CFM_COLOR; - m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (WPARAM)&cf); + HMENU hMenu = Menu_BuildContactMenu(m_hContact); + TrackPopupMenu(hMenu, 0, pt2.x, pt2.y, 0, m_hwnd, nullptr); + DestroyMenu(hMenu); + } + break; - // configure message history for proper RTL formatting - PARAFORMAT2 pf2; - memset(&pf2, 0, sizeof(pf2)); - pf2.cbSize = sizeof(pf2); + case WM_DROPFILES: // Mod from tabsrmm + ProcessFileDrop((HDROP)wParam); + return TRUE; - 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); + case HM_AVATARACK: + ShowAvatar(); + break; - RemakeLog(); - FixTabIcons(); -} + case DM_OPTIONSAPPLIED: + OnOptionsApplied(wParam != 0); + break; -void CSrmmWindow::OnSplitterMoved(CSplitter *pSplitter) -{ - RECT rc; - GetClientRect(m_hwnd, &rc); - m_iSplitterY = rc.bottom - pSplitter->GetPos(); + case DM_NEWTIMEZONE: + m_hTimeZone = TimeZone_CreateByContact(m_hContact, nullptr, TZF_KNOWNONLY); + m_wMinute = 61; + Resize(); + break; - int toplimit = 63; - if (!g_dat.bShowButtons) - toplimit += 22; + case WM_CBD_LOADICONS: + Srmm_UpdateToolbarIcons(m_hwnd); + break; - if (m_iSplitterY < m_minEditBoxSize.cy) - m_iSplitterY = m_minEditBoxSize.cy; - if (m_iSplitterY > rc.bottom - rc.top - toplimit) - m_iSplitterY = rc.bottom - rc.top - toplimit; -} + case WM_CBD_UPDATED: + SetButtonsPos(m_hwnd, false); + break; -///////////////////////////////////////////////////////////////////////////////////////// + case WM_CTLCOLORLISTBOX: + SetBkColor((HDC)wParam, g_Settings.crUserListBGColor); + return (INT_PTR)g_chatApi.hListBkgBrush; -void CSrmmWindow::NotifyTyping(int mode) -{ - if (!m_hContact) - return; + case WM_SIZE: + if (!IsIconic(m_hwnd)) { + bool bottomScroll; + + if (isChat()) { + bottomScroll = false; + bool bSend = db_get_b(0, CHAT_MODULE, "ShowSend", 0) != 0; + bool bFormat = db_get_b(0, CHAT_MODULE, "ShowFormatButtons", 1) != 0; + bool bControl = db_get_b(0, CHAT_MODULE, "ShowTopButtons", 1) != 0; + bool bNick = m_si->iType != GCW_SERVER && m_bNicklistEnabled; + + m_btnBold.Show(bFormat); + m_btnItalic.Show(bFormat); + m_btnUnderline.Show(bFormat); + + m_btnColor.Show(bFormat); + m_btnBkColor.Show(bFormat); + m_btnHistory.Show(bControl); + m_btnNickList.Show(bControl); + m_btnFilter.Show(bControl); + m_btnChannelMgr.Show(bControl); + m_btnOk.Show(bSend); + m_splitterX.Show(bNick); + if (m_si->iType != GCW_SERVER) + m_nickList.Show(m_bNicklistEnabled); + else + m_nickList.Hide(); - // Don't send to protocols who don't support typing - // Don't send to users who are unchecked in the typing notification options - // Don't send to protocols that are offline - // Don't send to users who are not visible and - // Don't send to users who are not on the visible list when you are in invisible mode. - if (!g_plugin.getByte(m_hContact, SRMSGSET_TYPING, g_dat.bTypingNew)) - return; + if (m_si->iType == GCW_SERVER) { + m_btnNickList.Enable(false); + m_btnFilter.Enable(false); + m_btnChannelMgr.Enable(false); + } + else { + m_btnNickList.Enable(true); + m_btnFilter.Enable(true); + if (m_si->iType == GCW_CHATROOM) + m_btnChannelMgr.Enable(m_si->pMI->bChanMgr); + } + } + else { + bottomScroll = true; + SetupStatusBar(); - if (!m_szProto) - return; + 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; + } + } - int protoStatus = Proto_GetStatus(m_szProto); - DWORD protoCaps = CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_1, 0); - DWORD typeCaps = CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_4, 0); + CSuper::DlgProc(uMsg, wParam, lParam); // call built-in resizer + SetButtonsPos(m_hwnd, isChat()); - if (!(typeCaps & PF4_SUPPORTTYPING)) - return; + 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 (protoStatus < ID_STATUS_ONLINE) - return; + if (bottomScroll) + ScrollToBottom(); + } + return TRUE; - if (protoCaps & PF1_VISLIST && db_get_w(m_hContact, m_szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) - return; + case HM_DBEVENTADDED: + if (wParam == m_hContact) { + MEVENT hDbEvent = lParam; + if (m_hDbEventFirst == 0) + m_hDbEventFirst = hDbEvent; - if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(m_hContact, m_szProto, "ApparentMode", 0) != ID_STATUS_ONLINE) - return; + DBEVENTINFO dbei = {}; + db_event_get(hDbEvent, &dbei); + bool isMessage = (dbei.eventType == EVENTTYPE_MESSAGE), isSent = ((dbei.flags & DBEF_SENT) != 0); + bool isActive = IsActive(); + if (DbEventIsShown(&dbei)) { + // Sounds *only* for sent messages, not for custom events + if (isMessage && !isSent) { + if (isActive) + Skin_PlaySound("RecvMsgActive"); + else + Skin_PlaySound("RecvMsgInactive"); + } + if (isMessage && !isSent) { + m_lastMessage = dbei.timestamp; + UpdateLastMessage(); + } - if (!g_dat.bTypingUnknown && db_get_b(m_hContact, "CList", "NotOnList", 0)) - return; + if (hDbEvent != m_hDbEventFirst && db_event_next(m_hContact, hDbEvent) == 0) + StreamInEvents(hDbEvent, 1, 1); + else + RemakeLog(); - // End user check - m_nTypeMode = mode; - CallService(MS_PROTO_SELFISTYPING, m_hContact, m_nTypeMode); -} - -void CSrmmWindow::RemakeLog() -{ - StreamInEvents(m_hDbEventFirst, -1, 0); -} - -void CSrmmWindow::ProcessFileDrop(HDROP hDrop) -{ - if (m_szProto == nullptr) return; - if (!(CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_FILESEND)) return; - if (m_wStatus == ID_STATUS_OFFLINE) return; - if (m_hContact != 0) { - wchar_t szFilename[MAX_PATH]; - int fileCount = DragQueryFile(hDrop, -1, nullptr, 0), totalCount = 0; - wchar_t **ppFiles = nullptr; - for (int i = 0; i < fileCount; i++) { - DragQueryFile(hDrop, i, szFilename, _countof(szFilename)); - AddToFileList(&ppFiles, totalCount, szFilename); - } - CallServiceSync(MS_FILE_SENDSPECIFICFILEST, m_hContact, (LPARAM)ppFiles); - if (ppFiles) { - for (int i = 0; ppFiles[i]; i++) - mir_free(ppFiles[i]); - mir_free(ppFiles); + // 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(); + } + } + else StartFlash(); + } + } } - } -} - -void CSrmmWindow::ShowAvatar() -{ - if (g_dat.bShowAvatar) { - AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, getActiveContact(), 0); - if (ace && (INT_PTR)ace != CALLSERVICE_NOTFOUND && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) - m_avatarPic = ace->hbmPic; - else - m_avatarPic = nullptr; - } - else m_avatarPic = nullptr; - - UpdateSizeBar(); - Resize(); -} - -void CSrmmWindow::ShowTime(bool bForce) -{ - if (!m_hTimeZone) - return; + break; - SYSTEMTIME st; - GetSystemTime(&st); - if (m_wMinute != st.wMinute || bForce) { - if (m_pOwner->m_tab.GetActivePage() == this) { - wchar_t buf[32]; - unsigned i = g_dat.bShowReadChar ? 2 : 1; + case WM_TIMECHANGE: + PostMessage(m_hwnd, DM_NEWTIMEZONE, 0, 0); + RemakeLog(); + break; - TimeZone_PrintDateTime(m_hTimeZone, L"t", buf, _countof(buf), 0); - SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, i, (LPARAM)buf); + case WM_TIMER: + if (wParam == TIMERID_FLASHWND) { + FixTabIcons(); + if (!g_dat.nFlashMax || m_nFlash < 2 * g_dat.nFlashMax) + FlashWindow(m_pOwner->GetHwnd(), TRUE); + m_nFlash++; + break; } - m_wMinute = st.wMinute; - } -} -void CSrmmWindow::SetupStatusBar() -{ - int i = 0, statwidths[4]; - int icons_width = GetStatusIconsCount(m_hContact) * (GetSystemMetrics(SM_CXSMICON) + 2) + SB_GRIP_WIDTH; + if (wParam == TIMERID_TYPE) { + ShowTime(false); + if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - m_nLastTyping > TIMEOUT_TYPEOFF) + NotifyTyping(PROTOTYPE_SELFTYPING_OFF); - RECT rc; - GetWindowRect(m_pOwner->m_hwndStatus, &rc); - int cx = rc.right - rc.left; + if (m_bShowTyping) { + if (m_nTypeSecs) { + m_nTypeSecs--; + if (GetForegroundWindow() == m_pOwner->GetHwnd()) + FixTabIcons(); + } + else { + UpdateLastMessage(); + if (g_dat.bShowTypingWin) + FixTabIcons(); + m_bShowTyping = false; + } + } + else { + if (m_nTypeSecs) { + wchar_t szBuf[256]; + wchar_t *szContactName = Clist_GetContactDisplayName(m_hContact); + HICON hTyping = Skin_LoadIcon(SKINICON_OTHER_TYPING); - if (m_hTimeZone) { - if (g_dat.bShowReadChar) - statwidths[i++] = cx - SB_TIME_WIDTH - SB_CHAR_WIDTH - icons_width; - statwidths[i++] = cx - SB_TIME_WIDTH - icons_width; - } - else if (g_dat.bShowReadChar) - statwidths[i++] = cx - SB_CHAR_WIDTH - icons_width; + mir_snwprintf(szBuf, TranslateT("%s is typing a message..."), szContactName); + m_nTypeSecs--; - statwidths[i++] = cx - icons_width; - statwidths[i++] = -1; - SendMessage(m_pOwner->m_hwndStatus, SB_SETPARTS, i, (LPARAM)statwidths); + SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf); + SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hTyping); + if (g_dat.bShowTypingWin && GetForegroundWindow() != m_pOwner->GetHwnd()) { + HICON hIcon = (HICON)SendMessage(m_hwnd, WM_GETICON, ICON_SMALL, 0); + SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hTyping); + IcoLib_ReleaseIcon(hIcon); + } + m_bShowTyping = true; + } + } + } + break; - UpdateReadChars(); - ShowTime(true); - SendMessage(m_hwnd, DM_STATUSICONCHANGE, 0, 0); -} + case WM_MEASUREITEM: + { + LPMEASUREITEMSTRUCT mis = (LPMEASUREITEMSTRUCT)lParam; + if (mis->CtlType == ODT_MENU) + return Menu_MeasureItem(lParam); -void CSrmmWindow::SetStatusText(const wchar_t *wszText, HICON hIcon) -{ - SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hIcon); - SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)(wszText == nullptr ? L"" : wszText)); -} + int ih = Chat_GetTextPixelSize(L"AQGgl'", g_Settings.UserListFont, FALSE); + int ih2 = Chat_GetTextPixelSize(L"AQGg'", g_Settings.UserListHeadingsFont, FALSE); + int font = ih > ih2 ? ih : ih2; + int height = db_get_b(0, CHAT_MODULE, "NicklistRowDist", 12); -void CSrmmWindow::UpdateAvatar() -{ - PROTO_AVATAR_INFORMATION ai = {}; - ai.hContact = m_hContact; - CallProtoService(m_szProto, PS_GETAVATARINFO, GAIF_FORCE, (LPARAM)&ai); + // make sure we have space for icon! + if (g_Settings.bShowContactStatus) + font = font > 16 ? font : 16; - ShowAvatar(); - SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, 1); -} + mis->itemHeight = height > font ? height : font; + } + return TRUE; -void CSrmmWindow::UpdateIcon(WPARAM wParam) -{ - if (!m_hContact || !m_szProto) - return; + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; + if (dis->CtlType == ODT_MENU) + return Menu_DrawItem(lParam); - bool bIsStatus = false; - DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *)wParam; - if (cws && !mir_strcmp(cws->szModule, m_szProto) && !mir_strcmp(cws->szSetting, "Status")) { - bIsStatus = true; - m_wStatus = cws->value.wVal; - } + if (dis->CtlID == IDC_AVATAR && m_avatarPic && g_dat.bShowAvatar) { + HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); + HPEN hOldPen = (HPEN)SelectObject(dis->hDC, hPen); + Rectangle(dis->hDC, 0, 0, m_avatarWidth, m_avatarHeight); + SelectObject(dis->hDC, hOldPen); + DeleteObject(hPen); - if (!cws || bIsStatus) - if (g_dat.bUseStatusWinIcon) - FixTabIcons(); -} + BITMAP bminfo; + GetObject(m_avatarPic, sizeof(bminfo), &bminfo); -void CSrmmWindow::UpdateLastMessage() -{ - if (m_nTypeSecs) - return; + HDC hdcMem = CreateCompatibleDC(dis->hDC); + HBITMAP hbmMem = (HBITMAP)SelectObject(hdcMem, m_avatarPic); - if (m_lastMessage) { - wchar_t date[64], time[64], fmt[128]; - TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"d", date, _countof(date), 0); - TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"t", time, _countof(time), 0); - mir_snwprintf(fmt, TranslateT("Last message received on %s at %s."), date, time); - SetStatusText(fmt, nullptr); - } - else SetStatusText(nullptr, nullptr); -} + SetStretchBltMode(dis->hDC, HALFTONE); + StretchBlt(dis->hDC, 1, 1, m_avatarWidth - 2, m_avatarHeight - 2, hdcMem, 0, 0, + bminfo.bmWidth, bminfo.bmHeight, SRCCOPY); -void CSrmmWindow::UpdateReadChars() -{ - if (g_dat.bShowReadChar) { - wchar_t buf[32]; - int len = GetWindowTextLength(m_message.GetHwnd()); + SelectObject(hdcMem, hbmMem); + DeleteDC(hdcMem); + return TRUE; + } - mir_snwprintf(buf, L"%d", len); - SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 1, (LPARAM)buf); - } -} + if (dis->CtlID == IDC_SRMM_NICKLIST) { + int index = dis->itemID; + USERINFO *ui = g_chatApi.SM_GetUserFromIndex(m_si->ptszID, m_si->pszModule, index); + if (ui) { + int x_offset = 2; + + int height = dis->rcItem.bottom - dis->rcItem.top; + if (height & 1) + height++; + + int offset = (height == 10) ? 0 : height / 2 - 4; + HFONT hFont = (ui->iStatusEx == 0) ? g_Settings.UserListFont : g_Settings.UserListHeadingsFont; + HFONT hOldFont = (HFONT)SelectObject(dis->hDC, hFont); + SetBkMode(dis->hDC, TRANSPARENT); + + if (dis->itemAction == ODA_FOCUS && dis->itemState & ODS_SELECTED) + FillRect(dis->hDC, &dis->rcItem, g_chatApi.hListSelectedBkgBrush); + else //if (dis->itemState & ODS_INACTIVE) + FillRect(dis->hDC, &dis->rcItem, g_chatApi.hListBkgBrush); + + if (g_Settings.bShowContactStatus && g_Settings.bContactStatusFirst && ui->ContactStatus) { + HICON hIcon = Skin_LoadProtoIcon(m_si->pszModule, ui->ContactStatus); + DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, nullptr, DI_NORMAL); + x_offset += 18; + } + DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset, g_chatApi.SM_GetStatusIcon(m_si, ui), 10, 10, 0, nullptr, DI_NORMAL); + x_offset += 12; + if (g_Settings.bShowContactStatus && !g_Settings.bContactStatusFirst && ui->ContactStatus) { + HICON hIcon = Skin_LoadProtoIcon(m_si->pszModule, ui->ContactStatus); + DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, nullptr, DI_NORMAL); + x_offset += 18; + } -void CSrmmWindow::UpdateSizeBar() -{ - m_minEditBoxSize.cx = m_minEditInit.right - m_minEditInit.left; - m_minEditBoxSize.cy = m_minEditInit.bottom - m_minEditInit.top; - if (g_dat.bShowAvatar) { - if (m_avatarPic == nullptr || !g_dat.bShowAvatar) { - m_avatarWidth = 50; - m_avatarHeight = 50; - m_avatar.Hide(); - return; - } - else { - BITMAP bminfo; - GetObject(m_avatarPic, sizeof(bminfo), &bminfo); - m_avatarWidth = bminfo.bmWidth + 2; - m_avatarHeight = bminfo.bmHeight + 2; - if (m_limitAvatarH && m_avatarHeight > m_limitAvatarH) { - m_avatarWidth = bminfo.bmWidth * m_limitAvatarH / bminfo.bmHeight + 2; - m_avatarHeight = m_limitAvatarH + 2; + SetTextColor(dis->hDC, ui->iStatusEx == 0 ? g_Settings.crUserListColor : g_Settings.crUserListHeadingsColor); + TextOut(dis->hDC, dis->rcItem.left + x_offset, dis->rcItem.top, ui->pszNick, (int)mir_wstrlen(ui->pszNick)); + SelectObject(dis->hDC, hOldFont); + } + return TRUE; } - m_avatar.Show(); } + break; - if (m_avatarPic && m_minEditBoxSize.cy <= m_avatarHeight) { - m_minEditBoxSize.cy = m_avatarHeight + 8; - if (m_iSplitterY < m_minEditBoxSize.cy) { - m_iSplitterY = m_minEditBoxSize.cy; - Resize(); + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_USERMENU: + if (GetKeyState(VK_SHIFT) & 0x8000) { // copy user name + ptrW id(Contact_GetInfo(CNF_UNIQUEID, m_hContact, m_szProto)); + if (id != nullptr && OpenClipboard(m_hwnd)) { + HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, mir_wstrlen(id) * sizeof(wchar_t) + 1); + if (hData) { + EmptyClipboard(); + mir_wstrcpy((wchar_t *)GlobalLock(hData), id); + GlobalUnlock(hData); + SetClipboardData(CF_UNICODETEXT, hData); + CloseClipboard(); + } + } } - } - } -} + else { + HMENU hMenu = Menu_BuildContactMenu(m_hContact); + GetWindowRect(GetDlgItem(m_hwnd, LOWORD(wParam)), &rc); + TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, m_hwnd, nullptr); + DestroyMenu(hMenu); + } + break; -void CSrmmWindow::UpdateTitle() -{ - wchar_t newtitle[256]; - if (m_hContact && m_szProto) { - m_wStatus = db_get_w(m_hContact, m_szProto, "Status", ID_STATUS_OFFLINE); - wchar_t *contactName = Clist_GetContactDisplayName(m_hContact); - - if (g_dat.bUseStatusWinIcon) - mir_snwprintf(newtitle, L"%s - %s", contactName, TranslateT("Message session")); + case IDC_DETAILS: + CallService(MS_USERINFO_SHOWDIALOG, m_hContact, 0); + break; + + case IDC_ADD: + Contact_Add(m_hContact, m_hwnd); + + if (!db_get_b(m_hContact, "CList", "NotOnList", 0)) + ShowWindow(GetDlgItem(m_hwnd, IDC_ADD), FALSE); + break; + + case IDC_SRMM_MESSAGE: + if (HIWORD(wParam) == EN_CHANGE) { + int len = GetWindowTextLength(m_message.GetHwnd()); + UpdateReadChars(); + m_btnOk.Enable(len != 0); + if (!(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000)) { + m_nLastTyping = GetTickCount(); + if (len) { + if (m_nTypeMode == PROTOTYPE_SELFTYPING_OFF) + NotifyTyping(PROTOTYPE_SELFTYPING_ON); + } + else if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) + NotifyTyping(PROTOTYPE_SELFTYPING_OFF); + } + } + break; + } + break; + + case WM_NOTIFY: + HCURSOR hCur; + switch (((LPNMHDR)lParam)->idFrom) { + case IDC_SRMM_LOG: + switch (((LPNMHDR)lParam)->code) { + case EN_MSGFILTER: + switch (((MSGFILTER *)lParam)->msg) { + case WM_LBUTTONDOWN: + hCur = GetCursor(); + if (hCur == LoadCursor(nullptr, IDC_SIZENS) || hCur == LoadCursor(nullptr, IDC_SIZEWE) || hCur == LoadCursor(nullptr, IDC_SIZENESW) || hCur == LoadCursor(nullptr, IDC_SIZENWSE)) { + SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE); + return TRUE; + } + break; + + case WM_MOUSEMOVE: + hCur = GetCursor(); + if (hCur == LoadCursor(nullptr, IDC_SIZENS) || hCur == LoadCursor(nullptr, IDC_SIZEWE) || hCur == LoadCursor(nullptr, IDC_SIZENESW) || hCur == LoadCursor(nullptr, IDC_SIZENWSE)) + SetCursor(LoadCursor(nullptr, IDC_ARROW)); + break; + + case WM_RBUTTONUP: + CHARRANGE all = { 0, -1 }; + HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXT)); + HMENU hSubMenu = GetSubMenu(hMenu, 0); + TranslateMenu(hSubMenu); + SendMessage(((NMHDR *)lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM)& sel); + if (sel.cpMin == sel.cpMax) + EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); + + pLink = (ENLINK *)lParam; + POINT pt = { GET_X_LPARAM(pLink->lParam), GET_Y_LPARAM(pLink->lParam) }; + ClientToScreen(pLink->nmhdr.hwndFrom, &pt); + + switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_hwnd, nullptr)) { + case IDM_COPY: + SendMessage(pLink->nmhdr.hwndFrom, WM_COPY, 0, 0); + break; + case IDM_COPYALL: + SendMessage(pLink->nmhdr.hwndFrom, EM_EXSETSEL, 0, (LPARAM)& all); + SendMessage(pLink->nmhdr.hwndFrom, WM_COPY, 0, 0); + SendMessage(pLink->nmhdr.hwndFrom, EM_EXSETSEL, 0, (LPARAM)& sel); + break; + case IDM_SELECTALL: + SendMessage(pLink->nmhdr.hwndFrom, EM_EXSETSEL, 0, (LPARAM)& all); + break; + case IDM_CLEAR: + ClearLog(); + m_hDbEventFirst = 0; + break; + } + DestroyMenu(hSubMenu); + DestroyMenu(hMenu); + SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE); + return TRUE; + } + break; + + case EN_VSCROLL: + if (LOWORD(wParam) == IDC_SRMM_LOG && GetWindowLongPtr((HWND)lParam, GWL_STYLE) & WS_VSCROLL) { + SCROLLINFO si = {}; + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + GetScrollInfo((HWND)lParam, SB_VERT, &si); + if ((si.nPos + (int)si.nPage + 5) >= si.nMax) + StopFlash(); + } + break; + } + } + break; + + case DM_UPDATETITLE: + if (isChat()) { + if (lParam == 0 || lParam == (LPARAM)m_hContact) + UpdateTitle(); + } else { - wchar_t *szStatus = Clist_GetStatusModeDescription(m_szProto == nullptr ? ID_STATUS_OFFLINE : db_get_w(m_hContact, m_szProto, "Status", ID_STATUS_OFFLINE), 0); - mir_snwprintf(newtitle, L"%s (%s): %s", contactName, szStatus, TranslateT("Message session")); + if (lParam != 0) { + bool bIsMe = (lParam == m_hContact) || (m_bIsMeta && db_mc_getMeta(lParam) == m_hContact); + if (!bIsMe) + break; + } + + UpdateIcon(wParam); + UpdateTitle(); } + break; - m_wOldStatus = m_wStatus; - } - else wcsncpy_s(newtitle, TranslateT("Message session"), _TRUNCATE); + case DM_STATUSICONCHANGE: + SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, (SBT_OWNERDRAW | (SendMessage(m_pOwner->m_hwndStatus, SB_GETPARTS, 0, 0) - 1)), 0); + break; - if (this == m_pOwner->CurrPage()) { - wchar_t oldtitle[256]; - GetWindowText(m_pOwner->GetHwnd(), oldtitle, _countof(oldtitle)); - if (mir_wstrcmp(newtitle, oldtitle)) //swt() flickers even if the title hasn't actually changed - SetWindowText(m_pOwner->GetHwnd(), newtitle); + case WM_KEYDOWN: + SetFocus(m_message.GetHwnd()); + break; + + case WM_LBUTTONDBLCLK: + if (LOWORD(lParam) < 30) + ScrollToBottom(); + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_ACTIVE) + break; + + SetFocus(m_message.GetHwnd()); + __fallthrough; + + case WM_MOUSEACTIVATE: + OnActivate(); + break; } -} -void CSrmmWindow::UserTyping(int nSecs) -{ - m_nTypeSecs = (nSecs > 0) ? nSecs : 0; + return CSuper::DlgProc(uMsg, wParam, lParam); } ///////////////////////////////////////////////////////////////////////////////////////// -int CSrmmWindow::Resizer(UTILRESIZECONTROL *urc) +static const CHARRANGE rangeAll = { 0, -1 }; + +LRESULT CMsgDialog::WndProc_Log(UINT msg, WPARAM wParam, LPARAM lParam) { - switch (urc->wId) { - case IDC_SRMM_LOG: - if (!g_dat.bShowButtons) - urc->rcItem.top = 2; - urc->rcItem.bottom = urc->dlgNewSize.cy - m_iSplitterY; - return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; - - case IDC_SPLITTERY: - urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY; - urc->rcItem.bottom = urc->rcItem.top + 3; - return RD_ANCHORX_WIDTH | RD_ANCHORY_CUSTOM; - - case IDC_SRMM_MESSAGE: - urc->rcItem.right = (g_dat.bSendButton) ? urc->dlgNewSize.cx - 64 : urc->dlgNewSize.cx; - if (g_dat.bShowAvatar && m_avatarPic) - urc->rcItem.left = m_avatarWidth + 4; - - urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 3; - urc->rcItem.bottom = urc->dlgNewSize.cy - 1; - return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; - - case IDCANCEL: - case IDOK: - urc->rcItem.top = urc->dlgNewSize.cy - m_iSplitterY + 3; - urc->rcItem.bottom = urc->dlgNewSize.cy - 1; - return RD_ANCHORX_RIGHT | RD_ANCHORY_CUSTOM; - - case IDC_AVATAR: - urc->rcItem.top = urc->rcItem.bottom - (m_avatarHeight + 2); - urc->rcItem.right = urc->rcItem.left + (m_avatarWidth + 2); - return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + switch(msg) { + case WM_LBUTTONUP: + CHARRANGE sel; + 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 (ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) + return FALSE; } - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; + + return CSuper::WndProc_Log(msg, wParam, lParam); } ///////////////////////////////////////////////////////////////////////////////////////// -LRESULT CSrmmWindow::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) +LRESULT CMsgDialog::WndProc_Nicklist(UINT msg, WPARAM wParam, LPARAM lParam) { - bool isShift, isCtrl, isAlt; - switch (msg) { - case WM_DROPFILES: - SendMessage(m_hwnd, WM_DROPFILES, wParam, lParam); - break; - - case WM_CHAR: - if (GetWindowLongPtr(m_message.GetHwnd(), GWL_STYLE) & ES_READONLY) - break; - - if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000) { //ctrl-a - m_message.SendMsg(EM_SETSEL, 0, -1); - return 0; + case WM_KEYDOWN: + if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) + CloseTab(); + return TRUE; } break; + } - case WM_KEYDOWN: - isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; - isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; + return CSuper::WndProc_Nicklist(msg, wParam, lParam); +} - if (wParam == VK_RETURN) { - if (!isShift && !isCtrl && g_dat.bSendOnEnter) { - onClick_Ok(&m_btnOk); - return 0; - } - if (!isShift && isCtrl && g_dat.bSendOnCtrlEnter) { - onClick_Ok(&m_btnOk); - return 0; - } - if (g_dat.bSendOnDblEnter) { - if (m_iLastEnterTime + ENTERCLICKTIME < GetTickCount()) - m_iLastEnterTime = GetTickCount(); - else { - m_message.SendMsg(WM_KEYDOWN, VK_BACK, 0); - m_message.SendMsg(WM_KEYUP, VK_BACK, 0); - onClick_Ok(&m_btnOk); - return 0; - } - } - } - else m_iLastEnterTime = 0; +///////////////////////////////////////////////////////////////////////////////////////// - if (wParam == VK_INSERT && isShift || wParam == 'V' && isCtrl) { // ctrl-v (paste clean text) - m_message.SendMsg(WM_PASTE, 0, 0); - return 0; - } - - if (isCtrl && g_dat.bCtrlSupport && !g_dat.bAutoClose) { - if (wParam == VK_UP) { - if (m_cmdList.getCount()) { - if (m_cmdListInd < 0) { - m_cmdListInd = m_cmdList.getCount() - 1; - SetEditorText(m_message.GetHwnd(), m_cmdList[m_cmdListInd]); - } - else if (m_cmdListInd > 0) { - SetEditorText(m_message.GetHwnd(), m_cmdList[--m_cmdListInd]); - } - } - m_btnOk.Enable(GetWindowTextLength(m_message.GetHwnd()) != 0); - UpdateReadChars(); - return 0; - } +LRESULT CMsgDialog::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_MOUSEWHEEL: + m_log.SendMsg(WM_MOUSEWHEEL, wParam, lParam); + m_iLastEnterTime = 0; + return TRUE; - if (wParam == VK_DOWN) { - if (m_cmdList.getCount() && m_cmdListInd >= 0) { - if (m_cmdListInd < m_cmdList.getCount() - 1) - SetEditorText(m_message.GetHwnd(), m_cmdList[++m_cmdListInd]); - else { - m_cmdListInd = -1; - SetEditorText(m_message.GetHwnd(), m_cmdList[m_cmdList.getCount() - 1]); - } - } + case EM_REPLACESEL: + PostMessage(m_message.GetHwnd(), EM_ACTIVATE, 0, 0); + break; - m_btnOk.Enable(GetWindowTextLength(m_message.GetHwnd()) != 0); - UpdateReadChars(); - return 0; - } - } + case EM_ACTIVATE: + SetActiveWindow(m_hwnd); + break; - if (ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) - return FALSE; + case WM_DROPFILES: + ProcessFileDrop((HDROP)wParam); break; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: - case WM_MOUSEWHEEL: case WM_KILLFOCUS: m_iLastEnterTime = 0; break; @@ -1054,15 +1098,13 @@ LRESULT CSrmmWindow::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) case WM_SYSCHAR: m_iLastEnterTime = 0; if ((wParam == 's' || wParam == 'S') && GetKeyState(VK_MENU) & 0x8000) { - onClick_Ok(&m_btnOk); + m_btnOk.Click(); return 0; } break; case WM_CONTEXTMENU: { - static const CHARRANGE all = { 0, -1 }; - MessageWindowPopupData mwpd = {}; mwpd.uType = MSG_WINDOWPOPUP_SHOWING; mwpd.uFlags = MSG_WINDOWPOPUP_INPUT; @@ -1114,7 +1156,7 @@ LRESULT CSrmmWindow::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) // Second notification mwpd.uType = MSG_WINDOWPOPUP_SELECTED; - NotifyEventHooks(g_chatApi.hevWinPopup, 0, (LPARAM)&mwpd); + NotifyEventHooks(g_chatApi.hevWinPopup, 0, (LPARAM)& mwpd); switch (mwpd.selection) { case IDM_UNDO: @@ -1139,7 +1181,7 @@ LRESULT CSrmmWindow::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) case IDM_PASTESEND: m_message.SendMsg(EM_PASTESPECIAL, CF_TEXT, 0); - onClick_Ok(&m_btnOk); + m_btnOk.Click(); break; case IDM_DELETE: @@ -1147,7 +1189,7 @@ LRESULT CSrmmWindow::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) break; case IDM_SELECTALL: - m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&all); + m_message.SendMsg(EM_EXSETSEL, 0, (LPARAM)&rangeAll); break; case IDM_CLEAR: @@ -1169,363 +1211,649 @@ LRESULT CSrmmWindow::WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) } else m_message.SendMsg(EM_PASTESPECIAL, CF_TEXT, 0); return 0; - } - - return CSuper::WndProc_Message(msg, wParam, lParam); -} -///////////////////////////////////////////////////////////////////////////////////////// + case WM_KEYUP: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + if (isChat()) + RefreshButtonStatus(); + break; -INT_PTR CSrmmWindow::DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - ENLINK *pLink; - CHARRANGE sel; - RECT rc; + case WM_KEYDOWN: + bool isShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; + bool isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; + bool isAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; - switch (uMsg) { - case WM_CONTEXTMENU: - if (m_pOwner->m_hwndStatus == (HWND)wParam) { - POINT pt, pt2; - GetCursorPos(&pt); - pt2.x = pt.x; pt2.y = pt.y; - ScreenToClient(m_pOwner->m_hwndStatus, &pt); - - // no popup menu for status icons - this is handled via NM_RCLICK notification and the plugins that added the icons - SendMessage(m_pOwner->m_hwndStatus, SB_GETRECT, SendMessage(m_pOwner->m_hwndStatus, SB_GETPARTS, 0, 0) - 1, (LPARAM)&rc); - if (pt.x >= rc.left) - break; - - HMENU hMenu = Menu_BuildContactMenu(m_hContact); - TrackPopupMenu(hMenu, 0, pt2.x, pt2.y, 0, m_hwnd, nullptr); - DestroyMenu(hMenu); + if (wParam == VK_RETURN) { + if (!isShift && !isCtrl && g_dat.bSendOnEnter) { + m_btnOk.Click(); + return 0; + } + if (!isShift && isCtrl && g_dat.bSendOnCtrlEnter) { + m_btnOk.Click(); + return 0; + } + if (g_dat.bSendOnDblEnter) { + if (m_iLastEnterTime + ENTERCLICKTIME < GetTickCount()) + m_iLastEnterTime = GetTickCount(); + else { + m_message.SendMsg(WM_KEYDOWN, VK_BACK, 0); + m_message.SendMsg(WM_KEYUP, VK_BACK, 0); + m_btnOk.Click(); + return 0; + } + } } - break; - - case WM_DROPFILES: // Mod from tabsrmm - ProcessFileDrop((HDROP)wParam); - return TRUE; - - case HM_AVATARACK: - ShowAvatar(); - break; + else m_iLastEnterTime = 0; - case DM_OPTIONSAPPLIED: - OnOptionsApplied(wParam != 0); - break; + if (g_Settings.bTabsEnable) { + if (wParam <= '9' && wParam >= '1' && isCtrl && !isAlt) { // CTRL + 1 -> 9 (switch tab) + m_pOwner->SwitchTab(wParam - '1'); + return TRUE; + } - case DM_NEWTIMEZONE: - m_hTimeZone = TimeZone_CreateByContact(m_hContact, nullptr, TZF_KNOWNONLY); - m_wMinute = 61; - Resize(); - break; + if (wParam <= VK_NUMPAD9 && wParam >= VK_NUMPAD1 && isCtrl && !isAlt) { // CTRL + 1 -> 9 (switch tab) + m_pOwner->SwitchTab(wParam - VK_NUMPAD1); + return TRUE; + } - case WM_CBD_LOADICONS: - Srmm_UpdateToolbarIcons(m_hwnd); - break; + if (wParam == VK_TAB && isCtrl && !isShift) { // CTRL-TAB (switch tab/window) + m_pOwner->SwitchNextTab(); + return TRUE; + } - case WM_CBD_UPDATED: - SetButtonsPos(m_hwnd, false); - break; + if (wParam == VK_TAB && isCtrl && isShift) { // CTRL_SHIFT-TAB (switch tab/window) + m_pOwner->SwitchPrevTab(); + return TRUE; + } - case WM_SIZE: - if (!IsIconic(m_hwnd)) { - BOOL bottomScroll = TRUE; + if (wParam == 0x57 && isCtrl && !isAlt) { // ctrl-w (close window) + CloseTab(); + return TRUE; + } + } - SetupStatusBar(); + if (isChat()) { + if (wParam == 0x46 && isCtrl && !isAlt) { // ctrl-f (toggle filter) + m_btnFilter.Click(); + return TRUE; + } - 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; + if (wParam == 0x4e && isCtrl && !isAlt) { // ctrl-n (nicklist) + m_btnNickList.Click(); + return TRUE; } - CDlgBase::DlgProc(uMsg, 0, 0); - SetButtonsPos(m_hwnd, false); + if (wParam == 0x4f && isCtrl && !isAlt) { // ctrl-o (options) + m_btnChannelMgr.Click(); + return TRUE; + } - // The statusbar sometimes draws over these 2 controls so redraw them - RedrawWindow(m_btnOk.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); - RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); - if (g_dat.bShowAvatar && m_avatarPic) - RedrawWindow(m_avatar.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); + if ((wParam == 45 && isShift || wParam == 0x56 && isCtrl) && !isAlt) { // ctrl-v (paste clean text) + m_message.SendMsg(EM_PASTESPECIAL, CF_TEXT, 0); + return TRUE; + } - if (bottomScroll) - ScrollToBottom(); - } - return TRUE; + if (wParam == VK_TAB && isShift && !isCtrl) { // SHIFT-TAB (go to nick list) + SetFocus(m_nickList.GetHwnd()); + return TRUE; + } - case HM_DBEVENTADDED: - if (wParam == m_hContact) { - MEVENT hDbEvent = lParam; - if (m_hDbEventFirst == 0) - m_hDbEventFirst = hDbEvent; + if (wParam == VK_TAB && !isCtrl && !isShift) { // tab-autocomplete + TabAutoComplete(); + return 0; + } - DBEVENTINFO dbei = {}; - db_event_get(hDbEvent, &dbei); - bool isMessage = (dbei.eventType == EVENTTYPE_MESSAGE), isSent = ((dbei.flags & DBEF_SENT) != 0); - bool isActive = IsActive(); - if (DbEventIsShown(&dbei)) { - // Sounds *only* for sent messages, not for custom events - if (isMessage && !isSent) { - if (isActive) - Skin_PlaySound("RecvMsgActive"); - else - Skin_PlaySound("RecvMsgInactive"); - } - if (isMessage && !isSent) { - m_lastMessage = dbei.timestamp; - UpdateLastMessage(); - } + if (m_szTabSave[0] != '\0' && wParam != VK_RIGHT && wParam != VK_LEFT && wParam != VK_SPACE && wParam != VK_RETURN && wParam != VK_BACK && wParam != VK_DELETE) { + if (g_Settings.bAddColonToAutoComplete && m_iTabStart == 0) + SendMessageA(m_message.GetHwnd(), EM_REPLACESEL, FALSE, (LPARAM) ": "); - if (hDbEvent != m_hDbEventFirst && db_event_next(m_hContact, hDbEvent) == 0) - StreamInEvents(hDbEvent, 1, 1); - else - RemakeLog(); + m_szTabSave[0] = '\0'; + } - // 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(); - } - } - else StartFlash(); - } + if (wParam == VK_NEXT || wParam == VK_PRIOR) { + m_log.SendMsg(msg, wParam, lParam); + m_iLastEnterTime = 0; + return TRUE; } } - break; - - case WM_TIMECHANGE: - PostMessage(m_hwnd, DM_NEWTIMEZONE, 0, 0); - RemakeLog(); - break; - case WM_TIMER: - if (wParam == TIMERID_TYPE) { - ShowTime(false); - if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - m_nLastTyping > TIMEOUT_TYPEOFF) - NotifyTyping(PROTOTYPE_SELFTYPING_OFF); + if (wParam == VK_INSERT && isShift || wParam == 'V' && isCtrl) { // ctrl-v (paste clean text) + m_message.SendMsg(WM_PASTE, 0, 0); + return 0; + } - if (m_bShowTyping) { - if (m_nTypeSecs) { - m_nTypeSecs--; - if (GetForegroundWindow() == m_pOwner->GetHwnd()) - FixTabIcons(); - } - else { - UpdateLastMessage(); - if (g_dat.bShowTypingWin) - FixTabIcons(); - m_bShowTyping = false; + if (isCtrl && g_dat.bCtrlSupport && !g_dat.bAutoClose) { + if (wParam == VK_UP) { + if (m_cmdList.getCount()) { + if (m_cmdListInd < 0) { + m_cmdListInd = m_cmdList.getCount() - 1; + SetEditorText(m_message.GetHwnd(), m_cmdList[m_cmdListInd]); + } + else if (m_cmdListInd > 0) { + SetEditorText(m_message.GetHwnd(), m_cmdList[--m_cmdListInd]); + } } + m_btnOk.Enable(GetWindowTextLength(m_message.GetHwnd()) != 0); + UpdateReadChars(); + return 0; } - else { - if (m_nTypeSecs) { - wchar_t szBuf[256]; - wchar_t* szContactName = Clist_GetContactDisplayName(m_hContact); - HICON hTyping = Skin_LoadIcon(SKINICON_OTHER_TYPING); - - mir_snwprintf(szBuf, TranslateT("%s is typing a message..."), szContactName); - m_nTypeSecs--; - SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf); - SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hTyping); - if (g_dat.bShowTypingWin && GetForegroundWindow() != m_pOwner->GetHwnd()) { - HICON hIcon = (HICON)SendMessage(m_hwnd, WM_GETICON, ICON_SMALL, 0); - SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hTyping); - IcoLib_ReleaseIcon(hIcon); + if (wParam == VK_DOWN) { + if (m_cmdList.getCount() && m_cmdListInd >= 0) { + if (m_cmdListInd < m_cmdList.getCount() - 1) + SetEditorText(m_message.GetHwnd(), m_cmdList[++m_cmdListInd]); + else { + m_cmdListInd = -1; + SetEditorText(m_message.GetHwnd(), m_cmdList[m_cmdList.getCount() - 1]); } - m_bShowTyping = true; } + + m_btnOk.Enable(GetWindowTextLength(m_message.GetHwnd()) != 0); + UpdateReadChars(); + return 0; } } - break; - case WM_MEASUREITEM: - { - LPMEASUREITEMSTRUCT mis = (LPMEASUREITEMSTRUCT)lParam; - if (mis->CtlType == ODT_MENU) - return Menu_MeasureItem(lParam); - } + if (ProcessHotkeys(wParam, isShift, isCtrl, isAlt)) + return FALSE; break; + } - case WM_DRAWITEM: - { - LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; - if (dis->CtlType == ODT_MENU) - return Menu_DrawItem(lParam); - - if (dis->CtlID == IDC_AVATAR && m_avatarPic && g_dat.bShowAvatar) { - HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); - HPEN hOldPen = (HPEN)SelectObject(dis->hDC, hPen); - Rectangle(dis->hDC, 0, 0, m_avatarWidth, m_avatarHeight); - SelectObject(dis->hDC, hOldPen); - DeleteObject(hPen); - - BITMAP bminfo; - GetObject(m_avatarPic, sizeof(bminfo), &bminfo); + return CSuper::WndProc_Message(msg, wParam, lParam); +} - HDC hdcMem = CreateCompatibleDC(dis->hDC); - HBITMAP hbmMem = (HBITMAP)SelectObject(hdcMem, m_avatarPic); +///////////////////////////////////////////////////////////////////////////////////////// - SetStretchBltMode(dis->hDC, HALFTONE); - StretchBlt(dis->hDC, 1, 1, m_avatarWidth - 2, m_avatarHeight - 2, hdcMem, 0, 0, - bminfo.bmWidth, bminfo.bmHeight, SRCCOPY); +int CMsgDialog::GetImageId() const +{ + if (m_nFlash & 1) + return 0; - SelectObject(hdcMem, hbmMem); - DeleteDC(hdcMem); - return TRUE; - } - } - break; + return g_clistApi.pfnIconFromStatusMode(m_szProto, m_wStatus, m_hContact); +} - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_USERMENU: - if (GetKeyState(VK_SHIFT) & 0x8000) { // copy user name - ptrW id(Contact_GetInfo(CNF_UNIQUEID, m_hContact, m_szProto)); - if (id != nullptr && OpenClipboard(m_hwnd)) { - HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, mir_wstrlen(id) * sizeof(wchar_t) + 1); - if (hData) { - EmptyClipboard(); - mir_wstrcpy((wchar_t*)GlobalLock(hData), id); - GlobalUnlock(hData); - SetClipboardData(CF_UNICODETEXT, hData); - CloseClipboard(); - } - } - } - else { - HMENU hMenu = Menu_BuildContactMenu(m_hContact); - GetWindowRect(GetDlgItem(m_hwnd, LOWORD(wParam)), &rc); - TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, m_hwnd, nullptr); - DestroyMenu(hMenu); +bool CMsgDialog::IsActive() const +{ + bool bRes = m_pOwner->IsActive(); + if (g_Settings.bTabsEnable && bRes) + bRes &= m_pOwner->m_tab.GetActivePage() == this; + + 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); +} + +void CMsgDialog::StopFlash() +{ + if (::KillTimer(m_hwnd, TIMERID_FLASHWND)) { + ::FlashWindow(m_pOwner->GetHwnd(), FALSE); + + m_nFlash = 0; + FixTabIcons(); + } +} + +void CMsgDialog::TabAutoComplete() +{ + LRESULT lResult = (LRESULT)m_message.SendMsg(EM_GETSEL, 0, 0); + + m_message.SendMsg(WM_SETREDRAW, FALSE, 0); + m_iTabStart = LOWORD(lResult); + int end = HIWORD(lResult); + m_message.SendMsg(EM_SETSEL, end, end); + + GETTEXTLENGTHEX gtl = {}; + gtl.flags = GTL_PRECISE; + gtl.codepage = CP_ACP; + int iLen = m_message.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)& gtl, 0); + if (iLen > 0) { + wchar_t *pszText = (wchar_t *)mir_alloc(sizeof(wchar_t) * (iLen + 100)); + + GETTEXTEX gt = {}; + gt.cb = iLen + 99; + gt.flags = GT_DEFAULT; + gt.codepage = 1200; + m_message.SendMsg(EM_GETTEXTEX, (WPARAM)& gt, (LPARAM)pszText); + + while (m_iTabStart > 0 && pszText[m_iTabStart - 1] != ' ' && pszText[m_iTabStart - 1] != 13 && pszText[m_iTabStart - 1] != VK_TAB) + m_iTabStart--; + while (end < iLen && pszText[end] != ' ' && pszText[end] != 13 && pszText[end - 1] != VK_TAB) + end++; + + if (m_szTabSave[0] == '\0') + mir_wstrncpy(m_szTabSave, pszText + m_iTabStart, end - m_iTabStart + 1); + + wchar_t *pszSelName = (wchar_t *)mir_alloc(sizeof(wchar_t) * (end - m_iTabStart + 1)); + mir_wstrncpy(pszSelName, pszText + m_iTabStart, end - m_iTabStart + 1); + + wchar_t *pszName = g_chatApi.UM_FindUserAutoComplete(m_si, m_szTabSave, pszSelName); + if (pszName == nullptr) { + pszName = m_szTabSave; + m_message.SendMsg(EM_SETSEL, m_iTabStart, end); + if (end != m_iTabStart) + m_message.SendMsg(EM_REPLACESEL, FALSE, (LPARAM)pszName); + m_szTabSave[0] = '\0'; + } + else { + m_message.SendMsg(EM_SETSEL, m_iTabStart, end); + if (end != m_iTabStart) + m_message.SendMsg(EM_REPLACESEL, FALSE, (LPARAM)pszName); + } + mir_free(pszText); + mir_free(pszSelName); + } + + m_message.SendMsg(WM_SETREDRAW, TRUE, 0); + RedrawWindow(m_message.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CMsgDialog::OnOptionsApplied(bool bUpdateAvatar) +{ + CustomButtonData *cbd; + for (int i = 0; cbd = Srmm_GetNthButton(i); i++) { + HWND hwndButton = GetDlgItem(m_hwnd, cbd->m_dwButtonCID); + if (hwndButton == nullptr) + continue; + + bool bShow = false; + if (m_hContact && g_dat.bShowButtons) { + if (cbd->m_dwButtonCID == IDC_ADD) { + bShow = 0 != db_get_b(m_hContact, "CList", "NotOnList", 0); + cbd->m_bHidden = !bShow; } - break; + else bShow = true; + } + ShowWindow(hwndButton, (bShow) ? SW_SHOW : SW_HIDE); + } + + ShowWindow(GetDlgItem(m_hwnd, IDCANCEL), SW_HIDE); + m_splitterY.Show(); + + m_btnOk.Show(g_dat.bSendButton); + m_btnOk.Enable(GetWindowTextLength(m_message.GetHwnd()) != 0); + + if (m_avatarPic == nullptr || !g_dat.bShowAvatar) + m_avatar.Hide(); + + UpdateIcon(0); + 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); + + // avatar stuff + m_avatarPic = nullptr; + m_limitAvatarH = 0; + if (CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_AVATARS) + m_limitAvatarH = g_dat.bLimitAvatarHeight ? g_dat.iAvatarHeight : 0; + + if (bUpdateAvatar) + UpdateAvatar(); + + InvalidateRect(m_message.GetHwnd(), nullptr, FALSE); + + LOGFONT lf; + CHARFORMAT cf = {}; + if (m_hFont) + DeleteObject(m_hFont); + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, &lf, &cf.crTextColor); + m_hFont = CreateFontIndirect(&lf); + m_message.SendMsg(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(TRUE, 0)); + + cf.cbSize = sizeof(CHARFORMAT); + 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); + + RemakeLog(); + FixTabIcons(); +} + +void CMsgDialog::onSplitterX(CSplitter *pSplitter) +{ + RECT rc; + GetClientRect(m_hwnd, &rc); + + m_iSplitterX = rc.right - pSplitter->GetPos() + 1; + if (m_iSplitterX < 35) + m_iSplitterX = 35; + if (m_iSplitterX > rc.right - rc.left - 35) + m_iSplitterX = rc.right - rc.left - 35; + g_Settings.iSplitterX = m_iSplitterX; +} + +void CMsgDialog::onSplitterY(CSplitter *pSplitter) +{ + RECT rc; + GetClientRect(m_hwnd, &rc); + + m_iSplitterY = rc.bottom - pSplitter->GetPos() + 1; + + int toplimit = 63; + if (!g_dat.bShowButtons) + toplimit += 22; + + if (m_iSplitterY < m_minEditBoxSize.cy) + m_iSplitterY = m_minEditBoxSize.cy; + if (m_iSplitterY > rc.bottom - rc.top - toplimit) + m_iSplitterY = rc.bottom - rc.top - toplimit; + g_Settings.iSplitterY = m_iSplitterY; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CMsgDialog::CloseTab() +{ + if (g_Settings.bTabsEnable) { + m_pOwner->RemoveTab(this); + Close(); + } + else SendMessage(m_hwndParent, WM_CLOSE, 0, 0); +} + +void CMsgDialog::NotifyTyping(int mode) +{ + if (!m_hContact) + return; + + // Don't send to protocols who don't support typing + // Don't send to users who are unchecked in the typing notification options + // Don't send to protocols that are offline + // Don't send to users who are not visible and + // Don't send to users who are not on the visible list when you are in invisible mode. + if (!g_plugin.getByte(m_hContact, SRMSGSET_TYPING, g_dat.bTypingNew)) + return; + + if (!m_szProto) + return; + + int protoStatus = Proto_GetStatus(m_szProto); + DWORD protoCaps = CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_1, 0); + DWORD typeCaps = CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_4, 0); + + if (!(typeCaps & PF4_SUPPORTTYPING)) + return; + + if (protoStatus < ID_STATUS_ONLINE) + return; + + if (protoCaps & PF1_VISLIST && db_get_w(m_hContact, m_szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) + return; + + if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(m_hContact, m_szProto, "ApparentMode", 0) != ID_STATUS_ONLINE) + return; + + if (!g_dat.bTypingUnknown && db_get_b(m_hContact, "CList", "NotOnList", 0)) + return; + + // End user check + m_nTypeMode = mode; + CallService(MS_PROTO_SELFISTYPING, m_hContact, m_nTypeMode); +} + +void CMsgDialog::RemakeLog() +{ + StreamInEvents(m_hDbEventFirst, -1, 0); +} + +void CMsgDialog::ProcessFileDrop(HDROP hDrop) +{ + if (m_szProto == nullptr) return; + if (!(CallProtoService(m_szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_FILESEND)) return; + if (m_wStatus == ID_STATUS_OFFLINE) return; + if (m_hContact != 0) { + wchar_t szFilename[MAX_PATH]; + int fileCount = DragQueryFile(hDrop, -1, nullptr, 0), totalCount = 0; + wchar_t **ppFiles = nullptr; + for (int i = 0; i < fileCount; i++) { + DragQueryFile(hDrop, i, szFilename, _countof(szFilename)); + AddToFileList(&ppFiles, totalCount, szFilename); + } + CallServiceSync(MS_FILE_SENDSPECIFICFILEST, m_hContact, (LPARAM)ppFiles); + if (ppFiles) { + for (int i = 0; ppFiles[i]; i++) + mir_free(ppFiles[i]); + mir_free(ppFiles); + } + } +} - case IDC_DETAILS: - CallService(MS_USERINFO_SHOWDIALOG, m_hContact, 0); - break; +void CMsgDialog::ShowAvatar() +{ + if (g_dat.bShowAvatar) { + AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, getActiveContact(), 0); + if (ace && (INT_PTR)ace != CALLSERVICE_NOTFOUND && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) + m_avatarPic = ace->hbmPic; + else + m_avatarPic = nullptr; + } + else m_avatarPic = nullptr; - case IDC_ADD: - Contact_Add(m_hContact, m_hwnd); + UpdateSizeBar(); + Resize(); +} - if (!db_get_b(m_hContact, "CList", "NotOnList", 0)) - ShowWindow(GetDlgItem(m_hwnd, IDC_ADD), FALSE); - break; +void CMsgDialog::ShowTime(bool bForce) +{ + if (!m_hTimeZone) + return; - case IDC_SRMM_MESSAGE: - if (HIWORD(wParam) == EN_CHANGE) { - int len = GetWindowTextLength(m_message.GetHwnd()); - UpdateReadChars(); - m_btnOk.Enable(len != 0); - if (!(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000)) { - m_nLastTyping = GetTickCount(); - if (len) { - if (m_nTypeMode == PROTOTYPE_SELFTYPING_OFF) - NotifyTyping(PROTOTYPE_SELFTYPING_ON); - } - else if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON) - NotifyTyping(PROTOTYPE_SELFTYPING_OFF); - } - } - break; + SYSTEMTIME st; + GetSystemTime(&st); + if (m_wMinute != st.wMinute || bForce) { + if (m_pOwner->m_tab.GetActivePage() == this) { + wchar_t buf[32]; + unsigned i = g_dat.bShowReadChar ? 2 : 1; + + TimeZone_PrintDateTime(m_hTimeZone, L"t", buf, _countof(buf), 0); + SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, i, (LPARAM)buf); } - break; + m_wMinute = st.wMinute; + } +} - case WM_NOTIFY: - HCURSOR hCur; - switch (((LPNMHDR)lParam)->idFrom) { - case IDC_SRMM_LOG: - switch (((LPNMHDR)lParam)->code) { - case EN_MSGFILTER: - switch (((MSGFILTER *)lParam)->msg) { - case WM_LBUTTONDOWN: - hCur = GetCursor(); - if (hCur == LoadCursor(nullptr, IDC_SIZENS) || hCur == LoadCursor(nullptr, IDC_SIZEWE) || hCur == LoadCursor(nullptr, IDC_SIZENESW) || hCur == LoadCursor(nullptr, IDC_SIZENWSE)) { - SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE); - return TRUE; - } - break; +void CMsgDialog::SetupStatusBar() +{ + int i = 0, statwidths[4]; + int icons_width = GetStatusIconsCount(m_hContact) * (GetSystemMetrics(SM_CXSMICON) + 2) + SB_GRIP_WIDTH; - case WM_MOUSEMOVE: - hCur = GetCursor(); - if (hCur == LoadCursor(nullptr, IDC_SIZENS) || hCur == LoadCursor(nullptr, IDC_SIZEWE) || hCur == LoadCursor(nullptr, IDC_SIZENESW) || hCur == LoadCursor(nullptr, IDC_SIZENWSE)) - SetCursor(LoadCursor(nullptr, IDC_ARROW)); - break; + RECT rc; + GetWindowRect(m_pOwner->m_hwndStatus, &rc); + int cx = rc.right - rc.left; - case WM_RBUTTONUP: - CHARRANGE all = { 0, -1 }; - HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXT)); - HMENU hSubMenu = GetSubMenu(hMenu, 0); - TranslateMenu(hSubMenu); - SendMessage(((NMHDR *)lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM)&sel); - if (sel.cpMin == sel.cpMax) - EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); + if (m_hTimeZone) { + if (g_dat.bShowReadChar) + statwidths[i++] = cx - SB_TIME_WIDTH - SB_CHAR_WIDTH - icons_width; + statwidths[i++] = cx - SB_TIME_WIDTH - icons_width; + } + else if (g_dat.bShowReadChar) + statwidths[i++] = cx - SB_CHAR_WIDTH - icons_width; - pLink = (ENLINK*)lParam; - POINT pt = { GET_X_LPARAM(pLink->lParam), GET_Y_LPARAM(pLink->lParam) }; - ClientToScreen(pLink->nmhdr.hwndFrom, &pt); + statwidths[i++] = cx - icons_width; + statwidths[i++] = -1; + SendMessage(m_pOwner->m_hwndStatus, SB_SETPARTS, i, (LPARAM)statwidths); - switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_hwnd, nullptr)) { - case IDM_COPY: - SendMessage(pLink->nmhdr.hwndFrom, WM_COPY, 0, 0); - break; - case IDM_COPYALL: - SendMessage(pLink->nmhdr.hwndFrom, EM_EXSETSEL, 0, (LPARAM)&all); - SendMessage(pLink->nmhdr.hwndFrom, WM_COPY, 0, 0); - SendMessage(pLink->nmhdr.hwndFrom, EM_EXSETSEL, 0, (LPARAM)&sel); - break; - case IDM_SELECTALL: - SendMessage(pLink->nmhdr.hwndFrom, EM_EXSETSEL, 0, (LPARAM)&all); - break; - case IDM_CLEAR: - ClearLog(); - m_hDbEventFirst = 0; - break; - } - DestroyMenu(hSubMenu); - DestroyMenu(hMenu); - SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE); - return TRUE; - } - break; + UpdateReadChars(); + ShowTime(true); + SendMessage(m_hwnd, DM_STATUSICONCHANGE, 0, 0); +} - case EN_VSCROLL: - if (LOWORD(wParam) == IDC_SRMM_LOG && GetWindowLongPtr((HWND)lParam, GWL_STYLE) & WS_VSCROLL) { - SCROLLINFO si = {}; - si.cbSize = sizeof(si); - si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; - GetScrollInfo((HWND)lParam, SB_VERT, &si); - if ((si.nPos + (int)si.nPage + 5) >= si.nMax) - StopFlash(); - } - break; +void CMsgDialog::SetStatusText(const wchar_t *wszText, HICON hIcon) +{ + SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hIcon); + SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)(wszText == nullptr ? L"" : wszText)); +} + +void CMsgDialog::UpdateAvatar() +{ + PROTO_AVATAR_INFORMATION ai = {}; + ai.hContact = m_hContact; + CallProtoService(m_szProto, PS_GETAVATARINFO, GAIF_FORCE, (LPARAM)&ai); + + ShowAvatar(); + SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, 1); +} + +void CMsgDialog::UpdateIcon(WPARAM wParam) +{ + if (!m_hContact || !m_szProto) + return; + + bool bIsStatus = false; + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *)wParam; + if (cws && !mir_strcmp(cws->szModule, m_szProto) && !mir_strcmp(cws->szSetting, "Status")) { + bIsStatus = true; + m_wStatus = cws->value.wVal; + } + + if (!cws || bIsStatus) + if (g_dat.bUseStatusWinIcon) + FixTabIcons(); +} + +void CMsgDialog::UpdateLastMessage() +{ + if (m_nTypeSecs) + return; + + if (m_lastMessage) { + wchar_t date[64], time[64], fmt[128]; + TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"d", date, _countof(date), 0); + TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"t", time, _countof(time), 0); + mir_snwprintf(fmt, TranslateT("Last message received on %s at %s."), date, time); + SetStatusText(fmt, nullptr); + } + else SetStatusText(nullptr, nullptr); +} + +void CMsgDialog::UpdateReadChars() +{ + if (g_dat.bShowReadChar) { + wchar_t buf[32]; + int len = GetWindowTextLength(m_message.GetHwnd()); + + mir_snwprintf(buf, L"%d", len); + SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 1, (LPARAM)buf); + } +} + +void CMsgDialog::UpdateSizeBar() +{ + m_minEditBoxSize.cx = m_minEditInit.right - m_minEditInit.left; + m_minEditBoxSize.cy = m_minEditInit.bottom - m_minEditInit.top; + if (g_dat.bShowAvatar) { + if (m_avatarPic == nullptr || !g_dat.bShowAvatar) { + m_avatarWidth = 50; + m_avatarHeight = 50; + m_avatar.Hide(); + return; + } + else { + BITMAP bminfo; + GetObject(m_avatarPic, sizeof(bminfo), &bminfo); + m_avatarWidth = bminfo.bmWidth + 2; + m_avatarHeight = bminfo.bmHeight + 2; + if (m_limitAvatarH && m_avatarHeight > m_limitAvatarH) { + m_avatarWidth = bminfo.bmWidth * m_limitAvatarH / bminfo.bmHeight + 2; + m_avatarHeight = m_limitAvatarH + 2; } + m_avatar.Show(); } - break; - case DM_UPDATETITLE: - if (lParam != 0) { - bool bIsMe = (lParam == m_hContact) || (m_bIsMeta && db_mc_getMeta(lParam) == m_hContact); - if (!bIsMe) - break; + if (m_avatarPic && m_minEditBoxSize.cy <= m_avatarHeight) { + m_minEditBoxSize.cy = m_avatarHeight + 8; + if (m_iSplitterY < m_minEditBoxSize.cy) { + m_iSplitterY = m_minEditBoxSize.cy; + Resize(); + } } + } +} - UpdateIcon(wParam); - UpdateTitle(); - break; +void CMsgDialog::UpdateTitle() +{ + wchar_t newtitle[256]; + if (isChat()) { + int nUsers = m_si->getUserList().getCount(); + + switch (m_si->iType) { + case GCW_CHATROOM: + mir_snwprintf(newtitle, + (nUsers == 1) ? TranslateT("%s: chat room (%u user)") : TranslateT("%s: chat room (%u users)"), + m_si->ptszName, nUsers); + break; + case GCW_PRIVMESS: + mir_snwprintf(newtitle, + (nUsers == 1) ? TranslateT("%s: message session") : TranslateT("%s: message session (%u users)"), + m_si->ptszName, nUsers); + break; + case GCW_SERVER: + mir_snwprintf(newtitle, L"%s: Server", m_si->ptszName); + break; + } + } + else { + if (m_hContact && m_szProto) { + m_wStatus = db_get_w(m_hContact, m_szProto, "Status", ID_STATUS_OFFLINE); + wchar_t *contactName = Clist_GetContactDisplayName(m_hContact); - case DM_STATUSICONCHANGE: - SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, (SBT_OWNERDRAW | (SendMessage(m_pOwner->m_hwndStatus, SB_GETPARTS, 0, 0) - 1)), 0); - break; + if (g_dat.bUseStatusWinIcon) + mir_snwprintf(newtitle, L"%s - %s", contactName, TranslateT("Message session")); + else { + wchar_t *szStatus = Clist_GetStatusModeDescription(m_szProto == nullptr ? ID_STATUS_OFFLINE : db_get_w(m_hContact, m_szProto, "Status", ID_STATUS_OFFLINE), 0); + mir_snwprintf(newtitle, L"%s (%s): %s", contactName, szStatus, TranslateT("Message session")); + } + + m_wOldStatus = m_wStatus; + } + else wcsncpy_s(newtitle, TranslateT("Message session"), _TRUNCATE); } - - return CSuper::DlgProc(uMsg, wParam, lParam); + + if (this == m_pOwner->CurrPage()) { + wchar_t oldtitle[256]; + GetWindowText(m_pOwner->GetHwnd(), oldtitle, _countof(oldtitle)); + if (mir_wstrcmp(newtitle, oldtitle)) //swt() flickers even if the title hasn't actually changed + SetWindowText(m_pOwner->GetHwnd(), newtitle); + } +} + +void CMsgDialog::UserTyping(int nSecs) +{ + m_nTypeSecs = (nSecs > 0) ? nSecs : 0; } diff --git a/src/core/stdmsg/src/msglog.cpp b/src/core/stdmsg/src/msglog.cpp index ba276e19b2..b48c2365cd 100644 --- a/src/core/stdmsg/src/msglog.cpp +++ b/src/core/stdmsg/src/msglog.cpp @@ -42,7 +42,7 @@ struct LogStreamData CMStringA buf; int eventsToInsert; bool isEmpty; - CSrmmWindow *dlgDat; + CMsgDialog *dlgDat; }; static int logPixelSY; @@ -393,7 +393,7 @@ static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG return 0; } -void CSrmmWindow::StreamInEvents(MEVENT hDbEventFirst, int count, bool bAppend) +void CMsgDialog::StreamInEvents(MEVENT hDbEventFirst, int count, bool bAppend) { CHARRANGE oldSel, sel; BOOL bottomScroll = TRUE; diff --git a/src/core/stdmsg/src/msgs.h b/src/core/stdmsg/src/msgs.h index 7c8e8252e7..f101611e6e 100644 --- a/src/core/stdmsg/src/msgs.h +++ b/src/core/stdmsg/src/msgs.h @@ -37,6 +37,18 @@ class CMsgDialog : public CSrmmBaseDialog typedef CSrmmBaseDialog CSuper; friend class CTabbedWindow; + void NotifyTyping(int mode); + void ProcessFileDrop(HDROP hDrop); + 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; @@ -60,136 +72,71 @@ protected: int m_cmdListInd = 0; LIST m_cmdList; - CMsgDialog(CTabbedWindow *pOwner, int idDialog, SESSION_INFO *si = nullptr); - - virtual int GetStatus() const PURE; - - virtual void OnActivate() PURE; - - bool OnInitDialog() override; - void OnDestroy() 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; - -public: - virtual void RemakeLog() {} - virtual void UpdateAvatar() {} - virtual void UserTyping(int) {} - - int GetImageId() const; - - void __forceinline FixTabIcons() - { m_pOwner->FixTabIcons(this); - } - - void CloseTab() override; - bool IsActive() const override; - void ScrollToBottom() override; - - void StartFlash(); - void StopFlash(); -}; - -class CSrmmWindow : public CMsgDialog -{ - typedef CMsgDialog CSuper; - - LRESULT WndProc_Message(UINT msg, WPARAM wParam, LPARAM lParam) override; - - void NotifyTyping(int mode); - void ProcessFileDrop(HDROP hDrop); - 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); - HFONT m_hFont = nullptr; - int m_windowWasCascaded; - int m_nTypeSecs, m_nTypeMode; - int m_limitAvatarH; - DWORD m_nLastTyping; - DWORD m_lastMessage; - HANDLE m_hTimeZone; - WORD m_wStatus, m_wOldStatus; - WORD m_wMinute; - bool m_bIsMeta, m_bShowTyping; - -public: - bool m_bIsAutoRTL, m_bNoActivate; - MEVENT m_hDbEventFirst, m_hDbEventLast; - - int m_avatarWidth, m_avatarHeight; - - HBITMAP m_avatarPic; - wchar_t *m_wszInitialText; + int m_nTypeSecs = 0, m_nTypeMode = 0; + int m_limitAvatarH = 0; + DWORD m_nLastTyping = 0; + DWORD m_lastMessage = 0; + HANDLE m_hTimeZone = 0; + WORD m_wStatus = ID_STATUS_OFFLINE, m_wOldStatus = ID_STATUS_OFFLINE; + WORD m_wMinute = 0; + bool m_bIsMeta = false, m_bShowTyping = false, m_bWindowCascaded = false, m_bNoActivate = false; public: - CSrmmWindow(CTabbedWindow*, MCONTACT hContact); + CMsgDialog(CTabbedWindow *pOwner, MCONTACT hContact); + CMsgDialog(CTabbedWindow *pOwner, SESSION_INFO *si); bool OnInitDialog() override; void OnDestroy() override; - void OnActivate() override; - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override; int Resizer(UTILRESIZECONTROL *urc) override; - virtual int GetStatus() const { return m_wStatus; } + 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; - void LoadSettings() override {} - void RemakeLog() override; - void SetStatusText(const wchar_t*, HICON) override; - void UpdateAvatar() override; - void UpdateTitle() override; - void UserTyping(int nSecs) override; + void OnActivate(); + void RemakeLog(); + void UpdateAvatar(); + void UserTyping(int nSecs); - void OnSplitterMoved(CSplitter*); + void onSplitterX(CSplitter *); + void onSplitterY(CSplitter *); - void onClick_Ok(CCtrlButton*); + void onClick_Ok(CCtrlButton *); + void onClick_Filter(CCtrlButton *); + void onClick_NickList(CCtrlButton *); void OnOptionsApplied(bool bUpdateAvatar); void UpdateReadChars(void); __forceinline MCONTACT getActiveContact() const - { return (m_bIsMeta) ? db_mc_getSrmmSub(m_hContact) : m_hContact; + { + return (m_bIsMeta) ? db_mc_getSrmmSub(m_hContact) : m_hContact; } -}; - -extern LIST g_arDialogs; -///////////////////////////////////////////////////////////////////////////////////////// - -class CChatRoomDlg : public CMsgDialog -{ - typedef CMsgDialog CSuper; - friend class CTabbedWindow; - - static INT_PTR CALLBACK FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - - 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; + MEVENT m_hDbEventFirst, m_hDbEventLast; -public: - CChatRoomDlg(CTabbedWindow*, SESSION_INFO*); + int m_avatarWidth = 0, m_avatarHeight = 0; - bool OnInitDialog() override; - void OnDestroy() override; - void OnActivate() override; + bool m_bIsAutoRTL = false; + HBITMAP m_avatarPic = 0; + wchar_t *m_wszInitialText = 0; - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override; - int Resizer(UTILRESIZECONTROL *urc) override; + int GetImageId() const; - virtual int GetStatus() const { return m_si->wStatus; } + void __forceinline FixTabIcons() + { m_pOwner->FixTabIcons(this); + } + void CloseTab() override; + bool IsActive() const override; void LoadSettings() override; void RedrawLog() override; + void ScrollToBottom() override; + void SetStatusText(const wchar_t *, HICON) override; void StreamInEvents(LOGINFO *lin, bool bRedraw) override; void ShowFilterMenu() override; void UpdateNickList() override; @@ -197,14 +144,13 @@ public: void UpdateStatusBar() override; void UpdateTitle() override; - void onClick_Ok(CCtrlButton*); + void StartFlash(); + void StopFlash(); +}; - void onClick_Filter(CCtrlButton*); - void onClick_NickList(CCtrlButton*); +extern LIST g_arDialogs; - void onSplitterX(CSplitter*); - void onSplitterY(CSplitter*); -}; +///////////////////////////////////////////////////////////////////////////////////////// int DbEventIsForMsgWindow(DBEVENTINFO *dbei); int DbEventIsShown(DBEVENTINFO *dbei); diff --git a/src/core/stdmsg/src/resource.h b/src/core/stdmsg/src/resource.h index 2464723183..78bd1288d8 100644 --- a/src/core/stdmsg/src/resource.h +++ b/src/core/stdmsg/src/resource.h @@ -2,7 +2,6 @@ // Microsoft Visual C++ generated include file. // Used by resource.rc // -#define IDD_CHANNEL 101 #define IDD_MSGSENDERROR 102 #define IDD_OPTIONS2 103 #define IDD_OPTIONS1 104 diff --git a/src/core/stdmsg/src/tabs.cpp b/src/core/stdmsg/src/tabs.cpp index 15c3d47d9f..8366c2d441 100644 --- a/src/core/stdmsg/src/tabs.cpp +++ b/src/core/stdmsg/src/tabs.cpp @@ -203,7 +203,7 @@ int CTabbedWindow::Resizer(UTILRESIZECONTROL *urc) CTabbedWindow* CTabbedWindow::AddPage(MCONTACT hContact, wchar_t *pwszText, int iNoActivate) { - CSrmmWindow *pDlg = new CSrmmWindow(this, hContact); + CMsgDialog *pDlg = new CMsgDialog(this, hContact); pDlg->m_wszInitialText = pwszText; if (iNoActivate != -1) pDlg->m_bNoActivate = iNoActivate != 0; @@ -239,7 +239,7 @@ void CTabbedWindow::AddPage(SESSION_INFO *si, int insertAt) if (!IsWindowVisible(m_hwnd)) Show(SW_SHOW); - CChatRoomDlg *pDlg = new CChatRoomDlg(this, si); + CMsgDialog *pDlg = new CMsgDialog(this, si); pDlg->SetParent(m_hwnd); m_tab.AddPage(szTemp, nullptr, pDlg); m_tab.ActivatePage(m_tab.GetCount() - 1); @@ -261,7 +261,7 @@ void CTabbedWindow::DropTab(int begin, int end) m_tab.SwapPages(begin, end); - CChatRoomDlg *pDlg = (CChatRoomDlg *)m_tab.GetNthPage(end); + CMsgDialog *pDlg = (CMsgDialog *)m_tab.GetNthPage(end); if (pDlg) { FixTabIcons(pDlg); m_tab.ActivatePage(end); @@ -270,7 +270,7 @@ void CTabbedWindow::DropTab(int begin, int end) // fix the "fixed" positions int tabCount = m_tab.GetCount(); for (int i = 0; i < tabCount; i++) { - pDlg = (CChatRoomDlg *)m_tab.GetNthPage(i); + pDlg = (CMsgDialog *)m_tab.GetNthPage(i); if (pDlg == nullptr) continue; @@ -306,7 +306,7 @@ void CTabbedWindow::FixTabIcons(CMsgDialog *pDlg) if (pDlg == CurrPage()) { Window_FreeIcon_IcoLib(m_hwnd); if (g_dat.bUseStatusWinIcon) - Window_SetProtoIcon_IcoLib(m_hwnd, pDlg->m_szProto, pDlg->GetStatus()); + Window_SetProtoIcon_IcoLib(m_hwnd, pDlg->m_szProto, pDlg->m_wStatus); else if (pDlg->isChat()) Window_SetIcon_IcoLib(m_hwnd, g_plugin.getIconHandle(IDI_CHANMGR)); else @@ -463,7 +463,7 @@ void CTabbedWindow::SwitchTab(int iNewTab) void CTabbedWindow::TabClicked() { - CChatRoomDlg *pDlg = (CChatRoomDlg*)m_tab.GetActivePage(); + CMsgDialog *pDlg = (CMsgDialog*)m_tab.GetActivePage(); if (pDlg == nullptr) return; -- cgit v1.2.3