diff options
Diffstat (limited to 'plugins/SmileyAdd/src/richcall.cpp')
-rw-r--r-- | plugins/SmileyAdd/src/richcall.cpp | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/plugins/SmileyAdd/src/richcall.cpp b/plugins/SmileyAdd/src/richcall.cpp new file mode 100644 index 0000000000..d9b9123c48 --- /dev/null +++ b/plugins/SmileyAdd/src/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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "general.h"
+#include "smileys.h"
+#include "smileyroutines.h"
+#include "services.h"
+#include "options.h"
+#include "SmileyBase.h"
+
+#include <richole.h>
+#include <tom.h>
+
+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<RichEditData> 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<RichEditOwnerData> 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 = (GetWindowLongPtr(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();
+}
|