summaryrefslogtreecommitdiff
path: root/plugins/TabSRMM/src/generic_msghandlers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/TabSRMM/src/generic_msghandlers.cpp')
-rw-r--r--plugins/TabSRMM/src/generic_msghandlers.cpp2716
1 files changed, 1358 insertions, 1358 deletions
diff --git a/plugins/TabSRMM/src/generic_msghandlers.cpp b/plugins/TabSRMM/src/generic_msghandlers.cpp
index 9399fdc313..f704717da6 100644
--- a/plugins/TabSRMM/src/generic_msghandlers.cpp
+++ b/plugins/TabSRMM/src/generic_msghandlers.cpp
@@ -1,1358 +1,1358 @@
-/////////////////////////////////////////////////////////////////////////////////////////
-// Miranda NG: the free IM client for Microsoft* Windows*
-//
-// Copyright (C) 2012-22 Miranda NG team,
-// Copyright (c) 2000-09 Miranda ICQ/IM project,
-// all portions of this codebase are copyrighted to the people
-// listed in contributors.txt.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// you should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-//
-// part of tabSRMM messaging plugin for Miranda.
-//
-// (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
-//
-// these are generic message handlers which are used by the message dialog window procedure.
-// calling them directly instead of using SendMessage() is faster.
-// also contains various callback functions for custom buttons
-
-#include "stdafx.h"
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Save message log for given session as RTF document
-
-/*
-void CMsgDialog::DM_SaveLogAsRTF() const
-{
- if (m_hwndIEView != nullptr) {
- IEVIEWEVENT event = { sizeof(event) };
- event.hwnd = m_hwndIEView;
- event.hContact = m_hContact;
- event.iType = IEE_SAVE_DOCUMENT;
- CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
- }
- else {
- wchar_t szFilter[MAX_PATH], szFilename[MAX_PATH];
- mir_snwprintf(szFilter, L"%s%c*.rtf%c%c", TranslateT("Rich Edit file"), 0, 0, 0);
- mir_snwprintf(szFilename, L"%s.rtf", m_cache->getNick());
-
- Utils::sanitizeFilename(szFilename);
-
- wchar_t szInitialDir[MAX_PATH + 2];
- mir_snwprintf(szInitialDir, L"%s%s\\", M.getDataPath(), L"\\Saved message logs");
- CreateDirectoryTreeW(szInitialDir);
-
- OPENFILENAME ofn = { 0 };
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = m_hwnd;
- ofn.lpstrFile = szFilename;
- ofn.lpstrFilter = szFilter;
- ofn.lpstrInitialDir = szInitialDir;
- ofn.nMaxFile = MAX_PATH;
- ofn.Flags = OFN_HIDEREADONLY;
- ofn.lpstrDefExt = L"rtf";
- if (GetSaveFileName(&ofn)) {
- EDITSTREAM stream = { 0 };
- stream.dwCookie = (DWORD_PTR)szFilename;
- stream.dwError = 0;
- stream.pfnCallback = Utils::StreamOut;
- m_rtf.SendMsg(EM_STREAMOUT, SF_RTF | SF_USECODEPAGE, (LPARAM)&stream);
- }
- }
-}
-*/
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// checks if the balloon tooltip can be dismissed (usually called by WM_MOUSEMOVE events)
-
-void CMsgDialog::DM_DismissTip(const POINT& pt)
-{
- if (!IsWindowVisible(m_hwndTip))
- return;
-
- RECT rc;
- GetWindowRect(m_hwndTip, &rc);
- if (PtInRect(&rc, pt))
- return;
-
- if (abs(pt.x - m_ptTipActivation.x) > 5 || abs(pt.y - m_ptTipActivation.y) > 5) {
- SendMessage(m_hwndTip, TTM_TRACKACTIVATE, FALSE, 0);
- m_ptTipActivation.x = m_ptTipActivation.y = 0;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// initialize the balloon tooltip for message window notifications
-
-void CMsgDialog::DM_InitTip()
-{
- m_hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, nullptr, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT, m_hwnd, nullptr, g_plugin.getInst(), (LPVOID)nullptr);
-
- memset(&ti, 0, sizeof(ti));
- ti.cbSize = sizeof(ti);
- ti.lpszText = TranslateT("No status message");
- ti.hinst = g_plugin.getInst();
- ti.hwnd = m_hwnd;
- ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_TRANSPARENT;
- ti.uId = (UINT_PTR)m_hwnd;
- SendMessage(m_hwndTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
-
- SetWindowPos(m_hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// checks generic hotkeys valid for both IM and MUC sessions
-//
-// returns 1 for handled hotkeys, 0 otherwise.
-
-bool CMsgDialog::DM_GenericHotkeysCheck(MSG *message)
-{
- LRESULT mim_hotkey_check = Hotkey_Check(message, TABSRMM_HK_SECTION_GENERIC);
-
- switch (mim_hotkey_check) {
- case TABSRMM_HK_PASTEANDSEND:
- HandlePasteAndSend();
- return true;
-
- case TABSRMM_HK_HISTORY:
- m_btnHistory.Click();
- return true;
-
- case TABSRMM_HK_CONTAINEROPTIONS:
- m_pContainer->OptionsDialog();
- return true;
-
- case TABSRMM_HK_TOGGLEINFOPANEL:
- m_pPanel.setActive(!m_pPanel.isActive());
- m_pPanel.showHide();
- return true;
-
- case TABSRMM_HK_TOGGLETOOLBAR:
- SendMessage(m_hwnd, WM_COMMAND, IDC_TOGGLETOOLBAR, 0);
- return true;
-
- case TABSRMM_HK_CLEARLOG:
- tabClearLog();
- return true;
-
- case TABSRMM_HK_TOGGLESIDEBAR:
- if (m_pContainer->m_pSideBar->isActive())
- SendMessage(m_hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
- return true;
-
- case TABSRMM_HK_CLOSE_OTHER:
- CloseOtherTabs(m_pContainer->m_hwndTabs, *this);
- return true;
- }
- return false;
-}
-
-LRESULT CMsgDialog::DM_MsgWindowCmdHandler(UINT cmd, WPARAM wParam, LPARAM lParam)
-{
- RECT rc;
- int iSelection;
- HMENU submenu;
-
- switch (cmd) {
- case IDC_SRMM_BOLD:
- case IDC_SRMM_ITALICS:
- case IDC_SRMM_UNDERLINE:
- case IDC_FONTSTRIKEOUT:
- if (m_SendFormat != 0) { // dont use formatting if disabled
- CHARFORMAT2 cf, cfOld;
- memset(&cf, 0, sizeof(CHARFORMAT2));
- memset(&cfOld, 0, sizeof(CHARFORMAT2));
- cfOld.cbSize = cf.cbSize = sizeof(CHARFORMAT2);
- cfOld.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT;
- m_message.SendMsg(EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
- BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
- BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
- BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
- BOOL isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT);
-
- int ctrlId = LOWORD(wParam);
- if (ctrlId == IDC_SRMM_BOLD && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_SRMM_BOLD)))
- break;
- if (ctrlId == IDC_SRMM_ITALICS && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_SRMM_ITALICS)))
- break;
- if (ctrlId == IDC_SRMM_UNDERLINE && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_SRMM_UNDERLINE)))
- break;
- if (ctrlId == IDC_FONTSTRIKEOUT && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_FONTSTRIKEOUT)))
- break;
- if (ctrlId == IDC_SRMM_BOLD) {
- cf.dwEffects = isBold ? 0 : CFE_BOLD;
- cf.dwMask = CFM_BOLD;
- CheckDlgButton(m_hwnd, IDC_SRMM_BOLD, !isBold ? BST_CHECKED : BST_UNCHECKED);
- }
- else if (ctrlId == IDC_SRMM_ITALICS) {
- cf.dwEffects = isItalic ? 0 : CFE_ITALIC;
- cf.dwMask = CFM_ITALIC;
- CheckDlgButton(m_hwnd, IDC_SRMM_ITALICS, !isItalic ? BST_CHECKED : BST_UNCHECKED);
- }
- else if (ctrlId == IDC_SRMM_UNDERLINE) {
- cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE;
- cf.dwMask = CFM_UNDERLINE;
- CheckDlgButton(m_hwnd, IDC_SRMM_UNDERLINE, !isUnderline ? BST_CHECKED : BST_UNCHECKED);
- }
- else if (ctrlId == IDC_FONTSTRIKEOUT) {
- cf.dwEffects = isStrikeout ? 0 : CFM_STRIKEOUT;
- cf.dwMask = CFM_STRIKEOUT;
- CheckDlgButton(m_hwnd, IDC_FONTSTRIKEOUT, !isStrikeout ? BST_CHECKED : BST_UNCHECKED);
- }
- m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
- }
- break;
-
- case IDCANCEL:
- ShowWindow(m_pContainer->m_hwnd, SW_MINIMIZE);
- return FALSE;
-
- case IDC_CLOSE:
- PostMessage(m_hwnd, WM_CLOSE, 1, 0);
- break;
-
- case IDC_NAME:
- if (GetKeyState(VK_SHIFT) & 0x8000) // copy UIN
- Utils_ClipboardCopy(m_cache->getUIN());
- else
- CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)(m_cache->getActiveContact()), 0);
- break;
-
- case IDC_TIME:
- submenu = GetSubMenu(PluginConfig.g_hMenuContext, 2);
- MsgWindowUpdateMenu(submenu, MENU_LOGMENU);
-
- GetWindowRect(GetDlgItem(m_hwnd, IDC_TIME), &rc);
-
- iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
- return MsgWindowMenuHandler(iSelection, MENU_LOGMENU);
-
- case IDC_PROTOMENU:
- submenu = GetSubMenu(PluginConfig.g_hMenuContext, 4);
- {
- bool iOldGlobalSendFormat = g_plugin.bSendFormat;
- int iLocalFormat = M.GetDword(m_hContact, "sendformat", 0);
- int iNewLocalFormat = iLocalFormat;
-
- GetWindowRect(GetDlgItem(m_hwnd, IDC_PROTOCOL), &rc);
-
- CheckMenuItem(submenu, ID_MODE_GLOBAL, !m_bSplitterOverride ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_MODE_PRIVATE, m_bSplitterOverride ? MF_CHECKED : MF_UNCHECKED);
-
- // formatting menu..
- CheckMenuItem(submenu, ID_GLOBAL_BBCODE, (g_plugin.bSendFormat) ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_GLOBAL_OFF, (g_plugin.bSendFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED);
-
- CheckMenuItem(submenu, ID_THISCONTACT_GLOBALSETTING, (iLocalFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_THISCONTACT_BBCODE, (iLocalFormat > 0) ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_THISCONTACT_OFF, (iLocalFormat == -1) ? MF_CHECKED : MF_UNCHECKED);
-
- iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
- switch (iSelection) {
- case ID_MODE_GLOBAL:
- m_bSplitterOverride = false;
- db_set_b(m_hContact, SRMSGMOD_T, "splitoverride", 0);
- LoadSplitter();
- AdjustBottomAvatarDisplay();
- DM_RecalcPictureSize();
- Resize();
- break;
-
- case ID_MODE_PRIVATE:
- m_bSplitterOverride = true;
- db_set_b(m_hContact, SRMSGMOD_T, "splitoverride", 1);
- LoadSplitter();
- AdjustBottomAvatarDisplay();
- DM_RecalcPictureSize();
- Resize();
- break;
-
- case ID_GLOBAL_BBCODE:
- g_plugin.bSendFormat = SENDFORMAT_BBCODE;
- break;
-
- case ID_GLOBAL_OFF:
- g_plugin.bSendFormat = SENDFORMAT_NONE;
- break;
-
- case ID_THISCONTACT_GLOBALSETTING:
- iNewLocalFormat = 0;
- break;
-
- case ID_THISCONTACT_BBCODE:
- iNewLocalFormat = SENDFORMAT_BBCODE;
- break;
-
- case ID_THISCONTACT_OFF:
- iNewLocalFormat = -1;
- break;
- }
-
- if (iNewLocalFormat == 0)
- db_unset(m_hContact, SRMSGMOD_T, "sendformat");
- else if (iNewLocalFormat != iLocalFormat)
- db_set_dw(m_hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat);
-
- if (iNewLocalFormat != iLocalFormat || g_plugin.bSendFormat != iOldGlobalSendFormat) {
- m_SendFormat = M.GetDword(m_hContact, "sendformat", g_plugin.bSendFormat);
- if (m_SendFormat == -1) // per contact override to disable it..
- m_SendFormat = 0;
- Srmm_Broadcast(DM_CONFIGURETOOLBAR, 0, 1);
- }
- }
- break;
-
- case IDC_TOGGLETOOLBAR:
- if (lParam == 1)
- m_pContainer->cfg.flags.m_bNoMenuBar = !m_pContainer->cfg.flags.m_bNoMenuBar;
- else
- m_pContainer->cfg.flags.m_bHideToolbar = !m_pContainer->cfg.flags.m_bHideToolbar;
- m_pContainer->ApplySetting(true);
- break;
-
- case IDC_SENDMENU:
- submenu = GetSubMenu(PluginConfig.g_hMenuContext, 3);
-
- GetWindowRect(GetDlgItem(m_hwnd, IDOK), &rc);
- CheckMenuItem(submenu, ID_SENDMENU_SENDTOMULTIPLEUSERS, (m_sendMode & SMODE_MULTIPLE) ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_SENDMENU_SENDDEFAULT, m_sendMode == 0 ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_SENDMENU_SENDTOCONTAINER, (m_sendMode & SMODE_CONTAINER) ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_SENDMENU_SENDLATER, (m_sendMode & SMODE_SENDLATER) ? MF_CHECKED : MF_UNCHECKED);
- CheckMenuItem(submenu, ID_SENDMENU_SENDWITHOUTTIMEOUTS, (m_sendMode & SMODE_NOACK) ? MF_CHECKED : MF_UNCHECKED);
-
- if (lParam)
- iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
- else
- iSelection = HIWORD(wParam);
-
- switch (iSelection) {
- case ID_SENDMENU_SENDTOMULTIPLEUSERS:
- m_sendMode ^= SMODE_MULTIPLE;
- if (m_sendMode & SMODE_MULTIPLE)
- DM_CreateClist();
- else if (IsWindow(GetDlgItem(m_hwnd, IDC_CLIST)))
- DestroyWindow(GetDlgItem(m_hwnd, IDC_CLIST));
- break;
- case ID_SENDMENU_SENDDEFAULT:
- m_sendMode = 0;
- break;
- case ID_SENDMENU_SENDTOCONTAINER:
- m_sendMode ^= SMODE_CONTAINER;
- RedrawWindow(m_hwnd, nullptr, nullptr, RDW_ERASENOW | RDW_UPDATENOW);
- break;
- case ID_SENDMENU_SENDLATER:
- if (SendLater::Avail)
- m_sendMode ^= SMODE_SENDLATER;
- else
- CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK | MB_ICONINFORMATION);
- break;
- case ID_SENDMENU_SENDWITHOUTTIMEOUTS:
- m_sendMode ^= SMODE_NOACK;
- if (m_sendMode & SMODE_NOACK)
- db_set_b(m_hContact, SRMSGMOD_T, "no_ack", 1);
- else
- db_unset(m_hContact, SRMSGMOD_T, "no_ack");
- break;
- }
- db_set_b(m_hContact, SRMSGMOD_T, "no_ack", (uint8_t)(m_sendMode & SMODE_NOACK ? 1 : 0));
- SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
- if (m_sendMode & SMODE_MULTIPLE || m_sendMode & SMODE_CONTAINER) {
- SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOZORDER |
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
- RedrawWindow(m_hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN);
- }
- else {
- if (IsWindow(GetDlgItem(m_hwnd, IDC_CLIST)))
- DestroyWindow(GetDlgItem(m_hwnd, IDC_CLIST));
- SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOZORDER |
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
- RedrawWindow(m_hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN);
- }
- m_pContainer->QueryClientArea(rc);
- Resize();
- DM_ScrollToBottom(1, 1);
- Utils::showDlgControl(m_hwnd, IDC_MULTISPLITTER, (m_sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
- Utils::showDlgControl(m_hwnd, IDC_CLIST, (m_sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
- break;
-
- case IDC_TOGGLESIDEBAR:
- SendMessage(m_pContainer->m_hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
- break;
-
- case IDC_PIC:
- GetClientRect(m_hwnd, &rc);
-
- m_bEditNotesActive = !m_bEditNotesActive;
- if (m_bEditNotesActive) {
- int iLen = GetWindowTextLength(m_message.GetHwnd());
- if (iLen != 0) {
- ActivateTooltip(IDC_SRMM_MESSAGE, TranslateT("You cannot edit user notes when there are unsent messages"));
- m_bEditNotesActive = false;
- break;
- }
-
- if (!m_bIsAutosizingInput) {
- m_iSplitterSaved = m_iSplitterY;
- m_iSplitterY = rc.bottom / 2;
- SendMessage(m_hwnd, WM_SIZE, 1, 1);
- }
-
- ptrW wszText(db_get_wsa(m_hContact, "UserInfo", "MyNotes"));
- if (wszText != nullptr)
- m_message.SetText(wszText);
- }
- else {
- ptrW buf(m_message.GetText());
- db_set_ws(m_hContact, "UserInfo", "MyNotes", buf);
- m_message.SetText(L"");
-
- if (!m_bIsAutosizingInput) {
- m_iSplitterY = m_iSplitterSaved;
- Resize();
- DM_ScrollToBottom(0, 1);
- }
- }
- SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOZORDER |
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
- RedrawWindow(m_hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN);
-
- if (m_bEditNotesActive)
- CWarning::show(CWarning::WARN_EDITUSERNOTES, MB_OK | MB_ICONINFORMATION);
- break;
-
- case IDM_CLEAR:
- tabClearLog();
- break;
-
- case IDC_PROTOCOL:
- submenu = Menu_BuildContactMenu(m_hContact);
- if (lParam == 0)
- GetWindowRect(GetDlgItem(m_hwnd, IDC_PROTOCOL), &rc);
- else
- GetWindowRect((HWND)lParam, &rc);
-
- iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
- if (iSelection)
- Clist_MenuProcessCommand(LOWORD(iSelection), MPCF_CONTACTMENU, m_hContact);
-
- DestroyMenu(submenu);
- break;
-
- // error control
- case IDC_CANCELSEND:
- DM_ErrorDetected(MSGERROR_CANCEL, 0);
- break;
-
- case IDC_RETRY:
- DM_ErrorDetected(MSGERROR_RETRY, 0);
- break;
-
- case IDC_MSGSENDLATER:
- DM_ErrorDetected(MSGERROR_SENDLATER, 0);
- break;
-
- case IDC_SELFTYPING:
- if (AllowTyping()) {
- int iCurrentTypingMode = g_plugin.getByte(m_hContact, SRMSGSET_TYPING, g_plugin.bTypingNew);
- if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON && iCurrentTypingMode) {
- DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
- m_nTypeMode = PROTOTYPE_SELFTYPING_OFF;
- }
- g_plugin.setByte(m_hContact, SRMSGSET_TYPING, (uint8_t)!iCurrentTypingMode);
- }
- break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// initialize rich edit control (log and edit control) for both MUC and
-// standard IM session windows.
-
-void CMsgDialog::DM_InitRichEdit()
-{
- char *szStreamOut = nullptr;
- if (!isChat() && GetWindowTextLength(m_message.GetHwnd()) > 0)
- szStreamOut = m_message.GetRichTextRtf();
- SetWindowText(m_message.GetHwnd(), L"");
-
- m_pLog->UpdateOptions();
-
- m_message.SendMsg(EM_SETBKGNDCOLOR, 0, m_pContainer->m_theme.inputbg);
-
- CHARFORMAT2 cf2 = {};
- cf2.cbSize = sizeof(cf2);
-
- if (isChat()) {
- LOGFONTW lf;
- COLORREF inputcharcolor;
- LoadMsgDlgFont(FONTSECTION_IM, MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor);
-
- cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR;
- cf2.crTextColor = inputcharcolor;
- cf2.bCharSet = lf.lfCharSet;
- cf2.crBackColor = m_pContainer->m_theme.inputbg;
- wcsncpy_s(cf2.szFaceName, lf.lfFaceName, _TRUNCATE);
- cf2.dwEffects = 0;
- cf2.wWeight = (uint16_t)lf.lfWeight;
- cf2.bPitchAndFamily = lf.lfPitchAndFamily;
- cf2.yHeight = abs(lf.lfHeight) * 15;
- }
- else {
- LOGFONTW lf = m_pContainer->m_theme.logFonts[MSGFONTID_MESSAGEAREA];
- COLORREF inputcharcolor = m_pContainer->m_theme.fontColors[MSGFONTID_MESSAGEAREA];
-
- for (auto &it : Utils::rtf_clrs)
- if (it->clr == inputcharcolor)
- inputcharcolor = RGB(GetRValue(inputcharcolor), GetGValue(inputcharcolor), GetBValue(inputcharcolor) == 0 ? GetBValue(inputcharcolor) + 1 : GetBValue(inputcharcolor) - 1);
-
- cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC;
- cf2.crTextColor = inputcharcolor;
- cf2.bCharSet = lf.lfCharSet;
- wcsncpy_s(cf2.szFaceName, lf.lfFaceName, _TRUNCATE);
- cf2.dwEffects = ((lf.lfWeight >= FW_BOLD) ? CFE_BOLD : 0) | (lf.lfItalic ? CFE_ITALIC : 0) | (lf.lfUnderline ? CFE_UNDERLINE : 0) | (lf.lfStrikeOut ? CFE_STRIKEOUT : 0);
- cf2.wWeight = (uint16_t)lf.lfWeight;
- cf2.bPitchAndFamily = lf.lfPitchAndFamily;
- cf2.yHeight = abs(lf.lfHeight) * 15;
- }
- m_message.SendMsg(EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
- m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); /* WINE: fix send colour text. */
- m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); /* WINE: fix send colour text. */
-
- // setup the rich edit control(s)
- // LOG is always set to RTL, because this is needed for proper bidirectional operation later.
- // The real text direction is then enforced by the streaming code which adds appropiate paragraph
- // and textflow formatting commands to the
- PARAFORMAT2 pf2;
- memset(&pf2, 0, sizeof(PARAFORMAT2));
- pf2.cbSize = sizeof(pf2);
- pf2.wEffects = PFE_RTLPARA;
- pf2.dwMask = PFM_RTLPARA;
- if (FindRTLLocale())
- m_message.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
- if (!(m_dwFlags & MWF_LOG_RTL)) {
- pf2.wEffects = 0;
- m_message.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
- }
- m_message.SendMsg(EM_SETLANGOPTIONS, 0, (LPARAM)m_message.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
-
- if (m_dwFlags & MWF_LOG_RTL)
- SetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
- else
- SetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE) & ~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
-
- if (szStreamOut != nullptr) {
- SETTEXTEX stx = { ST_DEFAULT, CP_UTF8 };
- m_message.SendMsg(EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut);
- mir_free(szStreamOut);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// set the states of defined database action buttons(only if button is a toggle)
-
-void CMsgDialog::DM_SetDBButtonStates()
-{
- ButtonItem *buttonItem = m_pContainer->m_buttonItems;
- MCONTACT hFinalContact = 0;
- HWND hwndContainer = m_pContainer->m_hwnd;
-
- while (buttonItem) {
- HWND hWnd = GetDlgItem(hwndContainer, buttonItem->uId);
-
- if (buttonItem->pfnCallback)
- buttonItem->pfnCallback(buttonItem, m_hwnd, this, hWnd);
-
- if (!(buttonItem->dwFlags & BUTTON_ISTOGGLE && buttonItem->dwFlags & BUTTON_ISDBACTION)) {
- buttonItem = buttonItem->nextItem;
- continue;
- }
-
- BOOL result = FALSE;
- char *szModule = buttonItem->szModule;
- char *szSetting = buttonItem->szSetting;
- if (buttonItem->dwFlags & BUTTON_DBACTIONONCONTACT || buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) {
- if (buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION)
- szModule = Proto_GetBaseAccountName(m_hContact);
- hFinalContact = m_hContact;
- }
- else hFinalContact = 0;
-
- switch (buttonItem->type) {
- case DBVT_BYTE:
- result = (db_get_b(hFinalContact, szModule, szSetting, 0) == buttonItem->bValuePush[0]);
- break;
- case DBVT_WORD:
- result = (db_get_w(hFinalContact, szModule, szSetting, 0) == *((uint16_t *)&buttonItem->bValuePush));
- break;
- case DBVT_DWORD:
- result = (db_get_dw(hFinalContact, szModule, szSetting, 0) == *((uint32_t *)&buttonItem->bValuePush));
- break;
- case DBVT_ASCIIZ:
- ptrA szValue(db_get_sa(hFinalContact, szModule, szSetting));
- if (szValue)
- result = !mir_strcmp((char*)buttonItem->bValuePush, szValue);
- break;
- }
- SendMessage(hWnd, BM_SETCHECK, result, 0);
- buttonItem = buttonItem->nextItem;
- }
-}
-
-void CMsgDialog::DM_ScrollToBottom(WPARAM wParam, LPARAM lParam)
-{
- if (m_bScrollingDisabled)
- return;
-
- if (IsIconic(m_pContainer->m_hwnd))
- m_bDeferredScroll = true;
-
- if (m_iLogMode == WANT_BUILTIN_LOG)
- ((CLogWindow *)m_pLog)->ScrollToBottom(wParam != 0, lParam != 0);
- else
- m_pLog->ScrollToBottom();
-}
-
-void CMsgDialog::DM_RecalcPictureSize()
-{
- HBITMAP hbm = ((m_pPanel.isActive()) && m_pContainer->cfg.avatarMode != 3) ? m_hOwnPic : (m_ace ? m_ace->hbmPic : PluginConfig.g_hbmUnknown);
- if (hbm) {
- BITMAP bminfo;
- GetObject(hbm, sizeof(bminfo), &bminfo);
- CalcDynamicAvatarSize(&bminfo);
- Resize();
- }
- else m_pic.cy = m_pic.cx = 60;
-}
-
-void CMsgDialog::DM_UpdateLastMessage() const
-{
- if (m_pContainer->m_hwndStatus == nullptr || m_pContainer->m_hwndActive != m_hwnd)
- return;
-
- wchar_t szBuf[100];
- if (m_bShowTyping) {
- SendMessage(m_pContainer->m_hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
- mir_snwprintf(szBuf, TranslateT("%s is typing a message..."), m_cache->getNick());
- }
- else if (m_bStatusSet) {
- SendMessage(m_pContainer->m_hwndStatus, SB_SETICON, 0, (LPARAM)m_szStatusIcon);
- SendMessage(m_pContainer->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)m_szStatusText.c_str());
- return;
- }
- else {
- SendMessage(m_pContainer->m_hwndStatus, SB_SETICON, 0, 0);
-
- if (m_pContainer->cfg.flags.m_bUinStatusBar)
- mir_snwprintf(szBuf, L"UID: %s", m_cache->getUIN());
- else if (m_lastMessage) {
- wchar_t date[64], time[64];
- TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"d", date, _countof(date), 0);
- if (m_pContainer->cfg.flags.m_bUinStatusBar && mir_wstrlen(date) > 6)
- date[mir_wstrlen(date) - 5] = 0;
- TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"t", time, _countof(time), 0);
- mir_snwprintf(szBuf, TranslateT("Last received: %s at %s"), date, time);
- }
- else szBuf[0] = 0;
- }
-
- SendMessage(m_pContainer->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// create embedded contact list control
-
-HWND CMsgDialog::DM_CreateClist()
-{
- if (!SendLater::Avail) {
- CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK | MB_ICONINFORMATION);
- m_sendMode &= ~SMODE_MULTIPLE;
- return nullptr;
- }
-
- HWND hwndClist = CreateWindowExA(0, "CListControl", "", WS_TABSTOP | WS_VISIBLE | WS_CHILD | 0x248, 184, 0, 30, 30, m_hwnd, (HMENU)IDC_CLIST, g_plugin.getInst(), nullptr);
- SendMessage(hwndClist, WM_TIMER, 14, 0);
- HANDLE hItem = (HANDLE)SendMessage(hwndClist, CLM_FINDCONTACT, m_hContact, 0);
-
- SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) & ~CLS_EX_TRACKSELECT);
- SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) | (CLS_EX_NOSMOOTHSCROLLING | CLS_EX_NOTRANSLUCENTSEL));
-
- if (!g_plugin.bAllowOfflineMultisend)
- SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) | CLS_HIDEOFFLINE);
-
- if (hItem)
- SendMessage(hwndClist, CLM_SETCHECKMARK, (WPARAM)hItem, 1);
-
- SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, Clist::HideEmptyGroups, 0);
- SendMessage(hwndClist, CLM_SETUSEGROUPS, Clist::UseGroups, 0);
- SendMessage(hwndClist, CLM_FIRST + 106, 0, 1);
- SendMessage(hwndClist, CLM_AUTOREBUILD, 0, 0);
- if (hwndClist)
- RedrawWindow(hwndClist, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
- return hwndClist;
-}
-
-LRESULT CMsgDialog::DM_MouseWheelHandler(WPARAM wParam, LPARAM lParam)
-{
- POINT pt;
- GetCursorPos(&pt);
-
- RECT rc;
- GetWindowRect(m_message.GetHwnd(), &rc);
- if (PtInRect(&rc, pt))
- return 1;
-
- if (isChat()) { // scroll nick list by just hovering it
- RECT rcNicklist;
- GetWindowRect(m_nickList.GetHwnd(), &rcNicklist);
- if (PtInRect(&rcNicklist, pt)) {
- m_nickList.SendMsg(WM_MOUSEWHEEL, wParam, lParam);
- return 0;
- }
- }
-
- GetWindowRect(m_pLog->GetHwnd(), &rc);
- if (PtInRect(&rc, pt)) {
- short wDirection = (short)HIWORD(wParam);
-
- if (LOWORD(wParam) & MK_SHIFT || M.GetByte("fastscroll", 0)) {
- if (wDirection < 0)
- SendMessage(m_pLog->GetHwnd(), WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0);
- else if (wDirection > 0)
- SendMessage(m_pLog->GetHwnd(), WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0);
- }
- else SendMessage(m_pLog->GetHwnd(), WM_MOUSEWHEEL, wParam, lParam);
- return 0;
- }
-
- if (GetTabItemFromMouse(m_pContainer->m_hwndTabs, &pt) != -1) {
- SendMessage(m_pContainer->m_hwndTabs, WM_MOUSEWHEEL, wParam, -1);
- return 0;
- }
- return 1;
-}
-
-void CMsgDialog::DM_FreeTheme()
-{
- if (m_hTheme) {
- CloseThemeData(m_hTheme);
- m_hTheme = nullptr;
- }
- if (m_hThemeIP) {
- CloseThemeData(m_hThemeIP);
- m_hThemeIP = nullptr;
- }
- if (m_hThemeToolbar) {
- CloseThemeData(m_hThemeToolbar);
- m_hThemeToolbar = nullptr;
- }
-}
-
-void CMsgDialog::DM_ThemeChanged()
-{
- CSkinItem *item_log = &SkinItems[ID_EXTBKHISTORY];
- CSkinItem *item_msg = &SkinItems[ID_EXTBKINPUTAREA];
-
- m_hTheme = OpenThemeData(m_hwnd, L"EDIT");
-
- if (m_hTheme != nullptr || (CSkin::m_skinEnabled && !item_log->IGNORED)) {
- if (m_iLogMode == WANT_BUILTIN_LOG)
- LOG()->DisableStaticEdge();
-
- if (isChat())
- SetWindowLongPtr(m_nickList.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_nickList.GetHwnd(), GWL_EXSTYLE) & ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
- }
-
- if (m_hTheme != nullptr || (CSkin::m_skinEnabled && !item_msg->IGNORED))
- SetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
-
- m_hThemeIP = M.isAero() ? OpenThemeData(m_hwnd, L"ButtonStyle") : nullptr;
- m_hThemeToolbar = (M.isAero() || (!CSkin::m_skinEnabled && M.isVSThemed())) ? OpenThemeData(m_hwnd, L"REBAR") : nullptr;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// send out message typing notifications (MTN) when the
-// user is typing/editing text in the message input area.
-
-void CMsgDialog::DM_NotifyTyping(int mode)
-{
- const char *szProto = m_cache->getActiveProto();
- MCONTACT hContact = m_cache->getActiveContact();
-
- // editing user notes or preparing a message for queued delivery -> don't send MTN
- if (m_bEditNotesActive || (m_sendMode & SMODE_SENDLATER))
- return;
-
- // allow supression of sending out TN for the contact (NOTE: for metacontacts, do NOT use the subcontact handle)
- if (!g_plugin.getByte(hContact, SRMSGSET_TYPING, g_plugin.bTypingNew))
- return;
-
- if (szProto == nullptr) // should not, but who knows...
- return;
-
- // check status and capabilities of the protocol
- uint32_t typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0);
- if (!(typeCaps & PF4_SUPPORTTYPING))
- return;
-
- if (isChat()) {
- m_nTypeMode = mode;
- Chat_DoEventHook(m_si, GC_USER_TYPNOTIFY, 0, 0, m_nTypeMode);
- }
- else {
- uint32_t protoStatus = Proto_GetStatus(szProto);
- if (protoStatus < ID_STATUS_ONLINE)
- return;
-
- // check visibility/invisibility lists to not "accidentially" send MTN to contacts who
- // should not see them (privacy issue)
- uint32_t protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
- if (protoCaps & PF1_VISLIST && db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
- return;
-
- if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(hContact, szProto, "ApparentMode", 0) != ID_STATUS_ONLINE)
- return;
-
- // don't send to contacts which are not permanently added to the contact list,
- // unless the option to ignore added status is set.
- if (!Contact::OnList(m_hContact) && !g_plugin.bTypingUnknown)
- return;
-
- // End user check
- m_nTypeMode = mode;
- CallService(MS_PROTO_SELFISTYPING, hContact, m_nTypeMode);
- }
-}
-
-void CMsgDialog::DM_OptionsApplied(bool bRemakeLog)
-{
- m_szMicroLf[0] = 0;
- if (!m_pContainer->m_theme.isPrivate) {
- m_pContainer->LoadThemeDefaults();
- m_dwFlags = m_pContainer->m_theme.dwFlags;
- }
-
- LoadLocalFlags();
- m_hTimeZone = TimeZone_CreateByContact(m_hContact, nullptr, TZF_KNOWNONLY);
-
- m_bShowUIElements = (m_pContainer->cfg.flags.m_bHideToolbar) == 0;
- m_bSplitterOverride = M.GetByte(m_hContact, "splitoverride", 0) != 0;
- m_pPanel.getVisibility();
-
- // small inner margins (padding) for the text areas
- m_message.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
-
- GetSendFormat();
- SetDialogToType();
- SendMessage(m_hwnd, DM_CONFIGURETOOLBAR, 0, 0);
-
- DM_InitRichEdit();
- if (m_hwnd == m_pContainer->m_hwndActive)
- SendMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 0);
- InvalidateRect(m_message.GetHwnd(), nullptr, FALSE);
- if (bRemakeLog) {
- if (IsIconic(m_pContainer->m_hwnd))
- m_bDeferredRemakeLog = true;
- else if (isChat())
- RedrawLog();
- else
- RemakeLog();
- }
-
- ShowWindow(m_hwndPanelPicParent, SW_SHOW);
- EnableWindow(m_hwndPanelPicParent, TRUE);
-
- UpdateWindowIcon();
-}
-
-void CMsgDialog::DM_Typing(bool fForceOff)
-{
- HWND hwndContainer = m_pContainer->m_hwnd;
- HWND hwndStatus = m_pContainer->m_hwndStatus;
-
- if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - m_nLastTyping > TIMEOUT_TYPEOFF)
- DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
-
- if (m_bShowTyping == 1) {
- if (m_nTypeSecs > 0) {
- m_nTypeSecs--;
- if (GetForegroundWindow() == hwndContainer)
- UpdateWindowIcon();
- }
- else {
- if (!fForceOff) {
- m_bShowTyping = 2;
- m_nTypeSecs = 86400;
-
- if (!isChat())
- mir_snwprintf(m_wszStatusBar, TranslateT("%s has entered text."), m_cache->getNick());
-
- if (hwndStatus && m_pContainer->m_hwndActive == m_hwnd)
- SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)m_wszStatusBar);
- }
- UpdateWindowIcon();
- HandleIconFeedback(this, (HICON)-1);
- CMsgDialog *dat_active = (CMsgDialog*)GetWindowLongPtr(m_pContainer->m_hwndActive, GWLP_USERDATA);
- if (dat_active && !dat_active->isChat())
- m_pContainer->UpdateTitle(0);
- else
- m_pContainer->UpdateTitle(0, dat_active);
- if (!m_pContainer->cfg.flags.m_bNoFlash && PluginConfig.m_FlashOnMTN)
- m_pContainer->ReflashContainer();
- }
- }
- else if (m_bShowTyping == 2) {
- if (m_nTypeSecs > 0)
- m_nTypeSecs--;
- else {
- m_wszStatusBar[0] = 0;
- m_bShowTyping = 0;
- }
- tabUpdateStatusBar();
- }
- else if (m_nTypeSecs > 0) {
- mir_snwprintf(m_wszStatusBar, TranslateT("%s is typing a message"),
- (m_pUserTyping) ? m_pUserTyping->pszNick : m_cache->getNick());
-
- m_nTypeSecs--;
- if (hwndStatus && m_pContainer->m_hwndActive == m_hwnd) {
- SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)m_wszStatusBar);
- SendMessage(hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
- }
- if (IsIconic(hwndContainer) || !IsActive()) {
- SetWindowText(hwndContainer, m_wszStatusBar);
- m_pContainer->cfg.flags.m_bNeedsUpdateTitle = true;
- if (!m_pContainer->cfg.flags.m_bNoFlash && PluginConfig.m_FlashOnMTN)
- m_pContainer->ReflashContainer();
- }
-
- if (m_pContainer->m_hwndActive != m_hwnd) {
- if (m_bCanFlashTab)
- m_iFlashIcon = PluginConfig.g_IconTypingEvent;
- HandleIconFeedback(this, PluginConfig.g_IconTypingEvent);
- }
- else { // active tab may show icon if status bar is disabled
- if (!hwndStatus) {
- if (TabCtrl_GetItemCount(m_hwndParent) > 1 || !m_pContainer->cfg.flags.m_bHideTabs)
- HandleIconFeedback(this, PluginConfig.g_IconTypingEvent);
- }
- }
- if ((GetForegroundWindow() != hwndContainer) || (m_pContainer->m_hwndStatus == nullptr) || (m_pContainer->m_hwndActive != m_hwnd))
- m_pContainer->SetIcon(this, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
-
- m_bShowTyping = 1;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// sync splitter position for all open sessions.
-// This cares about private / per container / MUC <> IM splitter syncing and everything.
-// called from IM and MUC windows via DM_SPLITTERGLOBALEVENT
-
-int CMsgDialog::DM_SplitterGlobalEvent(WPARAM wParam, LPARAM lParam)
-{
- CMsgDialog *srcDat = PluginConfig.lastSPlitterPos.pSrcDat;
- TContainerData *srcCnt = PluginConfig.lastSPlitterPos.pSrcContainer;
- bool fCntGlobal = (!m_pContainer->cfg.fPrivate ? true : false);
-
- if (m_bIsAutosizingInput)
- return 0;
-
- RECT rcWin;
- GetWindowRect(m_hwnd, &rcWin);
-
- LONG newPos;
- if (wParam == 0 && lParam == 0) {
- if (m_bSplitterOverride && this != srcDat)
- return 0;
-
- if (srcDat->isChat() == isChat())
- newPos = PluginConfig.lastSPlitterPos.pos;
- else if (!srcDat->isChat() && isChat())
- newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im;
- else if (srcDat->isChat() && !isChat())
- newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im;
- else
- newPos = 0;
-
- if (this == srcDat) {
- m_pContainer->cfg.iSplitterY = m_iSplitterY;
- if (fCntGlobal)
- SaveSplitter();
- return 0;
- }
-
- if (!fCntGlobal && m_pContainer != srcCnt)
- return 0;
- if (srcCnt->cfg.fPrivate && m_pContainer != srcCnt)
- return 0;
-
- // for inactive sessions, delay the splitter repositioning until they become
- // active (faster, avoid redraw/resize problems for minimized windows)
- if (IsIconic(m_pContainer->m_hwnd) || m_pContainer->m_hwndActive != m_hwnd) {
- m_bDelayedSplitter = true;
- m_wParam = newPos;
- m_lParam = PluginConfig.lastSPlitterPos.lParam;
- return 0;
- }
- }
- else newPos = wParam;
-
- LoadSplitter();
- AdjustBottomAvatarDisplay();
- DM_RecalcPictureSize();
- Resize();
- DM_ScrollToBottom(1, 1);
- if (this != srcDat)
- UpdateToolbarBG();
- return 0;
-}
-
-void CMsgDialog::DM_AddDivider()
-{
- if (!m_bDividerSet && g_plugin.bUseDividers)
- if (GetWindowTextLength(m_pLog->GetHwnd()) > 0)
- m_bDividerSet = m_bDividerWanted = true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// incoming event handler
-
-void CMsgDialog::DM_EventAdded(WPARAM, LPARAM lParam)
-{
- MEVENT hDbEvent = (MEVENT)lParam;
-
- DBEVENTINFO dbei = {};
- db_event_get(hDbEvent, &dbei);
- if (m_hDbEventFirst == 0)
- m_hDbEventFirst = hDbEvent;
-
- bool bIsStatusChangeEvent = IsStatusEvent(dbei.eventType);
- bool bDisableNotify = (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ));
-
- if (!DbEventIsShown(&dbei))
- return;
-
- if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) {
- m_lastMessage = dbei.timestamp;
- m_wszStatusBar[0] = 0;
- if (m_bShowTyping) {
- m_nTypeSecs = 0;
- DM_Typing(true);
- m_bShowTyping = 0;
- }
- HandleIconFeedback(this, (HICON)-1);
- if (m_pContainer->m_hwndStatus)
- PostMessage(m_hwnd, DM_UPDATELASTMESSAGE, 0, 0);
- }
-
- // set the message log divider to mark new (maybe unseen) messages, if the container has
- // been minimized or in the background.
- if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) {
- if (g_plugin.bDividersUsePopupConfig && g_plugin.bUseDividers) {
- if (!MessageWindowOpened(m_hContact, nullptr))
- DM_AddDivider();
- }
- else if (g_plugin.bUseDividers) {
- if (!m_pContainer->IsActive())
- DM_AddDivider();
- else if (m_pContainer->m_hwndActive != m_hwnd)
- DM_AddDivider();
- }
-
- if (IsWindowVisible(m_pContainer->m_hwnd))
- m_pContainer->m_bHidden = false;
- }
- m_cache->updateStats(TSessionStats::UPDATE_WITH_LAST_RCV, 0);
-
- if (hDbEvent != m_hDbEventFirst || isChat())
- StreamEvents(hDbEvent, 1, 1);
- else
- RemakeLog();
-
- // handle tab flashing
- if (!bDisableNotify && !bIsStatusChangeEvent)
- if ((TabCtrl_GetCurSel(m_hwndParent) != m_iTabID) && !(dbei.flags & DBEF_SENT)) {
- switch (dbei.eventType) {
- case EVENTTYPE_MESSAGE:
- m_iFlashIcon = PluginConfig.g_IconMsgEvent;
- break;
- case EVENTTYPE_FILE:
- m_iFlashIcon = PluginConfig.g_IconFileEvent;
- break;
- default:
- m_iFlashIcon = PluginConfig.g_IconMsgEvent;
- break;
- }
- timerFlash.Start(TIMEOUT_FLASHWND);
- m_bCanFlashTab = true;
- }
-
- // try to flash the contact list...
- if (!bDisableNotify)
- FlashOnClist(hDbEvent, &dbei);
-
- // autoswitch tab if option is set AND container is minimized (otherwise, we never autoswitch)
- // never switch for status changes...
- if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) {
- if (g_plugin.bAutoSwitchTabs && m_pContainer->m_hwndActive != m_hwnd) {
- if ((IsIconic(m_pContainer->m_hwnd) && !IsZoomed(m_pContainer->m_hwnd)) || (g_plugin.bHideOnClose && !IsWindowVisible(m_pContainer->m_hwnd))) {
- int iItem = GetTabIndexFromHWND(GetParent(m_hwnd), m_hwnd);
- if (iItem >= 0) {
- TabCtrl_SetCurSel(m_hwndParent, iItem);
- ShowWindow(m_pContainer->m_hwndActive, SW_HIDE);
- m_pContainer->m_hwndActive = m_hwnd;
- m_pContainer->UpdateTitle(m_hContact);
- m_pContainer->cfg.flags.m_bDeferredTabSelect = true;
- }
- }
- }
- }
-
- // flash window if it is not focused
- if (!bDisableNotify && !bIsStatusChangeEvent)
- if (!IsActive() && !(dbei.flags & DBEF_SENT)) {
- if (!m_pContainer->cfg.flags.m_bNoFlash && !m_pContainer->IsActive())
- m_pContainer->FlashContainer(1, 0);
- m_pContainer->SetIcon(this, Skin_LoadIcon(SKINICON_EVENT_MESSAGE));
- m_pContainer->cfg.flags.m_bNeedsUpdateTitle = true;
- }
-
- // play a sound
- if (!bDisableNotify && dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT)))
- PlayIncomingSound();
-
- if (m_pWnd)
- m_pWnd->Invalidate();
-}
-
-void CMsgDialog::DM_HandleAutoSizeRequest(REQRESIZE* rr)
-{
- if (rr == nullptr || GetForegroundWindow() != m_pContainer->m_hwnd)
- return;
-
- if (!m_bIsAutosizingInput || m_iInputAreaHeight == -1)
- return;
-
- LONG heightLimit = M.GetDword("autoSplitMinLimit", 0);
- LONG iNewHeight = rr->rc.bottom - rr->rc.top;
-
- if (CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED)
- iNewHeight += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP + SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM - 2);
-
- if (heightLimit && iNewHeight < heightLimit)
- iNewHeight = heightLimit;
-
- if (iNewHeight == m_iInputAreaHeight)
- return;
-
- RECT rc;
- GetClientRect(m_hwnd, &rc);
- LONG cy = rc.bottom - rc.top;
- LONG panelHeight = (m_pPanel.isActive() ? m_pPanel.getHeight() : 0);
-
- if (iNewHeight > (cy - panelHeight) / 2)
- iNewHeight = (cy - panelHeight) / 2;
-
- m_dynaSplitter = iNewHeight - DPISCALEY_S(2);
- if (m_pContainer->cfg.flags.m_bBottomToolbar)
- m_dynaSplitter += DPISCALEY_S(22);
- m_iSplitterY = m_dynaSplitter + DPISCALEY_S(34);
- DM_RecalcPictureSize();
-
- m_iInputAreaHeight = iNewHeight;
- UpdateToolbarBG();
- DM_ScrollToBottom(1, 0);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// status icon stuff (by sje, used for indicating encryption status in the status bar
-// this is now part of the message window api
-
-
-static int OnSrmmIconChanged(WPARAM hContact, LPARAM)
-{
- if (hContact == 0)
- Srmm_Broadcast(DM_STATUSICONCHANGE, 0, 0);
- else {
- HWND hwnd = Srmm_FindWindow(hContact);
- if (hwnd)
- PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0);
- }
- return 0;
-}
-
-void CMsgDialog::DrawStatusIcons(HDC hDC, const RECT &rc, int gap)
-{
- int x = rc.left;
- int y = (rc.top + rc.bottom - PluginConfig.m_smcxicon) >> 1;
-
- SetBkMode(hDC, TRANSPARENT);
-
- int nIcon = 0;
- while (StatusIconData *sid = Srmm_GetNthIcon(m_hContact, nIcon++)) {
- if (!mir_strcmp(sid->szModule, MSG_ICON_MODULE)) {
- if (sid->dwId == MSG_ICON_SOUND) {
- DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_SOUNDS],
- PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
-
- DrawIconEx(hDC, x, y, m_pContainer->cfg.flags.m_bNoSound ?
- PluginConfig.g_iconOverlayDisabled : PluginConfig.g_iconOverlayEnabled,
- PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
- }
- else if (sid->dwId == MSG_ICON_UTN) {
- if (AllowTyping()) {
- DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
-
- DrawIconEx(hDC, x, y, g_plugin.getByte(m_hContact, SRMSGSET_TYPING, g_plugin.bTypingNew) ?
- PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
- }
- else CSkin::DrawDimmedIcon(hDC, x, y, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], 50);
- }
- }
- else {
- HICON hIcon;
- if ((sid->flags & MBF_DISABLED) && sid->hIconDisabled)
- hIcon = sid->hIconDisabled;
- else
- hIcon = sid->hIcon;
-
- if ((sid->flags & MBF_DISABLED) && sid->hIconDisabled == nullptr)
- CSkin::DrawDimmedIcon(hDC, x, y, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, hIcon, 50);
- else
- DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, nullptr, DI_NORMAL);
- }
-
- x += PluginConfig.m_smcxicon + gap;
- }
-}
-
-void CMsgDialog::CheckStatusIconClick(POINT pt, const RECT &rc, int gap, int code)
-{
- if (code == NM_CLICK || code == NM_RCLICK) {
- POINT ptScreen;
- GetCursorPos(&ptScreen);
- if (!PtInRect(&rcLastStatusBarClick, ptScreen))
- return;
- }
-
- UINT iconNum = (pt.x - (rc.left + 0)) / (PluginConfig.m_smcxicon + gap);
-
- StatusIconData *sid = Srmm_GetNthIcon(m_hContact, iconNum);
- if (sid == nullptr)
- return;
-
- if (!mir_strcmp(sid->szModule, MSG_ICON_MODULE)) {
- if (sid->dwId == MSG_ICON_SOUND && code != NM_RCLICK) {
- if (GetKeyState(VK_SHIFT) & 0x8000) {
- for (TContainerData *p = pFirstContainer; p; p = p->pNext) {
- p->cfg.flags.m_bNoSound = m_pContainer->cfg.flags.m_bNoSound;
- InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
- }
- }
- else {
- m_pContainer->cfg.flags.m_bNoSound = !m_pContainer->cfg.flags.m_bNoSound;
- InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
- }
- }
- else if (sid->dwId == MSG_ICON_UTN && code != NM_RCLICK && AllowTyping()) {
- SendMessage(m_pContainer->m_hwndActive, WM_COMMAND, IDC_SELFTYPING, 0);
- InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
- }
- }
- else {
- StatusIconClickData sicd = { sizeof(sicd) };
- GetCursorPos(&sicd.clickLocation);
- sicd.dwId = sid->dwId;
- sicd.szModule = sid->szModule;
- sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0);
- Srmm_ClickStatusIcon(m_hContact, &sicd);
- InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
- }
-}
-
-void CMsgDialog::DM_ErrorDetected(int type, int flag)
-{
- switch (type) {
- case MSGERROR_CANCEL:
- case MSGERROR_SENDLATER:
- if (m_bErrorState) {
- m_cache->saveHistory();
- if (type == MSGERROR_SENDLATER)
- sendQueue->doSendLater(m_iCurrentQueueError, this); // to be implemented at a later time
- m_iOpenJobs--;
- sendQueue->dec();
- if (m_iCurrentQueueError >= 0 && m_iCurrentQueueError < SendQueue::NR_SENDJOBS)
- sendQueue->clearJob(m_iCurrentQueueError);
- m_iCurrentQueueError = -1;
- sendQueue->showErrorControls(this, FALSE);
- if (type != MSGERROR_CANCEL || flag == 0)
- m_message.SetText(L"");
- sendQueue->checkQueue(this);
- int iNextFailed = sendQueue->findNextFailed(this);
- if (iNextFailed >= 0)
- sendQueue->handleError(this, iNextFailed);
- }
- break;
-
- case MSGERROR_RETRY:
- if (m_bErrorState) {
- int resent = 0;
-
- m_cache->saveHistory();
- if (m_iCurrentQueueError >= 0 && m_iCurrentQueueError < SendQueue::NR_SENDJOBS) {
- SendJob *job = sendQueue->getJobByIndex(m_iCurrentQueueError);
- if (job->iSendId == 0 && job->hContact == 0)
- break;
-
- job->iSendId = ProtoChainSend(job->hContact, PSS_MESSAGE, job->dwFlags, (LPARAM)job->szSendBuffer);
- resent++;
- }
-
- if (resent) {
- SendJob *job = sendQueue->getJobByIndex(m_iCurrentQueueError);
-
- SetTimer(m_hwnd, TIMERID_MSGSEND + m_iCurrentQueueError, PluginConfig.m_MsgTimeout, nullptr);
- job->iStatus = SendQueue::SQ_INPROGRESS;
- m_iCurrentQueueError = -1;
- sendQueue->showErrorControls(this, FALSE);
- m_message.SetText(L"");
- sendQueue->checkQueue(this);
-
- int iNextFailed = sendQueue->findNextFailed(this);
- if (iNextFailed >= 0)
- sendQueue->handleError(this, iNextFailed);
- }
- }
- }
-}
-
-int SI_InitStatusIcons()
-{
- StatusIconData sid = {};
- sid.szModule = MSG_ICON_MODULE;
- sid.dwId = MSG_ICON_SOUND; // Sounds
- Srmm_AddIcon(&sid, &g_plugin);
-
- sid.dwId = MSG_ICON_UTN;
- Srmm_AddIcon(&sid, &g_plugin);
-
- HookEvent(ME_MSG_ICONSCHANGED, OnSrmmIconChanged);
- return 0;
-}
+/////////////////////////////////////////////////////////////////////////////////////////
+// Miranda NG: the free IM client for Microsoft* Windows*
+//
+// Copyright (C) 2012-23 Miranda NG team,
+// Copyright (c) 2000-09 Miranda ICQ/IM project,
+// all portions of this codebase are copyrighted to the people
+// listed in contributors.txt.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// you should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// part of tabSRMM messaging plugin for Miranda.
+//
+// (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+//
+// these are generic message handlers which are used by the message dialog window procedure.
+// calling them directly instead of using SendMessage() is faster.
+// also contains various callback functions for custom buttons
+
+#include "stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Save message log for given session as RTF document
+
+/*
+void CMsgDialog::DM_SaveLogAsRTF() const
+{
+ if (m_hwndIEView != nullptr) {
+ IEVIEWEVENT event = { sizeof(event) };
+ event.hwnd = m_hwndIEView;
+ event.hContact = m_hContact;
+ event.iType = IEE_SAVE_DOCUMENT;
+ CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event);
+ }
+ else {
+ wchar_t szFilter[MAX_PATH], szFilename[MAX_PATH];
+ mir_snwprintf(szFilter, L"%s%c*.rtf%c%c", TranslateT("Rich Edit file"), 0, 0, 0);
+ mir_snwprintf(szFilename, L"%s.rtf", m_cache->getNick());
+
+ Utils::sanitizeFilename(szFilename);
+
+ wchar_t szInitialDir[MAX_PATH + 2];
+ mir_snwprintf(szInitialDir, L"%s%s\\", M.getDataPath(), L"\\Saved message logs");
+ CreateDirectoryTreeW(szInitialDir);
+
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = m_hwnd;
+ ofn.lpstrFile = szFilename;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrInitialDir = szInitialDir;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY;
+ ofn.lpstrDefExt = L"rtf";
+ if (GetSaveFileName(&ofn)) {
+ EDITSTREAM stream = { 0 };
+ stream.dwCookie = (DWORD_PTR)szFilename;
+ stream.dwError = 0;
+ stream.pfnCallback = Utils::StreamOut;
+ m_rtf.SendMsg(EM_STREAMOUT, SF_RTF | SF_USECODEPAGE, (LPARAM)&stream);
+ }
+ }
+}
+*/
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// checks if the balloon tooltip can be dismissed (usually called by WM_MOUSEMOVE events)
+
+void CMsgDialog::DM_DismissTip(const POINT& pt)
+{
+ if (!IsWindowVisible(m_hwndTip))
+ return;
+
+ RECT rc;
+ GetWindowRect(m_hwndTip, &rc);
+ if (PtInRect(&rc, pt))
+ return;
+
+ if (abs(pt.x - m_ptTipActivation.x) > 5 || abs(pt.y - m_ptTipActivation.y) > 5) {
+ SendMessage(m_hwndTip, TTM_TRACKACTIVATE, FALSE, 0);
+ m_ptTipActivation.x = m_ptTipActivation.y = 0;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// initialize the balloon tooltip for message window notifications
+
+void CMsgDialog::DM_InitTip()
+{
+ m_hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, nullptr, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, m_hwnd, nullptr, g_plugin.getInst(), (LPVOID)nullptr);
+
+ memset(&ti, 0, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.lpszText = TranslateT("No status message");
+ ti.hinst = g_plugin.getInst();
+ ti.hwnd = m_hwnd;
+ ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_TRANSPARENT;
+ ti.uId = (UINT_PTR)m_hwnd;
+ SendMessage(m_hwndTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
+
+ SetWindowPos(m_hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// checks generic hotkeys valid for both IM and MUC sessions
+//
+// returns 1 for handled hotkeys, 0 otherwise.
+
+bool CMsgDialog::DM_GenericHotkeysCheck(MSG *message)
+{
+ LRESULT mim_hotkey_check = Hotkey_Check(message, TABSRMM_HK_SECTION_GENERIC);
+
+ switch (mim_hotkey_check) {
+ case TABSRMM_HK_PASTEANDSEND:
+ HandlePasteAndSend();
+ return true;
+
+ case TABSRMM_HK_HISTORY:
+ m_btnHistory.Click();
+ return true;
+
+ case TABSRMM_HK_CONTAINEROPTIONS:
+ m_pContainer->OptionsDialog();
+ return true;
+
+ case TABSRMM_HK_TOGGLEINFOPANEL:
+ m_pPanel.setActive(!m_pPanel.isActive());
+ m_pPanel.showHide();
+ return true;
+
+ case TABSRMM_HK_TOGGLETOOLBAR:
+ SendMessage(m_hwnd, WM_COMMAND, IDC_TOGGLETOOLBAR, 0);
+ return true;
+
+ case TABSRMM_HK_CLEARLOG:
+ tabClearLog();
+ return true;
+
+ case TABSRMM_HK_TOGGLESIDEBAR:
+ if (m_pContainer->m_pSideBar->isActive())
+ SendMessage(m_hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
+ return true;
+
+ case TABSRMM_HK_CLOSE_OTHER:
+ CloseOtherTabs(m_pContainer->m_hwndTabs, *this);
+ return true;
+ }
+ return false;
+}
+
+LRESULT CMsgDialog::DM_MsgWindowCmdHandler(UINT cmd, WPARAM wParam, LPARAM lParam)
+{
+ RECT rc;
+ int iSelection;
+ HMENU submenu;
+
+ switch (cmd) {
+ case IDC_SRMM_BOLD:
+ case IDC_SRMM_ITALICS:
+ case IDC_SRMM_UNDERLINE:
+ case IDC_FONTSTRIKEOUT:
+ if (m_SendFormat != 0) { // dont use formatting if disabled
+ CHARFORMAT2 cf, cfOld;
+ memset(&cf, 0, sizeof(CHARFORMAT2));
+ memset(&cfOld, 0, sizeof(CHARFORMAT2));
+ cfOld.cbSize = cf.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT;
+ m_message.SendMsg(EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
+ BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
+ BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
+ BOOL isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT);
+
+ int ctrlId = LOWORD(wParam);
+ if (ctrlId == IDC_SRMM_BOLD && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_SRMM_BOLD)))
+ break;
+ if (ctrlId == IDC_SRMM_ITALICS && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_SRMM_ITALICS)))
+ break;
+ if (ctrlId == IDC_SRMM_UNDERLINE && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_SRMM_UNDERLINE)))
+ break;
+ if (ctrlId == IDC_FONTSTRIKEOUT && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_FONTSTRIKEOUT)))
+ break;
+ if (ctrlId == IDC_SRMM_BOLD) {
+ cf.dwEffects = isBold ? 0 : CFE_BOLD;
+ cf.dwMask = CFM_BOLD;
+ CheckDlgButton(m_hwnd, IDC_SRMM_BOLD, !isBold ? BST_CHECKED : BST_UNCHECKED);
+ }
+ else if (ctrlId == IDC_SRMM_ITALICS) {
+ cf.dwEffects = isItalic ? 0 : CFE_ITALIC;
+ cf.dwMask = CFM_ITALIC;
+ CheckDlgButton(m_hwnd, IDC_SRMM_ITALICS, !isItalic ? BST_CHECKED : BST_UNCHECKED);
+ }
+ else if (ctrlId == IDC_SRMM_UNDERLINE) {
+ cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE;
+ cf.dwMask = CFM_UNDERLINE;
+ CheckDlgButton(m_hwnd, IDC_SRMM_UNDERLINE, !isUnderline ? BST_CHECKED : BST_UNCHECKED);
+ }
+ else if (ctrlId == IDC_FONTSTRIKEOUT) {
+ cf.dwEffects = isStrikeout ? 0 : CFM_STRIKEOUT;
+ cf.dwMask = CFM_STRIKEOUT;
+ CheckDlgButton(m_hwnd, IDC_FONTSTRIKEOUT, !isStrikeout ? BST_CHECKED : BST_UNCHECKED);
+ }
+ m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ break;
+
+ case IDCANCEL:
+ ShowWindow(m_pContainer->m_hwnd, SW_MINIMIZE);
+ return FALSE;
+
+ case IDC_CLOSE:
+ PostMessage(m_hwnd, WM_CLOSE, 1, 0);
+ break;
+
+ case IDC_NAME:
+ if (GetKeyState(VK_SHIFT) & 0x8000) // copy UIN
+ Utils_ClipboardCopy(m_cache->getUIN());
+ else
+ CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)(m_cache->getActiveContact()), 0);
+ break;
+
+ case IDC_TIME:
+ submenu = GetSubMenu(PluginConfig.g_hMenuContext, 2);
+ MsgWindowUpdateMenu(submenu, MENU_LOGMENU);
+
+ GetWindowRect(GetDlgItem(m_hwnd, IDC_TIME), &rc);
+
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
+ return MsgWindowMenuHandler(iSelection, MENU_LOGMENU);
+
+ case IDC_PROTOMENU:
+ submenu = GetSubMenu(PluginConfig.g_hMenuContext, 4);
+ {
+ bool iOldGlobalSendFormat = g_plugin.bSendFormat;
+ int iLocalFormat = M.GetDword(m_hContact, "sendformat", 0);
+ int iNewLocalFormat = iLocalFormat;
+
+ GetWindowRect(GetDlgItem(m_hwnd, IDC_PROTOCOL), &rc);
+
+ CheckMenuItem(submenu, ID_MODE_GLOBAL, !m_bSplitterOverride ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_MODE_PRIVATE, m_bSplitterOverride ? MF_CHECKED : MF_UNCHECKED);
+
+ // formatting menu..
+ CheckMenuItem(submenu, ID_GLOBAL_BBCODE, (g_plugin.bSendFormat) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_GLOBAL_OFF, (g_plugin.bSendFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED);
+
+ CheckMenuItem(submenu, ID_THISCONTACT_GLOBALSETTING, (iLocalFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_THISCONTACT_BBCODE, (iLocalFormat > 0) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_THISCONTACT_OFF, (iLocalFormat == -1) ? MF_CHECKED : MF_UNCHECKED);
+
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
+ switch (iSelection) {
+ case ID_MODE_GLOBAL:
+ m_bSplitterOverride = false;
+ db_set_b(m_hContact, SRMSGMOD_T, "splitoverride", 0);
+ LoadSplitter();
+ AdjustBottomAvatarDisplay();
+ DM_RecalcPictureSize();
+ Resize();
+ break;
+
+ case ID_MODE_PRIVATE:
+ m_bSplitterOverride = true;
+ db_set_b(m_hContact, SRMSGMOD_T, "splitoverride", 1);
+ LoadSplitter();
+ AdjustBottomAvatarDisplay();
+ DM_RecalcPictureSize();
+ Resize();
+ break;
+
+ case ID_GLOBAL_BBCODE:
+ g_plugin.bSendFormat = SENDFORMAT_BBCODE;
+ break;
+
+ case ID_GLOBAL_OFF:
+ g_plugin.bSendFormat = SENDFORMAT_NONE;
+ break;
+
+ case ID_THISCONTACT_GLOBALSETTING:
+ iNewLocalFormat = 0;
+ break;
+
+ case ID_THISCONTACT_BBCODE:
+ iNewLocalFormat = SENDFORMAT_BBCODE;
+ break;
+
+ case ID_THISCONTACT_OFF:
+ iNewLocalFormat = -1;
+ break;
+ }
+
+ if (iNewLocalFormat == 0)
+ db_unset(m_hContact, SRMSGMOD_T, "sendformat");
+ else if (iNewLocalFormat != iLocalFormat)
+ db_set_dw(m_hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat);
+
+ if (iNewLocalFormat != iLocalFormat || g_plugin.bSendFormat != iOldGlobalSendFormat) {
+ m_SendFormat = M.GetDword(m_hContact, "sendformat", g_plugin.bSendFormat);
+ if (m_SendFormat == -1) // per contact override to disable it..
+ m_SendFormat = 0;
+ Srmm_Broadcast(DM_CONFIGURETOOLBAR, 0, 1);
+ }
+ }
+ break;
+
+ case IDC_TOGGLETOOLBAR:
+ if (lParam == 1)
+ m_pContainer->cfg.flags.m_bNoMenuBar = !m_pContainer->cfg.flags.m_bNoMenuBar;
+ else
+ m_pContainer->cfg.flags.m_bHideToolbar = !m_pContainer->cfg.flags.m_bHideToolbar;
+ m_pContainer->ApplySetting(true);
+ break;
+
+ case IDC_SENDMENU:
+ submenu = GetSubMenu(PluginConfig.g_hMenuContext, 3);
+
+ GetWindowRect(GetDlgItem(m_hwnd, IDOK), &rc);
+ CheckMenuItem(submenu, ID_SENDMENU_SENDTOMULTIPLEUSERS, (m_sendMode & SMODE_MULTIPLE) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_SENDMENU_SENDDEFAULT, m_sendMode == 0 ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_SENDMENU_SENDTOCONTAINER, (m_sendMode & SMODE_CONTAINER) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_SENDMENU_SENDLATER, (m_sendMode & SMODE_SENDLATER) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(submenu, ID_SENDMENU_SENDWITHOUTTIMEOUTS, (m_sendMode & SMODE_NOACK) ? MF_CHECKED : MF_UNCHECKED);
+
+ if (lParam)
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
+ else
+ iSelection = HIWORD(wParam);
+
+ switch (iSelection) {
+ case ID_SENDMENU_SENDTOMULTIPLEUSERS:
+ m_sendMode ^= SMODE_MULTIPLE;
+ if (m_sendMode & SMODE_MULTIPLE)
+ DM_CreateClist();
+ else if (IsWindow(GetDlgItem(m_hwnd, IDC_CLIST)))
+ DestroyWindow(GetDlgItem(m_hwnd, IDC_CLIST));
+ break;
+ case ID_SENDMENU_SENDDEFAULT:
+ m_sendMode = 0;
+ break;
+ case ID_SENDMENU_SENDTOCONTAINER:
+ m_sendMode ^= SMODE_CONTAINER;
+ RedrawWindow(m_hwnd, nullptr, nullptr, RDW_ERASENOW | RDW_UPDATENOW);
+ break;
+ case ID_SENDMENU_SENDLATER:
+ if (SendLater::Avail)
+ m_sendMode ^= SMODE_SENDLATER;
+ else
+ CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK | MB_ICONINFORMATION);
+ break;
+ case ID_SENDMENU_SENDWITHOUTTIMEOUTS:
+ m_sendMode ^= SMODE_NOACK;
+ if (m_sendMode & SMODE_NOACK)
+ db_set_b(m_hContact, SRMSGMOD_T, "no_ack", 1);
+ else
+ db_unset(m_hContact, SRMSGMOD_T, "no_ack");
+ break;
+ }
+ db_set_b(m_hContact, SRMSGMOD_T, "no_ack", (uint8_t)(m_sendMode & SMODE_NOACK ? 1 : 0));
+ SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
+ if (m_sendMode & SMODE_MULTIPLE || m_sendMode & SMODE_CONTAINER) {
+ SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOZORDER |
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
+ RedrawWindow(m_hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+ }
+ else {
+ if (IsWindow(GetDlgItem(m_hwnd, IDC_CLIST)))
+ DestroyWindow(GetDlgItem(m_hwnd, IDC_CLIST));
+ SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOZORDER |
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
+ RedrawWindow(m_hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+ }
+ m_pContainer->QueryClientArea(rc);
+ Resize();
+ DM_ScrollToBottom(1, 1);
+ Utils::showDlgControl(m_hwnd, IDC_MULTISPLITTER, (m_sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
+ Utils::showDlgControl(m_hwnd, IDC_CLIST, (m_sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE);
+ break;
+
+ case IDC_TOGGLESIDEBAR:
+ SendMessage(m_pContainer->m_hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0);
+ break;
+
+ case IDC_PIC:
+ GetClientRect(m_hwnd, &rc);
+
+ m_bEditNotesActive = !m_bEditNotesActive;
+ if (m_bEditNotesActive) {
+ int iLen = GetWindowTextLength(m_message.GetHwnd());
+ if (iLen != 0) {
+ ActivateTooltip(IDC_SRMM_MESSAGE, TranslateT("You cannot edit user notes when there are unsent messages"));
+ m_bEditNotesActive = false;
+ break;
+ }
+
+ if (!m_bIsAutosizingInput) {
+ m_iSplitterSaved = m_iSplitterY;
+ m_iSplitterY = rc.bottom / 2;
+ SendMessage(m_hwnd, WM_SIZE, 1, 1);
+ }
+
+ ptrW wszText(db_get_wsa(m_hContact, "UserInfo", "MyNotes"));
+ if (wszText != nullptr)
+ m_message.SetText(wszText);
+ }
+ else {
+ ptrW buf(m_message.GetText());
+ db_set_ws(m_hContact, "UserInfo", "MyNotes", buf);
+ m_message.SetText(L"");
+
+ if (!m_bIsAutosizingInput) {
+ m_iSplitterY = m_iSplitterSaved;
+ Resize();
+ DM_ScrollToBottom(0, 1);
+ }
+ }
+ SetWindowPos(m_message.GetHwnd(), nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOZORDER |
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
+ RedrawWindow(m_hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN);
+
+ if (m_bEditNotesActive)
+ CWarning::show(CWarning::WARN_EDITUSERNOTES, MB_OK | MB_ICONINFORMATION);
+ break;
+
+ case IDM_CLEAR:
+ tabClearLog();
+ break;
+
+ case IDC_PROTOCOL:
+ submenu = Menu_BuildContactMenu(m_hContact);
+ if (lParam == 0)
+ GetWindowRect(GetDlgItem(m_hwnd, IDC_PROTOCOL), &rc);
+ else
+ GetWindowRect((HWND)lParam, &rc);
+
+ iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, m_hwnd, nullptr);
+ if (iSelection)
+ Clist_MenuProcessCommand(LOWORD(iSelection), MPCF_CONTACTMENU, m_hContact);
+
+ DestroyMenu(submenu);
+ break;
+
+ // error control
+ case IDC_CANCELSEND:
+ DM_ErrorDetected(MSGERROR_CANCEL, 0);
+ break;
+
+ case IDC_RETRY:
+ DM_ErrorDetected(MSGERROR_RETRY, 0);
+ break;
+
+ case IDC_MSGSENDLATER:
+ DM_ErrorDetected(MSGERROR_SENDLATER, 0);
+ break;
+
+ case IDC_SELFTYPING:
+ if (AllowTyping()) {
+ int iCurrentTypingMode = g_plugin.getByte(m_hContact, SRMSGSET_TYPING, g_plugin.bTypingNew);
+ if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON && iCurrentTypingMode) {
+ DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
+ m_nTypeMode = PROTOTYPE_SELFTYPING_OFF;
+ }
+ g_plugin.setByte(m_hContact, SRMSGSET_TYPING, (uint8_t)!iCurrentTypingMode);
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// initialize rich edit control (log and edit control) for both MUC and
+// standard IM session windows.
+
+void CMsgDialog::DM_InitRichEdit()
+{
+ char *szStreamOut = nullptr;
+ if (!isChat() && GetWindowTextLength(m_message.GetHwnd()) > 0)
+ szStreamOut = m_message.GetRichTextRtf();
+ SetWindowText(m_message.GetHwnd(), L"");
+
+ m_pLog->UpdateOptions();
+
+ m_message.SendMsg(EM_SETBKGNDCOLOR, 0, m_pContainer->m_theme.inputbg);
+
+ CHARFORMAT2 cf2 = {};
+ cf2.cbSize = sizeof(cf2);
+
+ if (isChat()) {
+ LOGFONTW lf;
+ COLORREF inputcharcolor;
+ LoadMsgDlgFont(FONTSECTION_IM, MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor);
+
+ cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR;
+ cf2.crTextColor = inputcharcolor;
+ cf2.bCharSet = lf.lfCharSet;
+ cf2.crBackColor = m_pContainer->m_theme.inputbg;
+ wcsncpy_s(cf2.szFaceName, lf.lfFaceName, _TRUNCATE);
+ cf2.dwEffects = 0;
+ cf2.wWeight = (uint16_t)lf.lfWeight;
+ cf2.bPitchAndFamily = lf.lfPitchAndFamily;
+ cf2.yHeight = abs(lf.lfHeight) * 15;
+ }
+ else {
+ LOGFONTW lf = m_pContainer->m_theme.logFonts[MSGFONTID_MESSAGEAREA];
+ COLORREF inputcharcolor = m_pContainer->m_theme.fontColors[MSGFONTID_MESSAGEAREA];
+
+ for (auto &it : Utils::rtf_clrs)
+ if (it->clr == inputcharcolor)
+ inputcharcolor = RGB(GetRValue(inputcharcolor), GetGValue(inputcharcolor), GetBValue(inputcharcolor) == 0 ? GetBValue(inputcharcolor) + 1 : GetBValue(inputcharcolor) - 1);
+
+ cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC;
+ cf2.crTextColor = inputcharcolor;
+ cf2.bCharSet = lf.lfCharSet;
+ wcsncpy_s(cf2.szFaceName, lf.lfFaceName, _TRUNCATE);
+ cf2.dwEffects = ((lf.lfWeight >= FW_BOLD) ? CFE_BOLD : 0) | (lf.lfItalic ? CFE_ITALIC : 0) | (lf.lfUnderline ? CFE_UNDERLINE : 0) | (lf.lfStrikeOut ? CFE_STRIKEOUT : 0);
+ cf2.wWeight = (uint16_t)lf.lfWeight;
+ cf2.bPitchAndFamily = lf.lfPitchAndFamily;
+ cf2.yHeight = abs(lf.lfHeight) * 15;
+ }
+ m_message.SendMsg(EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
+ m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); /* WINE: fix send colour text. */
+ m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2); /* WINE: fix send colour text. */
+
+ // setup the rich edit control(s)
+ // LOG is always set to RTL, because this is needed for proper bidirectional operation later.
+ // The real text direction is then enforced by the streaming code which adds appropiate paragraph
+ // and textflow formatting commands to the
+ PARAFORMAT2 pf2;
+ memset(&pf2, 0, sizeof(PARAFORMAT2));
+ pf2.cbSize = sizeof(pf2);
+ pf2.wEffects = PFE_RTLPARA;
+ pf2.dwMask = PFM_RTLPARA;
+ if (FindRTLLocale())
+ m_message.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ if (!(m_dwFlags & MWF_LOG_RTL)) {
+ pf2.wEffects = 0;
+ m_message.SendMsg(EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+ }
+ m_message.SendMsg(EM_SETLANGOPTIONS, 0, (LPARAM)m_message.SendMsg(EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+
+ if (m_dwFlags & MWF_LOG_RTL)
+ SetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
+ else
+ SetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE) & ~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
+
+ if (szStreamOut != nullptr) {
+ SETTEXTEX stx = { ST_DEFAULT, CP_UTF8 };
+ m_message.SendMsg(EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut);
+ mir_free(szStreamOut);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// set the states of defined database action buttons(only if button is a toggle)
+
+void CMsgDialog::DM_SetDBButtonStates()
+{
+ ButtonItem *buttonItem = m_pContainer->m_buttonItems;
+ MCONTACT hFinalContact = 0;
+ HWND hwndContainer = m_pContainer->m_hwnd;
+
+ while (buttonItem) {
+ HWND hWnd = GetDlgItem(hwndContainer, buttonItem->uId);
+
+ if (buttonItem->pfnCallback)
+ buttonItem->pfnCallback(buttonItem, m_hwnd, this, hWnd);
+
+ if (!(buttonItem->dwFlags & BUTTON_ISTOGGLE && buttonItem->dwFlags & BUTTON_ISDBACTION)) {
+ buttonItem = buttonItem->nextItem;
+ continue;
+ }
+
+ BOOL result = FALSE;
+ char *szModule = buttonItem->szModule;
+ char *szSetting = buttonItem->szSetting;
+ if (buttonItem->dwFlags & BUTTON_DBACTIONONCONTACT || buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) {
+ if (buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION)
+ szModule = Proto_GetBaseAccountName(m_hContact);
+ hFinalContact = m_hContact;
+ }
+ else hFinalContact = 0;
+
+ switch (buttonItem->type) {
+ case DBVT_BYTE:
+ result = (db_get_b(hFinalContact, szModule, szSetting, 0) == buttonItem->bValuePush[0]);
+ break;
+ case DBVT_WORD:
+ result = (db_get_w(hFinalContact, szModule, szSetting, 0) == *((uint16_t *)&buttonItem->bValuePush));
+ break;
+ case DBVT_DWORD:
+ result = (db_get_dw(hFinalContact, szModule, szSetting, 0) == *((uint32_t *)&buttonItem->bValuePush));
+ break;
+ case DBVT_ASCIIZ:
+ ptrA szValue(db_get_sa(hFinalContact, szModule, szSetting));
+ if (szValue)
+ result = !mir_strcmp((char*)buttonItem->bValuePush, szValue);
+ break;
+ }
+ SendMessage(hWnd, BM_SETCHECK, result, 0);
+ buttonItem = buttonItem->nextItem;
+ }
+}
+
+void CMsgDialog::DM_ScrollToBottom(WPARAM wParam, LPARAM lParam)
+{
+ if (m_bScrollingDisabled)
+ return;
+
+ if (IsIconic(m_pContainer->m_hwnd))
+ m_bDeferredScroll = true;
+
+ if (m_iLogMode == WANT_BUILTIN_LOG)
+ ((CLogWindow *)m_pLog)->ScrollToBottom(wParam != 0, lParam != 0);
+ else
+ m_pLog->ScrollToBottom();
+}
+
+void CMsgDialog::DM_RecalcPictureSize()
+{
+ HBITMAP hbm = ((m_pPanel.isActive()) && m_pContainer->cfg.avatarMode != 3) ? m_hOwnPic : (m_ace ? m_ace->hbmPic : PluginConfig.g_hbmUnknown);
+ if (hbm) {
+ BITMAP bminfo;
+ GetObject(hbm, sizeof(bminfo), &bminfo);
+ CalcDynamicAvatarSize(&bminfo);
+ Resize();
+ }
+ else m_pic.cy = m_pic.cx = 60;
+}
+
+void CMsgDialog::DM_UpdateLastMessage() const
+{
+ if (m_pContainer->m_hwndStatus == nullptr || m_pContainer->m_hwndActive != m_hwnd)
+ return;
+
+ wchar_t szBuf[100];
+ if (m_bShowTyping) {
+ SendMessage(m_pContainer->m_hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
+ mir_snwprintf(szBuf, TranslateT("%s is typing a message..."), m_cache->getNick());
+ }
+ else if (m_bStatusSet) {
+ SendMessage(m_pContainer->m_hwndStatus, SB_SETICON, 0, (LPARAM)m_szStatusIcon);
+ SendMessage(m_pContainer->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)m_szStatusText.c_str());
+ return;
+ }
+ else {
+ SendMessage(m_pContainer->m_hwndStatus, SB_SETICON, 0, 0);
+
+ if (m_pContainer->cfg.flags.m_bUinStatusBar)
+ mir_snwprintf(szBuf, L"UID: %s", m_cache->getUIN());
+ else if (m_lastMessage) {
+ wchar_t date[64], time[64];
+ TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"d", date, _countof(date), 0);
+ if (m_pContainer->cfg.flags.m_bUinStatusBar && mir_wstrlen(date) > 6)
+ date[mir_wstrlen(date) - 5] = 0;
+ TimeZone_PrintTimeStamp(nullptr, m_lastMessage, L"t", time, _countof(time), 0);
+ mir_snwprintf(szBuf, TranslateT("Last received: %s at %s"), date, time);
+ }
+ else szBuf[0] = 0;
+ }
+
+ SendMessage(m_pContainer->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// create embedded contact list control
+
+HWND CMsgDialog::DM_CreateClist()
+{
+ if (!SendLater::Avail) {
+ CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK | MB_ICONINFORMATION);
+ m_sendMode &= ~SMODE_MULTIPLE;
+ return nullptr;
+ }
+
+ HWND hwndClist = CreateWindowExA(0, "CListControl", "", WS_TABSTOP | WS_VISIBLE | WS_CHILD | 0x248, 184, 0, 30, 30, m_hwnd, (HMENU)IDC_CLIST, g_plugin.getInst(), nullptr);
+ SendMessage(hwndClist, WM_TIMER, 14, 0);
+ HANDLE hItem = (HANDLE)SendMessage(hwndClist, CLM_FINDCONTACT, m_hContact, 0);
+
+ SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) & ~CLS_EX_TRACKSELECT);
+ SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) | (CLS_EX_NOSMOOTHSCROLLING | CLS_EX_NOTRANSLUCENTSEL));
+
+ if (!g_plugin.bAllowOfflineMultisend)
+ SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) | CLS_HIDEOFFLINE);
+
+ if (hItem)
+ SendMessage(hwndClist, CLM_SETCHECKMARK, (WPARAM)hItem, 1);
+
+ SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, Clist::HideEmptyGroups, 0);
+ SendMessage(hwndClist, CLM_SETUSEGROUPS, Clist::UseGroups, 0);
+ SendMessage(hwndClist, CLM_FIRST + 106, 0, 1);
+ SendMessage(hwndClist, CLM_AUTOREBUILD, 0, 0);
+ if (hwndClist)
+ RedrawWindow(hwndClist, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
+ return hwndClist;
+}
+
+LRESULT CMsgDialog::DM_MouseWheelHandler(WPARAM wParam, LPARAM lParam)
+{
+ POINT pt;
+ GetCursorPos(&pt);
+
+ RECT rc;
+ GetWindowRect(m_message.GetHwnd(), &rc);
+ if (PtInRect(&rc, pt))
+ return 1;
+
+ if (isChat()) { // scroll nick list by just hovering it
+ RECT rcNicklist;
+ GetWindowRect(m_nickList.GetHwnd(), &rcNicklist);
+ if (PtInRect(&rcNicklist, pt)) {
+ m_nickList.SendMsg(WM_MOUSEWHEEL, wParam, lParam);
+ return 0;
+ }
+ }
+
+ GetWindowRect(m_pLog->GetHwnd(), &rc);
+ if (PtInRect(&rc, pt)) {
+ short wDirection = (short)HIWORD(wParam);
+
+ if (LOWORD(wParam) & MK_SHIFT || M.GetByte("fastscroll", 0)) {
+ if (wDirection < 0)
+ SendMessage(m_pLog->GetHwnd(), WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0);
+ else if (wDirection > 0)
+ SendMessage(m_pLog->GetHwnd(), WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0);
+ }
+ else SendMessage(m_pLog->GetHwnd(), WM_MOUSEWHEEL, wParam, lParam);
+ return 0;
+ }
+
+ if (GetTabItemFromMouse(m_pContainer->m_hwndTabs, &pt) != -1) {
+ SendMessage(m_pContainer->m_hwndTabs, WM_MOUSEWHEEL, wParam, -1);
+ return 0;
+ }
+ return 1;
+}
+
+void CMsgDialog::DM_FreeTheme()
+{
+ if (m_hTheme) {
+ CloseThemeData(m_hTheme);
+ m_hTheme = nullptr;
+ }
+ if (m_hThemeIP) {
+ CloseThemeData(m_hThemeIP);
+ m_hThemeIP = nullptr;
+ }
+ if (m_hThemeToolbar) {
+ CloseThemeData(m_hThemeToolbar);
+ m_hThemeToolbar = nullptr;
+ }
+}
+
+void CMsgDialog::DM_ThemeChanged()
+{
+ CSkinItem *item_log = &SkinItems[ID_EXTBKHISTORY];
+ CSkinItem *item_msg = &SkinItems[ID_EXTBKINPUTAREA];
+
+ m_hTheme = OpenThemeData(m_hwnd, L"EDIT");
+
+ if (m_hTheme != nullptr || (CSkin::m_skinEnabled && !item_log->IGNORED)) {
+ if (m_iLogMode == WANT_BUILTIN_LOG)
+ LOG()->DisableStaticEdge();
+
+ if (isChat())
+ SetWindowLongPtr(m_nickList.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_nickList.GetHwnd(), GWL_EXSTYLE) & ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
+ }
+
+ if (m_hTheme != nullptr || (CSkin::m_skinEnabled && !item_msg->IGNORED))
+ SetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(m_message.GetHwnd(), GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
+
+ m_hThemeIP = M.isAero() ? OpenThemeData(m_hwnd, L"ButtonStyle") : nullptr;
+ m_hThemeToolbar = (M.isAero() || (!CSkin::m_skinEnabled && M.isVSThemed())) ? OpenThemeData(m_hwnd, L"REBAR") : nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// send out message typing notifications (MTN) when the
+// user is typing/editing text in the message input area.
+
+void CMsgDialog::DM_NotifyTyping(int mode)
+{
+ const char *szProto = m_cache->getActiveProto();
+ MCONTACT hContact = m_cache->getActiveContact();
+
+ // editing user notes or preparing a message for queued delivery -> don't send MTN
+ if (m_bEditNotesActive || (m_sendMode & SMODE_SENDLATER))
+ return;
+
+ // allow supression of sending out TN for the contact (NOTE: for metacontacts, do NOT use the subcontact handle)
+ if (!g_plugin.getByte(hContact, SRMSGSET_TYPING, g_plugin.bTypingNew))
+ return;
+
+ if (szProto == nullptr) // should not, but who knows...
+ return;
+
+ // check status and capabilities of the protocol
+ uint32_t typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0);
+ if (!(typeCaps & PF4_SUPPORTTYPING))
+ return;
+
+ if (isChat()) {
+ m_nTypeMode = mode;
+ Chat_DoEventHook(m_si, GC_USER_TYPNOTIFY, 0, 0, m_nTypeMode);
+ }
+ else {
+ uint32_t protoStatus = Proto_GetStatus(szProto);
+ if (protoStatus < ID_STATUS_ONLINE)
+ return;
+
+ // check visibility/invisibility lists to not "accidentially" send MTN to contacts who
+ // should not see them (privacy issue)
+ uint32_t protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (protoCaps & PF1_VISLIST && db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
+ return;
+
+ if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(hContact, szProto, "ApparentMode", 0) != ID_STATUS_ONLINE)
+ return;
+
+ // don't send to contacts which are not permanently added to the contact list,
+ // unless the option to ignore added status is set.
+ if (!Contact::OnList(m_hContact) && !g_plugin.bTypingUnknown)
+ return;
+
+ // End user check
+ m_nTypeMode = mode;
+ CallService(MS_PROTO_SELFISTYPING, hContact, m_nTypeMode);
+ }
+}
+
+void CMsgDialog::DM_OptionsApplied(bool bRemakeLog)
+{
+ m_szMicroLf[0] = 0;
+ if (!m_pContainer->m_theme.isPrivate) {
+ m_pContainer->LoadThemeDefaults();
+ m_dwFlags = m_pContainer->m_theme.dwFlags;
+ }
+
+ LoadLocalFlags();
+ m_hTimeZone = TimeZone_CreateByContact(m_hContact, nullptr, TZF_KNOWNONLY);
+
+ m_bShowUIElements = (m_pContainer->cfg.flags.m_bHideToolbar) == 0;
+ m_bSplitterOverride = M.GetByte(m_hContact, "splitoverride", 0) != 0;
+ m_pPanel.getVisibility();
+
+ // small inner margins (padding) for the text areas
+ m_message.SendMsg(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3));
+
+ GetSendFormat();
+ SetDialogToType();
+ SendMessage(m_hwnd, DM_CONFIGURETOOLBAR, 0, 0);
+
+ DM_InitRichEdit();
+ if (m_hwnd == m_pContainer->m_hwndActive)
+ SendMessage(m_pContainer->m_hwnd, WM_SIZE, 0, 0);
+ InvalidateRect(m_message.GetHwnd(), nullptr, FALSE);
+ if (bRemakeLog) {
+ if (IsIconic(m_pContainer->m_hwnd))
+ m_bDeferredRemakeLog = true;
+ else if (isChat())
+ RedrawLog();
+ else
+ RemakeLog();
+ }
+
+ ShowWindow(m_hwndPanelPicParent, SW_SHOW);
+ EnableWindow(m_hwndPanelPicParent, TRUE);
+
+ UpdateWindowIcon();
+}
+
+void CMsgDialog::DM_Typing(bool fForceOff)
+{
+ HWND hwndContainer = m_pContainer->m_hwnd;
+ HWND hwndStatus = m_pContainer->m_hwndStatus;
+
+ if (m_nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - m_nLastTyping > TIMEOUT_TYPEOFF)
+ DM_NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
+
+ if (m_bShowTyping == 1) {
+ if (m_nTypeSecs > 0) {
+ m_nTypeSecs--;
+ if (GetForegroundWindow() == hwndContainer)
+ UpdateWindowIcon();
+ }
+ else {
+ if (!fForceOff) {
+ m_bShowTyping = 2;
+ m_nTypeSecs = 86400;
+
+ if (!isChat())
+ mir_snwprintf(m_wszStatusBar, TranslateT("%s has entered text."), m_cache->getNick());
+
+ if (hwndStatus && m_pContainer->m_hwndActive == m_hwnd)
+ SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)m_wszStatusBar);
+ }
+ UpdateWindowIcon();
+ HandleIconFeedback(this, (HICON)-1);
+ CMsgDialog *dat_active = (CMsgDialog*)GetWindowLongPtr(m_pContainer->m_hwndActive, GWLP_USERDATA);
+ if (dat_active && !dat_active->isChat())
+ m_pContainer->UpdateTitle(0);
+ else
+ m_pContainer->UpdateTitle(0, dat_active);
+ if (!m_pContainer->cfg.flags.m_bNoFlash && PluginConfig.m_FlashOnMTN)
+ m_pContainer->ReflashContainer();
+ }
+ }
+ else if (m_bShowTyping == 2) {
+ if (m_nTypeSecs > 0)
+ m_nTypeSecs--;
+ else {
+ m_wszStatusBar[0] = 0;
+ m_bShowTyping = 0;
+ }
+ tabUpdateStatusBar();
+ }
+ else if (m_nTypeSecs > 0) {
+ mir_snwprintf(m_wszStatusBar, TranslateT("%s is typing a message"),
+ (m_pUserTyping) ? m_pUserTyping->pszNick : m_cache->getNick());
+
+ m_nTypeSecs--;
+ if (hwndStatus && m_pContainer->m_hwndActive == m_hwnd) {
+ SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)m_wszStatusBar);
+ SendMessage(hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
+ }
+ if (IsIconic(hwndContainer) || !IsActive()) {
+ SetWindowText(hwndContainer, m_wszStatusBar);
+ m_pContainer->cfg.flags.m_bNeedsUpdateTitle = true;
+ if (!m_pContainer->cfg.flags.m_bNoFlash && PluginConfig.m_FlashOnMTN)
+ m_pContainer->ReflashContainer();
+ }
+
+ if (m_pContainer->m_hwndActive != m_hwnd) {
+ if (m_bCanFlashTab)
+ m_iFlashIcon = PluginConfig.g_IconTypingEvent;
+ HandleIconFeedback(this, PluginConfig.g_IconTypingEvent);
+ }
+ else { // active tab may show icon if status bar is disabled
+ if (!hwndStatus) {
+ if (TabCtrl_GetItemCount(m_hwndParent) > 1 || !m_pContainer->cfg.flags.m_bHideTabs)
+ HandleIconFeedback(this, PluginConfig.g_IconTypingEvent);
+ }
+ }
+ if ((GetForegroundWindow() != hwndContainer) || (m_pContainer->m_hwndStatus == nullptr) || (m_pContainer->m_hwndActive != m_hwnd))
+ m_pContainer->SetIcon(this, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
+
+ m_bShowTyping = 1;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// sync splitter position for all open sessions.
+// This cares about private / per container / MUC <> IM splitter syncing and everything.
+// called from IM and MUC windows via DM_SPLITTERGLOBALEVENT
+
+int CMsgDialog::DM_SplitterGlobalEvent(WPARAM wParam, LPARAM lParam)
+{
+ CMsgDialog *srcDat = PluginConfig.lastSPlitterPos.pSrcDat;
+ TContainerData *srcCnt = PluginConfig.lastSPlitterPos.pSrcContainer;
+ bool fCntGlobal = (!m_pContainer->cfg.fPrivate ? true : false);
+
+ if (m_bIsAutosizingInput)
+ return 0;
+
+ RECT rcWin;
+ GetWindowRect(m_hwnd, &rcWin);
+
+ LONG newPos;
+ if (wParam == 0 && lParam == 0) {
+ if (m_bSplitterOverride && this != srcDat)
+ return 0;
+
+ if (srcDat->isChat() == isChat())
+ newPos = PluginConfig.lastSPlitterPos.pos;
+ else if (!srcDat->isChat() && isChat())
+ newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im;
+ else if (srcDat->isChat() && !isChat())
+ newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im;
+ else
+ newPos = 0;
+
+ if (this == srcDat) {
+ m_pContainer->cfg.iSplitterY = m_iSplitterY;
+ if (fCntGlobal)
+ SaveSplitter();
+ return 0;
+ }
+
+ if (!fCntGlobal && m_pContainer != srcCnt)
+ return 0;
+ if (srcCnt->cfg.fPrivate && m_pContainer != srcCnt)
+ return 0;
+
+ // for inactive sessions, delay the splitter repositioning until they become
+ // active (faster, avoid redraw/resize problems for minimized windows)
+ if (IsIconic(m_pContainer->m_hwnd) || m_pContainer->m_hwndActive != m_hwnd) {
+ m_bDelayedSplitter = true;
+ m_wParam = newPos;
+ m_lParam = PluginConfig.lastSPlitterPos.lParam;
+ return 0;
+ }
+ }
+ else newPos = wParam;
+
+ LoadSplitter();
+ AdjustBottomAvatarDisplay();
+ DM_RecalcPictureSize();
+ Resize();
+ DM_ScrollToBottom(1, 1);
+ if (this != srcDat)
+ UpdateToolbarBG();
+ return 0;
+}
+
+void CMsgDialog::DM_AddDivider()
+{
+ if (!m_bDividerSet && g_plugin.bUseDividers)
+ if (GetWindowTextLength(m_pLog->GetHwnd()) > 0)
+ m_bDividerSet = m_bDividerWanted = true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// incoming event handler
+
+void CMsgDialog::DM_EventAdded(WPARAM, LPARAM lParam)
+{
+ MEVENT hDbEvent = (MEVENT)lParam;
+
+ DBEVENTINFO dbei = {};
+ db_event_get(hDbEvent, &dbei);
+ if (m_hDbEventFirst == 0)
+ m_hDbEventFirst = hDbEvent;
+
+ bool bIsStatusChangeEvent = IsStatusEvent(dbei.eventType);
+ bool bDisableNotify = (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ));
+
+ if (!DbEventIsShown(&dbei))
+ return;
+
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) {
+ m_lastMessage = dbei.timestamp;
+ m_wszStatusBar[0] = 0;
+ if (m_bShowTyping) {
+ m_nTypeSecs = 0;
+ DM_Typing(true);
+ m_bShowTyping = 0;
+ }
+ HandleIconFeedback(this, (HICON)-1);
+ if (m_pContainer->m_hwndStatus)
+ PostMessage(m_hwnd, DM_UPDATELASTMESSAGE, 0, 0);
+ }
+
+ // set the message log divider to mark new (maybe unseen) messages, if the container has
+ // been minimized or in the background.
+ if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) {
+ if (g_plugin.bDividersUsePopupConfig && g_plugin.bUseDividers) {
+ if (!MessageWindowOpened(m_hContact, nullptr))
+ DM_AddDivider();
+ }
+ else if (g_plugin.bUseDividers) {
+ if (!m_pContainer->IsActive())
+ DM_AddDivider();
+ else if (m_pContainer->m_hwndActive != m_hwnd)
+ DM_AddDivider();
+ }
+
+ if (IsWindowVisible(m_pContainer->m_hwnd))
+ m_pContainer->m_bHidden = false;
+ }
+ m_cache->updateStats(TSessionStats::UPDATE_WITH_LAST_RCV, 0);
+
+ if (hDbEvent != m_hDbEventFirst || isChat())
+ StreamEvents(hDbEvent, 1, 1);
+ else
+ RemakeLog();
+
+ // handle tab flashing
+ if (!bDisableNotify && !bIsStatusChangeEvent)
+ if ((TabCtrl_GetCurSel(m_hwndParent) != m_iTabID) && !(dbei.flags & DBEF_SENT)) {
+ switch (dbei.eventType) {
+ case EVENTTYPE_MESSAGE:
+ m_iFlashIcon = PluginConfig.g_IconMsgEvent;
+ break;
+ case EVENTTYPE_FILE:
+ m_iFlashIcon = PluginConfig.g_IconFileEvent;
+ break;
+ default:
+ m_iFlashIcon = PluginConfig.g_IconMsgEvent;
+ break;
+ }
+ timerFlash.Start(TIMEOUT_FLASHWND);
+ m_bCanFlashTab = true;
+ }
+
+ // try to flash the contact list...
+ if (!bDisableNotify)
+ FlashOnClist(hDbEvent, &dbei);
+
+ // autoswitch tab if option is set AND container is minimized (otherwise, we never autoswitch)
+ // never switch for status changes...
+ if (!(dbei.flags & DBEF_SENT) && !bIsStatusChangeEvent) {
+ if (g_plugin.bAutoSwitchTabs && m_pContainer->m_hwndActive != m_hwnd) {
+ if ((IsIconic(m_pContainer->m_hwnd) && !IsZoomed(m_pContainer->m_hwnd)) || (g_plugin.bHideOnClose && !IsWindowVisible(m_pContainer->m_hwnd))) {
+ int iItem = GetTabIndexFromHWND(GetParent(m_hwnd), m_hwnd);
+ if (iItem >= 0) {
+ TabCtrl_SetCurSel(m_hwndParent, iItem);
+ ShowWindow(m_pContainer->m_hwndActive, SW_HIDE);
+ m_pContainer->m_hwndActive = m_hwnd;
+ m_pContainer->UpdateTitle(m_hContact);
+ m_pContainer->cfg.flags.m_bDeferredTabSelect = true;
+ }
+ }
+ }
+ }
+
+ // flash window if it is not focused
+ if (!bDisableNotify && !bIsStatusChangeEvent)
+ if (!IsActive() && !(dbei.flags & DBEF_SENT)) {
+ if (!m_pContainer->cfg.flags.m_bNoFlash && !m_pContainer->IsActive())
+ m_pContainer->FlashContainer(1, 0);
+ m_pContainer->SetIcon(this, Skin_LoadIcon(SKINICON_EVENT_MESSAGE));
+ m_pContainer->cfg.flags.m_bNeedsUpdateTitle = true;
+ }
+
+ // play a sound
+ if (!bDisableNotify && dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT)))
+ PlayIncomingSound();
+
+ if (m_pWnd)
+ m_pWnd->Invalidate();
+}
+
+void CMsgDialog::DM_HandleAutoSizeRequest(REQRESIZE* rr)
+{
+ if (rr == nullptr || GetForegroundWindow() != m_pContainer->m_hwnd)
+ return;
+
+ if (!m_bIsAutosizingInput || m_iInputAreaHeight == -1)
+ return;
+
+ LONG heightLimit = M.GetDword("autoSplitMinLimit", 0);
+ LONG iNewHeight = rr->rc.bottom - rr->rc.top;
+
+ if (CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED)
+ iNewHeight += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP + SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM - 2);
+
+ if (heightLimit && iNewHeight < heightLimit)
+ iNewHeight = heightLimit;
+
+ if (iNewHeight == m_iInputAreaHeight)
+ return;
+
+ RECT rc;
+ GetClientRect(m_hwnd, &rc);
+ LONG cy = rc.bottom - rc.top;
+ LONG panelHeight = (m_pPanel.isActive() ? m_pPanel.getHeight() : 0);
+
+ if (iNewHeight > (cy - panelHeight) / 2)
+ iNewHeight = (cy - panelHeight) / 2;
+
+ m_dynaSplitter = iNewHeight - DPISCALEY_S(2);
+ if (m_pContainer->cfg.flags.m_bBottomToolbar)
+ m_dynaSplitter += DPISCALEY_S(22);
+ m_iSplitterY = m_dynaSplitter + DPISCALEY_S(34);
+ DM_RecalcPictureSize();
+
+ m_iInputAreaHeight = iNewHeight;
+ UpdateToolbarBG();
+ DM_ScrollToBottom(1, 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// status icon stuff (by sje, used for indicating encryption status in the status bar
+// this is now part of the message window api
+
+
+static int OnSrmmIconChanged(WPARAM hContact, LPARAM)
+{
+ if (hContact == 0)
+ Srmm_Broadcast(DM_STATUSICONCHANGE, 0, 0);
+ else {
+ HWND hwnd = Srmm_FindWindow(hContact);
+ if (hwnd)
+ PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0);
+ }
+ return 0;
+}
+
+void CMsgDialog::DrawStatusIcons(HDC hDC, const RECT &rc, int gap)
+{
+ int x = rc.left;
+ int y = (rc.top + rc.bottom - PluginConfig.m_smcxicon) >> 1;
+
+ SetBkMode(hDC, TRANSPARENT);
+
+ int nIcon = 0;
+ while (StatusIconData *sid = Srmm_GetNthIcon(m_hContact, nIcon++)) {
+ if (!mir_strcmp(sid->szModule, MSG_ICON_MODULE)) {
+ if (sid->dwId == MSG_ICON_SOUND) {
+ DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_SOUNDS],
+ PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
+
+ DrawIconEx(hDC, x, y, m_pContainer->cfg.flags.m_bNoSound ?
+ PluginConfig.g_iconOverlayDisabled : PluginConfig.g_iconOverlayEnabled,
+ PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
+ }
+ else if (sid->dwId == MSG_ICON_UTN) {
+ if (AllowTyping()) {
+ DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
+
+ DrawIconEx(hDC, x, y, g_plugin.getByte(m_hContact, SRMSGSET_TYPING, g_plugin.bTypingNew) ?
+ PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, 0, nullptr, DI_NORMAL);
+ }
+ else CSkin::DrawDimmedIcon(hDC, x, y, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], 50);
+ }
+ }
+ else {
+ HICON hIcon;
+ if ((sid->flags & MBF_DISABLED) && sid->hIconDisabled)
+ hIcon = sid->hIconDisabled;
+ else
+ hIcon = sid->hIcon;
+
+ if ((sid->flags & MBF_DISABLED) && sid->hIconDisabled == nullptr)
+ CSkin::DrawDimmedIcon(hDC, x, y, PluginConfig.m_smcxicon, PluginConfig.m_smcyicon, hIcon, 50);
+ else
+ DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, nullptr, DI_NORMAL);
+ }
+
+ x += PluginConfig.m_smcxicon + gap;
+ }
+}
+
+void CMsgDialog::CheckStatusIconClick(POINT pt, const RECT &rc, int gap, int code)
+{
+ if (code == NM_CLICK || code == NM_RCLICK) {
+ POINT ptScreen;
+ GetCursorPos(&ptScreen);
+ if (!PtInRect(&rcLastStatusBarClick, ptScreen))
+ return;
+ }
+
+ UINT iconNum = (pt.x - (rc.left + 0)) / (PluginConfig.m_smcxicon + gap);
+
+ StatusIconData *sid = Srmm_GetNthIcon(m_hContact, iconNum);
+ if (sid == nullptr)
+ return;
+
+ if (!mir_strcmp(sid->szModule, MSG_ICON_MODULE)) {
+ if (sid->dwId == MSG_ICON_SOUND && code != NM_RCLICK) {
+ if (GetKeyState(VK_SHIFT) & 0x8000) {
+ for (TContainerData *p = pFirstContainer; p; p = p->pNext) {
+ p->cfg.flags.m_bNoSound = m_pContainer->cfg.flags.m_bNoSound;
+ InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
+ }
+ }
+ else {
+ m_pContainer->cfg.flags.m_bNoSound = !m_pContainer->cfg.flags.m_bNoSound;
+ InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
+ }
+ }
+ else if (sid->dwId == MSG_ICON_UTN && code != NM_RCLICK && AllowTyping()) {
+ SendMessage(m_pContainer->m_hwndActive, WM_COMMAND, IDC_SELFTYPING, 0);
+ InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
+ }
+ }
+ else {
+ StatusIconClickData sicd = { sizeof(sicd) };
+ GetCursorPos(&sicd.clickLocation);
+ sicd.dwId = sid->dwId;
+ sicd.szModule = sid->szModule;
+ sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0);
+ Srmm_ClickStatusIcon(m_hContact, &sicd);
+ InvalidateRect(m_pContainer->m_hwndStatus, nullptr, TRUE);
+ }
+}
+
+void CMsgDialog::DM_ErrorDetected(int type, int flag)
+{
+ switch (type) {
+ case MSGERROR_CANCEL:
+ case MSGERROR_SENDLATER:
+ if (m_bErrorState) {
+ m_cache->saveHistory();
+ if (type == MSGERROR_SENDLATER)
+ sendQueue->doSendLater(m_iCurrentQueueError, this); // to be implemented at a later time
+ m_iOpenJobs--;
+ sendQueue->dec();
+ if (m_iCurrentQueueError >= 0 && m_iCurrentQueueError < SendQueue::NR_SENDJOBS)
+ sendQueue->clearJob(m_iCurrentQueueError);
+ m_iCurrentQueueError = -1;
+ sendQueue->showErrorControls(this, FALSE);
+ if (type != MSGERROR_CANCEL || flag == 0)
+ m_message.SetText(L"");
+ sendQueue->checkQueue(this);
+ int iNextFailed = sendQueue->findNextFailed(this);
+ if (iNextFailed >= 0)
+ sendQueue->handleError(this, iNextFailed);
+ }
+ break;
+
+ case MSGERROR_RETRY:
+ if (m_bErrorState) {
+ int resent = 0;
+
+ m_cache->saveHistory();
+ if (m_iCurrentQueueError >= 0 && m_iCurrentQueueError < SendQueue::NR_SENDJOBS) {
+ SendJob *job = sendQueue->getJobByIndex(m_iCurrentQueueError);
+ if (job->iSendId == 0 && job->hContact == 0)
+ break;
+
+ job->iSendId = ProtoChainSend(job->hContact, PSS_MESSAGE, job->dwFlags, (LPARAM)job->szSendBuffer);
+ resent++;
+ }
+
+ if (resent) {
+ SendJob *job = sendQueue->getJobByIndex(m_iCurrentQueueError);
+
+ SetTimer(m_hwnd, TIMERID_MSGSEND + m_iCurrentQueueError, PluginConfig.m_MsgTimeout, nullptr);
+ job->iStatus = SendQueue::SQ_INPROGRESS;
+ m_iCurrentQueueError = -1;
+ sendQueue->showErrorControls(this, FALSE);
+ m_message.SetText(L"");
+ sendQueue->checkQueue(this);
+
+ int iNextFailed = sendQueue->findNextFailed(this);
+ if (iNextFailed >= 0)
+ sendQueue->handleError(this, iNextFailed);
+ }
+ }
+ }
+}
+
+int SI_InitStatusIcons()
+{
+ StatusIconData sid = {};
+ sid.szModule = MSG_ICON_MODULE;
+ sid.dwId = MSG_ICON_SOUND; // Sounds
+ Srmm_AddIcon(&sid, &g_plugin);
+
+ sid.dwId = MSG_ICON_UTN;
+ Srmm_AddIcon(&sid, &g_plugin);
+
+ HookEvent(ME_MSG_ICONSCHANGED, OnSrmmIconChanged);
+ return 0;
+}