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/AniSmileyObject.cpp | 450 ++++++++++++++++++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100644 plugins/SmileyAdd/AniSmileyObject.cpp (limited to 'plugins/SmileyAdd/AniSmileyObject.cpp') diff --git a/plugins/SmileyAdd/AniSmileyObject.cpp b/plugins/SmileyAdd/AniSmileyObject.cpp new file mode 100644 index 0000000000..42a63d3549 --- /dev/null +++ b/plugins/SmileyAdd/AniSmileyObject.cpp @@ -0,0 +1,450 @@ +/* +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 "SmileyBase.h" +#include "m_smileyadd.h" +#include "smileys.h" +#include "options.h" + +#include + + +class CAniSmileyObject; + +static int CompareAniSmiley(const CAniSmileyObject* p1, const CAniSmileyObject* p2) +{ + return (int)((char*)p2 - (char*)p1); +} + +static LIST regAniSmileys(10, CompareAniSmiley); + +static UINT_PTR timerId; +static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD); + +static void CALLBACK sttMainThreadCallback( PVOID ) +{ + if (timerId == 0xffffffff) + timerId = SetTimer(NULL, 0, 100, (TIMERPROC)timerProc); +} + + +class CAniSmileyObject : public ISmileyBase +{ +private: + typedef enum { animStdOle, animDrctRichEd, animHpp } AnimType; + + POINTL m_rectOrig; + SIZEL m_rectExt; + + COLORREF m_bkg; + + SmileyType* m_sml; + ImageBase* m_img; + unsigned m_nFramePosition; + + long m_counter; + unsigned m_richFlags; + long m_lastObjNum; + + AnimType m_animtype; + bool m_allowAni; + +public: + CAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp) + { + m_allowAni = false; + m_animtype = ishpp ? animHpp : animStdOle; + m_bkg = clr; + + m_rectOrig.x = 0; + m_rectOrig.y = 0; + m_rectExt.cx = 0; + m_rectExt.cy = 0; + + m_richFlags = 0; + m_lastObjNum = 0; + + m_sml = sml; + m_img = NULL; + m_nFramePosition = 0; + m_counter = 0; + } + + ~CAniSmileyObject(void) + { + UnloadSmiley(); + } + + void LoadSmiley(void) + { + if (m_img != NULL) return; + + m_img = m_sml->CreateCachedImage(); + if (m_img && m_img->IsAnimated() && opt.AnimateDlg) + { + m_nFramePosition = 0; + m_img->SelectFrame(m_nFramePosition); + long frtm = m_img->GetFrameDelay(); + m_counter = frtm / 10 + ((frtm % 10) >= 5); + + regAniSmileys.insert(this); + if (timerId == 0) + { + timerId = 0xffffffff; + CallFunctionAsync(sttMainThreadCallback, NULL); + } + } + else + m_nFramePosition = m_sml->GetStaticFrame(); + } + + void UnloadSmiley(void) + { + regAniSmileys.remove(this); + + if (timerId && (timerId+1) && regAniSmileys.getCount() == 0) + { + KillTimer(NULL, timerId); + timerId = 0; + } + if (m_img) m_img->Release(); + m_img = NULL; + } + + void GetDrawingProp(void) + { + if (m_hwnd == NULL) return; + + IRichEditOle* RichEditOle; + if (SendMessage(m_hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return; + + REOBJECT reObj = {0}; + reObj.cbStruct = sizeof(REOBJECT); + + HRESULT hr = RichEditOle->GetObject(m_lastObjNum, &reObj, REO_GETOBJ_NO_INTERFACES); + if (hr == S_OK && reObj.dwUser == (DWORD)(ISmileyBase*)this && reObj.clsid == CLSID_NULL) + { + m_richFlags = reObj.dwFlags; + } + else + { + long objectCount = RichEditOle->GetObjectCount(); + for (long i = objectCount; i--; ) + { + HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_NO_INTERFACES); + if (FAILED(hr)) continue; + + if (reObj.dwUser == (DWORD)(ISmileyBase*)this && reObj.clsid == CLSID_NULL) + { + m_lastObjNum = i; + m_richFlags = reObj.dwFlags; + break; + } + } + } + RichEditOle->Release(); + + if ((m_richFlags & REO_SELECTED) == 0) + { + CHARRANGE sel; + SendMessage(m_hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (reObj.cp >= sel.cpMin && reObj.cp < sel.cpMax) + m_richFlags |= REO_INVERTEDSELECT; + else + m_richFlags &= ~REO_INVERTEDSELECT; + } + } + + + void DoDirectDraw(HDC hdc) + { + HBITMAP hBmp = CreateCompatibleBitmap(hdc, m_rectExt.cx, m_rectExt.cy); + HDC hdcMem = CreateCompatibleDC(hdc); + HANDLE hOld = SelectObject(hdcMem, hBmp); + + RECT rc; + rc.left = m_rectExt.cx - m_sizeExtent.cx; + rc.top = m_rectExt.cy - m_sizeExtent.cy; + rc.right = rc.left + m_sizeExtent.cx; + rc.bottom = rc.top + m_sizeExtent.cy; + + HBRUSH hbr = CreateSolidBrush(m_bkg); + RECT frc = { 0, 0, m_rectExt.cx, m_rectExt.cy }; + FillRect(hdcMem, &frc, hbr); + DeleteObject(hbr); + + m_img->DrawInternal(hdcMem, rc.left, rc.top, m_sizeExtent.cx - 1, m_sizeExtent.cy - 1); + + if (m_richFlags & REO_SELECTED) + { + HBRUSH hbr = CreateSolidBrush(m_bkg ^ 0xFFFFFF); + FrameRect(hdcMem, &rc, hbr); + DeleteObject(hbr); + } + + if (m_richFlags & REO_INVERTEDSELECT) + InvertRect(hdcMem, &rc); + + BitBlt(hdc, m_rectOrig.x, m_rectOrig.y, m_rectExt.cx, m_rectExt.cy, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, hOld); + DeleteObject(hBmp); + DeleteDC(hdcMem); + } + + void DrawOnRichEdit(void) + { + HDC hdc = GetDC(m_hwnd); + if (RectVisible(hdc, &m_orect)) + { + RECT crct; + GetClientRect(m_hwnd, &crct); + + HRGN hrgnOld = CreateRectRgnIndirect(&crct); + int res = GetClipRgn(hdc, hrgnOld); + + HRGN hrgn = CreateRectRgnIndirect(&crct); + SelectClipRgn(hdc, hrgn); + DeleteObject(hrgn); + + DoDirectDraw(hdc); + + SelectClipRgn(hdc, res < 1 ? NULL : hrgnOld); + DeleteObject(hrgnOld); + } + else + { + m_visible = false; + m_allowAni = false; + UnloadSmiley(); + } + ReleaseDC(m_hwnd, hdc); + } + + void DrawOnHPP(void) + { + FVCNDATA_NMHDR nmh = {0}; + nmh.code = NM_FIREVIEWCHANGE; + nmh.hwndFrom = m_hwnd; + + nmh.cbSize = sizeof(nmh); + nmh.bEvent = FVCN_PREFIRE; + nmh.bAction = FVCA_DRAW; + nmh.rcRect = m_orect; + SendMessage(GetParent(m_hwnd), WM_NOTIFY, (WPARAM)m_hwnd, (LPARAM)&nmh); + + switch (nmh.bAction) + { + case FVCA_DRAW: + // support for pseudo-edit mode and event details + m_animtype = m_dirAniAllow ? animDrctRichEd : animStdOle; + GetDrawingProp(); + DrawOnRichEdit(); + break; + + case FVCA_CUSTOMDRAW: + m_rectExt.cy = nmh.rcRect.bottom - nmh.rcRect.top; + m_rectExt.cx = nmh.rcRect.right - nmh.rcRect.left; + m_rectOrig.x = nmh.rcRect.left; + m_rectOrig.y = nmh.rcRect.top; + + m_bkg = nmh.clrBackground; + + DoDirectDraw(nmh.hDC); + + nmh.bEvent = FVCN_POSTFIRE; + SendMessage(GetParent(m_hwnd), WM_NOTIFY, (WPARAM)m_hwnd, (LPARAM)&nmh); + break; + + case FVCA_SKIPDRAW: + break; + + case FVCA_NONE: + m_visible = false; + break; + + default: + break; + } + } + + void ProcessTimerTick(void) + { + if (m_visible && m_img && --m_counter <= 0) + { + m_nFramePosition = m_img->SelectNextFrame(m_nFramePosition); + long frtm = m_img->GetFrameDelay(); + m_counter = frtm / 10 + ((frtm % 10) >= 5); + + switch (m_animtype) + { + case animStdOle: + if (m_allowAni) SendOnViewChange(); + else + { + m_visible = false; + UnloadSmiley(); + } + m_allowAni = false; + break; + + case animDrctRichEd: + DrawOnRichEdit(); + break; + + case animHpp: + DrawOnHPP(); + break; + } + } + } + + void SetPosition(HWND hwnd, LPCRECT lpRect) + { + ISmileyBase::SetPosition(hwnd, lpRect); + + m_allowAni = m_visible; + + if (m_visible) LoadSmiley(); + else UnloadSmiley(); + + if (lpRect == NULL) return; + if (m_animtype == animStdOle) + { + m_animtype = animDrctRichEd; + GetDrawingProp(); + } + + if (lpRect->top == -1) + { + m_rectOrig.x = lpRect->left; + m_rectOrig.y = lpRect->bottom - m_sizeExtent.cy; + m_rectExt.cy = m_sizeExtent.cy; + } + else if (lpRect->bottom == -1) + { + m_rectOrig.x = lpRect->left; + m_rectOrig.y = lpRect->top; + } + else + { + m_rectOrig.x = lpRect->left; + m_rectOrig.y = lpRect->top; + m_rectExt.cy = lpRect->bottom - lpRect->top; + } + } + + STDMETHOD(Close)(DWORD dwSaveOption) + { + m_visible = false; + UnloadSmiley(); + + return ISmileyBase::Close(dwSaveOption); + } + + STDMETHOD(Draw)(DWORD dwAspect, LONG, void*, DVTARGETDEVICE*, HDC, + HDC hdc, LPCRECTL pRectBounds, LPCRECTL /* pRectWBounds */, + BOOL (__stdcall *)(ULONG_PTR), ULONG_PTR) + { + if (dwAspect != DVASPECT_CONTENT) return DV_E_DVASPECT; + if (pRectBounds == NULL) return E_INVALIDARG; + + LoadSmiley(); + + if (m_img == NULL) return E_FAIL; + + m_sizeExtent.cx = pRectBounds->right - pRectBounds->left; + m_sizeExtent.cy = pRectBounds->bottom - pRectBounds->top; + + m_rectExt = m_sizeExtent; + + switch (m_animtype) + { + case animDrctRichEd: + { + m_rectExt.cy = pRectBounds->bottom - m_rectOrig.y; + RECT frc = { 0, 0, m_sizeExtent.cx - 1, m_sizeExtent.cy - 1 }; + + HBITMAP hBmp = CreateCompatibleBitmap(hdc, frc.right, frc.bottom); + HDC hdcMem = CreateCompatibleDC(hdc); + HANDLE hOld = SelectObject(hdcMem, hBmp); + + HBRUSH hbr = CreateSolidBrush(m_bkg); + FillRect(hdcMem, &frc, hbr); + DeleteObject(hbr); + + m_img->DrawInternal(hdcMem, 0, 0, frc.right, frc.bottom); + + BitBlt(hdc, pRectBounds->left, pRectBounds->top, frc.right, frc.bottom, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, hOld); + DeleteObject(hBmp); + DeleteDC(hdcMem); + } + GetDrawingProp(); + break; + + case animHpp: + m_orect = *(LPRECT)pRectBounds; + + default: + m_img->DrawInternal(hdc, pRectBounds->left, pRectBounds->top, + m_sizeExtent.cx - 1, m_sizeExtent.cy - 1); + break; + } + + m_allowAni = true; + m_visible = true; + + return S_OK; + } + + STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel) + { + HRESULT hr = ISmileyBase::SetExtent(dwDrawAspect, psizel); + if (hr == S_OK) m_rectExt = m_sizeExtent; + return hr; + } +}; + +ISmileyBase* CreateAniSmileyObject(SmileyType* sml, COLORREF clr, bool ishpp) +{ + if (!sml->IsValid()) return NULL; + + CAniSmileyObject *obj = new CAniSmileyObject(sml, clr, ishpp); + return obj; +} + +static void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD) +{ + for (int i=0; iProcessTimerTick(); +} + +void DestroyAniSmileys(void) +{ + if (timerId && (timerId+1)) + { + KillTimer(NULL, timerId); + timerId = 0; + } + regAniSmileys.destroy(); +} + -- cgit v1.2.3