From f920ef497f3299ae24fe783ce03bdd93b419f764 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Fri, 18 May 2012 22:02:50 +0000 Subject: plugins folders renaming git-svn-id: http://svn.miranda-ng.org/main/trunk@60 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/SmileyAdd/richcall.cpp | 554 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 554 insertions(+) create mode 100644 plugins/SmileyAdd/richcall.cpp (limited to 'plugins/SmileyAdd/richcall.cpp') diff --git a/plugins/SmileyAdd/richcall.cpp b/plugins/SmileyAdd/richcall.cpp new file mode 100644 index 0000000000..72830400a5 --- /dev/null +++ b/plugins/SmileyAdd/richcall.cpp @@ -0,0 +1,554 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2008 - 2011 Boris Krasnovskiy All Rights Reserved + +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 version 2 +of the License. + +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, see . +*/ + +#include "general.h" +#include "smileys.h" +#include "smileyroutines.h" +#include "services.h" +#include "options.h" +#include "SmileyBase.h" + +#include +#include + +typedef struct +{ + HWND hwnd; + HANDLE hContact; + WNDPROC wpOrigWndProc; + HWND hToolTip; + int tipActive; + bool inputarea; + bool dontReplace; +} RichEditData; + +typedef struct +{ + HWND hwnd; + WNDPROC wpOrigWndProc; + HWND hwndInput; + HWND hwndLog; +} RichEditOwnerData; + +static int CompareRichEditData(const RichEditData* p1, const RichEditData* p2) +{ + return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); +} +static LIST g_RichEditList(10, CompareRichEditData); + + +static int CompareRichEditData(const RichEditOwnerData* p1, const RichEditOwnerData* p2) +{ + return (int)((INT_PTR)p1->hwnd - (INT_PTR)p2->hwnd); +} +static LIST g_RichEditOwnerList(5, CompareRichEditData); + + +static void SetPosition(HWND hwnd) +{ + IRichEditOle* RichEditOle; + if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return; + + ITextDocument* TextDocument; + if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) + { + RichEditOle->Release(); + return; + } + + // retrieve text range + ITextRange* TextRange; + if (TextDocument->Range(0, 0, &TextRange) != S_OK) + { + TextDocument->Release(); + RichEditOle->Release(); + return; + } + TextDocument->Release(); + + int objectCount = RichEditOle->GetObjectCount(); + for (int i = objectCount - 1; i >= 0; i--) + { + REOBJECT reObj = {0}; + reObj.cbStruct = sizeof(REOBJECT); + + HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ); + if (FAILED(hr)) continue; + + ISmileyBase *igsc = NULL; + if (reObj.clsid == CLSID_NULL) + reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc); + + reObj.poleobj->Release(); + if (igsc == NULL) continue; + + TextRange->SetRange(reObj.cp, reObj.cp); + + BOOL res; + POINT pt; + RECT rect; + hr = TextRange->GetPoint(tomStart | TA_BOTTOM | TA_LEFT, &pt.x, &pt.y); + if (hr == S_OK) + { + res = ScreenToClient(hwnd, &pt); + rect.bottom = pt.y; + rect.left = pt.x; + } + else + rect.bottom = -1; + + hr = TextRange->GetPoint(tomStart | TA_TOP | TA_LEFT, &pt.x, &pt.y); + if (hr == S_OK) + { + res = ScreenToClient(hwnd, &pt); + rect.top = pt.y; + rect.left = pt.x; + } + else + rect.top = -1; + + igsc->SetPosition(hwnd, &rect); + igsc->Release(); + } + TextRange->Release(); + RichEditOle->Release(); +} + +static void SetTooltip(long x, long y, HWND hwnd, RichEditData* rdt) +{ + TCHAR* smltxt; + int needtip = CheckForTip(x, y, hwnd, &smltxt); + if (needtip != rdt->tipActive) + { + TOOLINFO ti = {0}; + ti.cbSize = sizeof(ti); + ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + ti.hwnd = hwnd; + ti.uId = (UINT_PTR)ti.hwnd; + + if (needtip != -1) + { + if (rdt->tipActive == -1) + { + rdt->hToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), + TTS_NOPREFIX | WS_POPUP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, NULL, g_hInst, NULL); + + SendMessage(rdt->hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti); + } + + ti.lpszText = smltxt; + SendMessage(rdt->hToolTip, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); + SendMessage(rdt->hToolTip, TTM_ACTIVATE, TRUE, 0); + } + else + { + if (rdt->tipActive != -1) + { + SendMessage(rdt->hToolTip, TTM_ACTIVATE, FALSE, 0); + DestroyWindow(rdt->hToolTip); + rdt->hToolTip = NULL; + } + } + rdt->tipActive = needtip; + } +} + +static const CHARRANGE allsel = { 0, LONG_MAX }; + + +static void ReplaceContactSmileys(RichEditData *rdt, const CHARRANGE &sel, bool ignoreLast, bool unFreeze) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + SmileyPackCType *smcp = NULL; + SmileyPackType* SmileyPack = GetSmileyPack(NULL, rdt->hContact, rdt->inputarea ? NULL : &smcp); + ReplaceSmileys(rdt->hwnd, SmileyPack, smcp, sel, false, ignoreLast, unFreeze); +} + +static void ReplaceContactSmileysWithText(RichEditData *rdt, CHARRANGE &sel, bool freeze) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + ReplaceSmileysWithText(rdt->hwnd, sel, freeze); +} + +static void SmileyToTextCutPrep(RichEditData* rdt) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + + SendMessage(rdt->hwnd, WM_SETREDRAW, FALSE, 0); + CHARRANGE sel; + SendMessage(rdt->hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + ReplaceContactSmileysWithText(rdt, sel, true); +} + +static void SmileyToTextCutRest(RichEditData* rdt) +{ + if ((rdt->inputarea && !opt.InputSmileys) || rdt->dontReplace) return; + + CHARRANGE sel; + SendMessage(rdt->hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + ReplaceContactSmileys(rdt, sel, false, true); + SendMessage(rdt->hwnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(rdt->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); +} + + +static LRESULT CALLBACK RichEditSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RichEditData* rdt = g_RichEditList.find((RichEditData*)&hwnd); + if (rdt == NULL) return 0; + + CHARRANGE sel; + + WNDPROC wpOrigWndProc = rdt->wpOrigWndProc; + + switch(uMsg) + { + case WM_DESTROY: + CloseRichCallback(hwnd, false); + break; + + case WM_COPY: + case WM_CUT: + SmileyToTextCutPrep(rdt); + break; + + case WM_PAINT: + SetPosition(hwnd); + break; + + case EM_STREAMOUT: + if (wParam & SFF_SELECTION) + SmileyToTextCutPrep(rdt); + else + { + sel = allsel; + ReplaceContactSmileysWithText(rdt, sel, true); + } + break; + + case WM_KEYDOWN: + if ((wParam == 'C' || wParam == VK_INSERT) && (GetKeyState(VK_CONTROL) & 0x8000)) + { + SmileyToTextCutPrep(rdt); + } + else if ((wParam == 'X' && (GetKeyState(VK_CONTROL) & 0x8000)) || + (wParam == VK_DELETE && (GetKeyState(VK_SHIFT) & 0x8000))) + { + SmileyToTextCutPrep(rdt); + } + else if (wParam == VK_TAB && ((GetKeyState(VK_CONTROL) | GetKeyState(VK_SHIFT)) & 0x8000) == 0) + { + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + sel.cpMin = max(sel.cpMin - 20, 0); + + ReplaceContactSmileysWithText(rdt, sel, true); + } + break; + } + + LRESULT result = CallWindowProc(wpOrigWndProc, hwnd, uMsg, wParam, lParam); + + switch(uMsg) + { + case WM_DESTROY: + CloseRichCallback(hwnd, true); + break; + + case WM_MOUSEMOVE: + SetTooltip(LOWORD(lParam), HIWORD(lParam), hwnd, rdt); + break; + + case WM_PAINT: + case WM_HSCROLL: + case WM_VSCROLL: + SetPosition(hwnd); + break; + + case WM_COPY: + case WM_CUT: + SmileyToTextCutRest(rdt); + break; + + case EM_STREAMOUT: + if (wParam & SFF_SELECTION) + SmileyToTextCutRest(rdt); + else + ReplaceContactSmileys(rdt, allsel, false, true); + break; + + case WM_KEYDOWN: + if ((wParam == 'C' || wParam == VK_INSERT) && (GetKeyState(VK_CONTROL) & 0x8000)) + { + SmileyToTextCutRest(rdt); + } + else if ((wParam == 'X' && (GetKeyState(VK_CONTROL) & 0x8000)) || + (wParam == VK_DELETE && (GetKeyState(VK_SHIFT) & 0x8000))) + { + SmileyToTextCutRest(rdt); + } + else if (wParam == VK_TAB && ((GetKeyState(VK_CONTROL) | GetKeyState(VK_SHIFT)) & 0x8000) == 0) + { + sel.cpMax = LONG_MAX; + bool hascont = rdt->hContact != NULL; + ReplaceContactSmileys(rdt, sel, false, hascont); + } + break; + + case WM_CHAR: + if (!rdt->inputarea || (rdt->inputarea && !opt.InputSmileys)) + break; + + if (lParam & (1 << 28)) // ALT key + break; + + if ((lParam & 0xFF) > 2) // Repeat rate + break; + + if (wParam > ' ' && opt.EnforceSpaces) + break; + + if (wParam == 0x16) + { + ReplaceContactSmileys(rdt, allsel, false, false); + break; + } + + if (opt.DCursorSmiley) + { + ReplaceContactSmileys(rdt, allsel, true, true); + } + else + { + if (wParam >= ' ' || wParam == '\n' || wParam == '\r') + { + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + sel.cpMin = max(sel.cpMin - 20, 0); + sel.cpMax += 20; + + ReplaceContactSmileysWithText(rdt, sel, true); + ReplaceContactSmileys(rdt, sel, false, true); + } + } + break; + + case EM_PASTESPECIAL: + case WM_PASTE: + case EM_REPLACESEL: + case WM_SETTEXT: + case EM_SETTEXTEX: + if (rdt->inputarea) + ReplaceContactSmileys(rdt, allsel, false, false); + break; + + case WM_REMAKERICH: + ReplaceContactSmileys(rdt, allsel, false, false); + break; + } + + return result; +} + +void CloseRichCallback(HWND hwnd, bool force) +{ + int ind = g_RichEditList.getIndex((RichEditData*)&hwnd); + if ( ind != -1 ) + { + RichEditData* rdt = g_RichEditList[ind]; + bool richsub = GetWindowLongPtr(hwnd, GWLP_WNDPROC) == (LONG_PTR)RichEditSubclass; + if (richsub) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)rdt->wpOrigWndProc); + if (richsub || force) + { + if (rdt->hToolTip) DestroyWindow(rdt->hToolTip); + delete rdt; + g_RichEditList.remove(ind); + } + } +} + +bool SetRichCallback(HWND hwnd, HANDLE hContact, bool subany, bool subnew) +{ + RichEditData* rdt = g_RichEditList.find((RichEditData*)&hwnd); + if (rdt == NULL) + { + IRichEditOle* RichEditOle; + if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return false; + RichEditOle->Release(); + + rdt = new RichEditData; + + rdt->hwnd = hwnd; + rdt->hContact = hContact; + rdt->inputarea = (GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY) == 0; + rdt->dontReplace = false; + rdt->tipActive = -1; + rdt->wpOrigWndProc = NULL; + rdt->hToolTip = NULL; + g_RichEditList.insert(rdt); + + if (subnew) + rdt->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditSubclass); + } + else + { + if (hContact && !rdt->hContact) rdt->hContact = hContact; + if (subany && rdt->wpOrigWndProc == NULL) + rdt->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditSubclass); + } + return true; +} + +static LRESULT CALLBACK RichEditOwnerSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RichEditOwnerData* rdto = g_RichEditOwnerList.find((RichEditOwnerData*)&hwnd); + if (rdto == NULL) return 0; + + WNDPROC wpOrigWndProc = rdto->wpOrigWndProc; + + switch(uMsg) + { + case WM_DESTROY: + { + RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); + if (rdt && (!rdt->inputarea || opt.InputSmileys)) + { + CHARRANGE sel = allsel; + rdt->dontReplace = true; + ReplaceSmileysWithText(rdt->hwnd, sel, false); + } + } + CloseRichOwnerCallback(hwnd, false); + break; + + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == 1624) + { + RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); + if (rdt && (!rdt->inputarea || opt.InputSmileys)) + { + rdt->dontReplace = true; + CHARRANGE sel = allsel; + ReplaceSmileysWithText(rdt->hwnd, sel, false); + } + } + break; + } + + LRESULT result = CallWindowProc(wpOrigWndProc, hwnd, uMsg, wParam, lParam); + + switch(uMsg) + { + case WM_DESTROY: + CloseRichOwnerCallback(hwnd, true); + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == 1624) // && lParam == 0) + { + RichEditData* rdt = g_RichEditList.find((RichEditData*)&rdto->hwndInput); + if (rdt) + { + CHARRANGE sel = allsel; + if (!result) ReplaceContactSmileys(rdt, sel, false, false); + rdt->dontReplace = false; + } + } + break; + } + return result; +} + +void CloseRichOwnerCallback(HWND hwnd, bool force) +{ + int ind = g_RichEditOwnerList.getIndex((RichEditOwnerData*)&hwnd); + if ( ind != -1 ) + { + RichEditOwnerData* rdto = g_RichEditOwnerList[ind]; + bool richsub = GetWindowLongPtr(hwnd, GWLP_WNDPROC) == (LONG_PTR)RichEditOwnerSubclass; + if (richsub) + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)rdto->wpOrigWndProc); + rdto->wpOrigWndProc = NULL; + } + if (force) + { + CloseRichCallback(rdto->hwndInput, true); + CloseRichCallback(rdto->hwndLog, true); + + delete rdto; + g_RichEditOwnerList.remove(ind); + } + } +} + +void SetRichOwnerCallback(HWND hwnd, HWND hwndInput, HWND hwndLog) +{ + RichEditOwnerData* rdto = g_RichEditOwnerList.find((RichEditOwnerData*)&hwnd); + if (rdto == NULL) + { + rdto = new RichEditOwnerData; + + rdto->hwnd = hwnd; + rdto->hwndInput = hwndInput; + rdto->hwndLog = hwndLog; + rdto->wpOrigWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RichEditOwnerSubclass); + g_RichEditOwnerList.insert(rdto); + } + else + { + if (rdto->hwndInput == NULL) rdto->hwndInput = hwndInput; + if (rdto->hwndLog == NULL) rdto->hwndLog = hwndLog; + } +} + +void ProcessAllInputAreas(bool restoreText) +{ + for (int i=g_RichEditList.getCount(); i--; ) + { + RichEditData* rdt = g_RichEditList[i]; + if (rdt->inputarea) + { + if (restoreText) + { + CHARRANGE sel = allsel; + ReplaceContactSmileysWithText(rdt, sel, false); + } + else + { + ReplaceContactSmileys(rdt, allsel, false, false); + } + } + } +} + + +void RichEditData_Destroy(void) +{ + int i; + for (i=g_RichEditList.getCount(); i--; ) + CloseRichCallback(g_RichEditList[i]->hwnd, true); + g_RichEditList.destroy(); + + for (i=g_RichEditOwnerList.getCount(); i--; ) + CloseRichOwnerCallback(g_RichEditOwnerList[i]->hwnd, true); + g_RichEditOwnerList.destroy(); +} -- cgit v1.2.3