From 1e92bf5cf72665b5fec103a0a70d734340725539 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 24 Jul 2012 09:26:39 +0000 Subject: StopSpamPlus, TipperYM, TooltipNotify, TopToolBar, TranslitSwitcher, UserGuide: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1159 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/TipperYM/src/bitmap_func.cpp | 776 ++++++++++ plugins/TipperYM/src/bitmap_func.h | 71 + plugins/TipperYM/src/common.h | 105 ++ plugins/TipperYM/src/message_pump.cpp | 413 ++++++ plugins/TipperYM/src/message_pump.h | 71 + plugins/TipperYM/src/mir_smileys.cpp | 514 +++++++ plugins/TipperYM/src/mir_smileys.h | 70 + plugins/TipperYM/src/options.cpp | 2495 +++++++++++++++++++++++++++++++++ plugins/TipperYM/src/options.h | 196 +++ plugins/TipperYM/src/popwin.cpp | 2016 ++++++++++++++++++++++++++ plugins/TipperYM/src/popwin.h | 140 ++ plugins/TipperYM/src/preset_items.cpp | 131 ++ plugins/TipperYM/src/preset_items.h | 57 + plugins/TipperYM/src/resource.h | 137 ++ plugins/TipperYM/src/skin_parser.cpp | 417 ++++++ plugins/TipperYM/src/skin_parser.h | 30 + plugins/TipperYM/src/str_utils.cpp | 231 +++ plugins/TipperYM/src/str_utils.h | 66 + plugins/TipperYM/src/subst.cpp | 1011 +++++++++++++ plugins/TipperYM/src/subst.h | 47 + plugins/TipperYM/src/tipper.cpp | 362 +++++ plugins/TipperYM/src/translations.cpp | 744 ++++++++++ plugins/TipperYM/src/translations.h | 125 ++ plugins/TipperYM/src/version.h | 4 + 24 files changed, 10229 insertions(+) create mode 100644 plugins/TipperYM/src/bitmap_func.cpp create mode 100644 plugins/TipperYM/src/bitmap_func.h create mode 100644 plugins/TipperYM/src/common.h create mode 100644 plugins/TipperYM/src/message_pump.cpp create mode 100644 plugins/TipperYM/src/message_pump.h create mode 100644 plugins/TipperYM/src/mir_smileys.cpp create mode 100644 plugins/TipperYM/src/mir_smileys.h create mode 100644 plugins/TipperYM/src/options.cpp create mode 100644 plugins/TipperYM/src/options.h create mode 100644 plugins/TipperYM/src/popwin.cpp create mode 100644 plugins/TipperYM/src/popwin.h create mode 100644 plugins/TipperYM/src/preset_items.cpp create mode 100644 plugins/TipperYM/src/preset_items.h create mode 100644 plugins/TipperYM/src/resource.h create mode 100644 plugins/TipperYM/src/skin_parser.cpp create mode 100644 plugins/TipperYM/src/skin_parser.h create mode 100644 plugins/TipperYM/src/str_utils.cpp create mode 100644 plugins/TipperYM/src/str_utils.h create mode 100644 plugins/TipperYM/src/subst.cpp create mode 100644 plugins/TipperYM/src/subst.h create mode 100644 plugins/TipperYM/src/tipper.cpp create mode 100644 plugins/TipperYM/src/translations.cpp create mode 100644 plugins/TipperYM/src/translations.h create mode 100644 plugins/TipperYM/src/version.h (limited to 'plugins/TipperYM/src') diff --git a/plugins/TipperYM/src/bitmap_func.cpp b/plugins/TipperYM/src/bitmap_func.cpp new file mode 100644 index 0000000000..0a33c7b1d8 --- /dev/null +++ b/plugins/TipperYM/src/bitmap_func.cpp @@ -0,0 +1,776 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "options.h" +#include "bitmap_func.h" +#include "message_pump.h" + +TOOLTIPSKIN skin = {0}; + +HBITMAP CreateBitmapPart(FIBITMAP *fibSrc, int iSrcWidth, int iSrcHeight, int iDesWidth, int iDesHeight, TransformationMode transfMode) +{ + FIBITMAP *fibMem = NULL; + HBITMAP hbmpDes = NULL; + + if (!fibSrc) + return NULL; + + switch (transfMode) + { + case TM_NONE: + case TM_CENTRE: + case TM_TILE_ALL: + { + hbmpDes = fii->FI_CreateHBITMAPFromDIB(fibSrc); + break; + } + case TM_STRECH_ALL: + { + fibMem = fii->FI_Rescale(fibSrc, iDesWidth, iDesHeight, FILTER_BILINEAR); + hbmpDes = fii->FI_CreateHBITMAPFromDIB(fibMem); + break; + } + case TM_STRECH_HORIZONTAL: + case TM_TILE_VERTICAL: + { + fibMem = fii->FI_Rescale(fibSrc, iDesWidth, iSrcHeight, FILTER_BILINEAR); + hbmpDes = fii->FI_CreateHBITMAPFromDIB(fibMem); + break; + } + case TM_STRECH_VERTICAL: + case TM_TILE_HORIZONTAL: + { + fibMem = fii->FI_Rescale(fibSrc, iSrcWidth, iSrcHeight, FILTER_BILINEAR); + hbmpDes = fii->FI_CreateHBITMAPFromDIB(fibMem); + break; + } + } + + if (fibMem) fii->FI_Unload(fibMem); + return hbmpDes; +} + +void DrawBitmapPart(HDC hdcMem, HBITMAP hbmpPart, RECT *rcDes, TransformationMode transfMode) +{ + if (!hbmpPart) + return; + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + + BITMAP bitmap; + GetObject(hbmpPart, sizeof(bitmap), &bitmap); + int iBmpWidth = bitmap.bmWidth; + int iBmpHeight = bitmap.bmHeight; + + int iDesWidth = rcDes->right - rcDes->left; + int iDesHeight = rcDes->bottom - rcDes->top; + + SelectObject(hdcMem, hbmpPart); + + switch (transfMode) + { + case TM_NONE: + case TM_STRECH_ALL: + case TM_STRECH_HORIZONTAL: + case TM_STRECH_VERTICAL: + { + AlphaBlend(skin.hdc, rcDes->left, rcDes->top, iBmpWidth, iBmpHeight, hdcMem, 0, 0, iBmpWidth, iBmpHeight, blend); + break; + } + case TM_CENTRE: + { + int iPosX = rcDes->left + ((iDesWidth - iBmpWidth) / 2); + int iPosY = rcDes->top + ((iDesHeight - iBmpHeight) / 2); + AlphaBlend(skin.hdc, iPosX, iPosY, iBmpWidth, iBmpHeight, hdcMem, 0, 0, iBmpWidth, iBmpHeight, blend); + break; + } + case TM_TILE_ALL: + { + int iRepX = iDesWidth / iBmpWidth; + int iRepY = iDesHeight / iBmpHeight; + int iEndX = iDesWidth % iBmpWidth; + int iEndY = iDesHeight % iBmpHeight; + int x,y; + + for (y = 0; y < iRepY; y++) + { + for (x = 0; x < iRepX; x++) + { + AlphaBlend(skin.hdc, rcDes->left + (x * iBmpWidth), rcDes->top + (y * iBmpHeight), iBmpWidth, iBmpHeight, hdcMem, 0, 0, iBmpWidth, iBmpHeight, blend); + } + + AlphaBlend(skin.hdc, rcDes->left + (x * iBmpWidth), rcDes->top + (y * iBmpHeight), iEndX, iBmpHeight, hdcMem, 0, 0, iEndX, iBmpHeight, blend); + } + + for (x = 0; x < iRepX; x++) + { + AlphaBlend(skin.hdc, rcDes->left + (x * iBmpWidth), rcDes->top + (y * iBmpHeight), iBmpWidth, iEndY, hdcMem, 0, 0, iBmpWidth, iEndY, blend); + } + + AlphaBlend(skin.hdc, rcDes->left + (x * iBmpWidth), rcDes->top + (y * iBmpHeight), iEndX, iEndY, hdcMem, 0, 0, iEndX, iEndY, blend); + break; + } + case TM_TILE_HORIZONTAL: + { + int iRepX = iDesWidth / iBmpWidth; + int iEndX = iDesWidth % iBmpWidth; + int x; + + for (x = 0; x < iRepX; x++) + { + AlphaBlend(skin.hdc, rcDes->left + (x * iBmpWidth), rcDes->top, iBmpWidth, iDesHeight, hdcMem, 0, 0, iBmpWidth, iDesHeight, blend); + } + + AlphaBlend(skin.hdc, rcDes->left + (x * iBmpWidth), rcDes->top, iEndX, iDesHeight, hdcMem, 0, 0, iEndX, iDesHeight, blend); + break; + } + case TM_TILE_VERTICAL: + { + int iRepY = iDesHeight / iBmpHeight; + int iEndY = iDesHeight % iBmpHeight; + int y; + + for(y = 0; y < iRepY; y++) + { + AlphaBlend(skin.hdc, rcDes->left, rcDes->top + (y * iBmpHeight), iDesWidth, iBmpHeight, hdcMem, 0, 0, iDesWidth, iBmpHeight, blend); + } + + AlphaBlend(skin.hdc, rcDes->left, rcDes->top + (y * iBmpHeight), iDesWidth, iEndY, hdcMem, 0, 0, iDesWidth, iEndY, blend); + break; + } + } +} + +void CreateFromBitmaps(bool bServiceTip) +{ + int rcWidth, rcHeight; + int iCentWidth, iCentHeight; + int iBmpWidth, iBmpHeight; + int top, right, bottom, left; + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + + for (int i = 0; i < SKIN_ITEMS_COUNT; i++) + { + if (i == SKIN_ITEM_SIDEBAR && (!opt.iSidebarWidth || bServiceTip)) + continue; + + TCHAR* tszFileName = opt.szImgFile[i]; + if (tszFileName && *tszFileName != 0) + { + FIBITMAP *fib = NULL; + if (!skin.bCached) + { + FIBITMAP *fibLoad = (FIBITMAP *)CallService(MS_IMG_LOAD, (WPARAM)tszFileName, (LPARAM)(IMGL_TCHAR | IMGL_RETURNDIB)); + if (!fibLoad) continue; + + if (fii->FI_GetBPP(fibLoad) != 32) + fib = fii->FI_ConvertTo32Bits(fibLoad); + else + fib = fibLoad; + + if (fib != fibLoad) + fii->FI_Unload(fibLoad); + + skin.fib[i] = fib; + } + else + { + fib = skin.fib[i]; + } + + // destination rectangle size + if (i == SKIN_ITEM_BG) + { + rcWidth = skin.iWidth; + rcHeight = skin.iHeight; + } + else if (i == SKIN_ITEM_SIDEBAR) + { + rcWidth = opt.iSidebarWidth; + rcHeight = skin.iHeight; + } + + // bitmap size + iBmpWidth = fii->FI_GetWidth(fib); + iBmpHeight = fii->FI_GetHeight(fib); + + // margins + top = opt.margins[i].top < iBmpHeight ? opt.margins[i].top : 0; + right = opt.margins[i].right < iBmpWidth ? opt.margins[i].right : 0; + bottom = opt.margins[i].bottom < iBmpHeight ? opt.margins[i].bottom : 0; + left = opt.margins[i].left < iBmpWidth ? opt.margins[i].left : 0; + + // centre area size + iCentWidth = max(rcWidth - left - right, 0); + iCentHeight = max(rcHeight - top - bottom, 0); + + FIBITMAP *fibCentre = NULL, *fibMem = NULL; + if (opt.margins[i].left || opt.margins[i].top || opt.margins[i].right || opt.margins[i].bottom) + { + // create corners bitmaps + if (!skin.bCached) + { + if (top > 0 && left > 0) // TL + { + fibMem = fii->FI_Copy(fib, 0, 0, left, top); + skin.hbmpSkinParts[i][SP_CORNER_TL] = fii->FI_CreateHBITMAPFromDIB(fibMem); + if (fibMem) fii->FI_Unload(fibMem); + } + if (top > 0 && right > 0) // TR + { + fibMem = fii->FI_Copy(fib, iBmpWidth - right, 0, iBmpWidth, top); + skin.hbmpSkinParts[i][SP_CORNER_TR] = fii->FI_CreateHBITMAPFromDIB(fibMem); + if (fibMem) fii->FI_Unload(fibMem); + } + if (bottom > 0 && right > 0) // BR + { + fibMem = fii->FI_Copy(fib, iBmpWidth - right, iBmpHeight - bottom, iBmpWidth, iBmpHeight); + skin.hbmpSkinParts[i][SP_CORNER_BR] = fii->FI_CreateHBITMAPFromDIB(fibMem); + if (fibMem) fii->FI_Unload(fibMem); + } + if (bottom > 0 && left > 0) // BL + { + fibMem = fii->FI_Copy(fib, 0, iBmpHeight - bottom, left, iBmpHeight); + skin.hbmpSkinParts[i][SP_CORNER_BL] = fii->FI_CreateHBITMAPFromDIB(fibMem); + if (fibMem) fii->FI_Unload(fibMem); + } + } + + // create edge parts bitmaps + if (top > 0 && iCentWidth > 0) // top + { + fibMem = fii->FI_Copy(fib, left, 0, iBmpWidth - right, top); + skin.hbmpSkinParts[i][SP_EDGE_TOP] = CreateBitmapPart(fibMem, iBmpWidth - left - right, top, iCentWidth, top, opt.transfMode[i]); + if (fibMem) fii->FI_Unload(fibMem); + } + if (right > 0 && iCentHeight > 0) // right + { + fibMem = fii->FI_Copy(fib, iBmpWidth - right, top, iBmpWidth, iBmpHeight - bottom); + skin.hbmpSkinParts[i][SP_EDGE_RIGHT] = CreateBitmapPart(fibMem, right, iBmpHeight - top - bottom, right, iCentHeight, opt.transfMode[i]); + if (fibMem) fii->FI_Unload(fibMem); + } + if (bottom > 0 && iCentWidth > 0) // bottom + { + fibMem = fii->FI_Copy(fib, left, iBmpHeight - bottom, iBmpWidth - right, iBmpHeight); + skin.hbmpSkinParts[i][SP_EDGE_BOTTOM] = CreateBitmapPart(fibMem, iBmpWidth - left - right, bottom, iCentWidth, bottom, opt.transfMode[i]); + if (fibMem) fii->FI_Unload(fibMem); + } + if (left > 0 && iCentHeight > 0) // left + { + fibMem = fii->FI_Copy(fib, 0, top, left, iBmpHeight - bottom); + skin.hbmpSkinParts[i][SP_EDGE_LEFT] = CreateBitmapPart(fibMem, left, iBmpHeight - top - bottom, left, iCentHeight, opt.transfMode[i]); + if (fibMem) fii->FI_Unload(fibMem); + } + + fibCentre = fii->FI_Copy(fib, left, top, iBmpWidth - right, iBmpHeight - bottom); + if (fibCentre) + { + fib = fibCentre; + iBmpWidth = fii->FI_GetWidth(fib); + iBmpHeight = fii->FI_GetHeight(fib); + } + } + + // create centre area bitmap + skin.hbmpSkinParts[i][SP_CENTRE_AREA] = CreateBitmapPart(fib, iBmpWidth, iBmpHeight, iCentWidth, iCentHeight, opt.transfMode[i]); + if (fibCentre) + fii->FI_Unload(fibCentre); + + if (i == SKIN_ITEM_SIDEBAR) + { + int limit = skin.bCached ? SP_CORNER_TL : SKIN_PARTS_COUNT; // don't premultiply corner bitmaps multiple times + for (int j = 0; j < limit; j++) + { + if (skin.hbmpSkinParts[i][j]) + fii->FI_Premultiply(skin.hbmpSkinParts[i][j]); + } + } + + HDC hdcMem = CreateCompatibleDC(0); + RECT rc = {0}; + + if (skin.hbmpSkinParts[i][SP_CENTRE_AREA]) + { + SetRect(&rc, left, top, rcWidth - right, rcHeight - bottom); + DrawBitmapPart(hdcMem, skin.hbmpSkinParts[i][SP_CENTRE_AREA], &rc, opt.transfMode[i]); + } + + if (opt.margins[i].left || opt.margins[i].top || opt.margins[i].right || opt.margins[i].bottom) + { + // draw edge parts + if (skin.hbmpSkinParts[i][SP_EDGE_TOP]) // top + { + SetRect(&rc, left, 0, rcWidth - right, top); + DrawBitmapPart(hdcMem, skin.hbmpSkinParts[i][SP_EDGE_TOP], &rc, opt.transfMode[i]); + } + if (skin.hbmpSkinParts[i][SP_EDGE_RIGHT]) // right + { + SetRect(&rc, rcWidth - right, top, rcWidth, rcHeight - bottom); + DrawBitmapPart(hdcMem, skin.hbmpSkinParts[i][SP_EDGE_RIGHT], &rc, opt.transfMode[i]); + } + if (skin.hbmpSkinParts[i][SP_EDGE_BOTTOM]) // bottom + { + SetRect(&rc, left, rcHeight - bottom, rcWidth - right, rcHeight); + DrawBitmapPart(hdcMem, skin.hbmpSkinParts[i][SP_EDGE_BOTTOM], &rc, opt.transfMode[i]); + } + if (skin.hbmpSkinParts[i][SP_EDGE_LEFT]) // left + { + SetRect(&rc, 0, top, left, rcHeight - bottom); + DrawBitmapPart(hdcMem, skin.hbmpSkinParts[i][SP_EDGE_LEFT], &rc, opt.transfMode[i]); + } + + // draw corners + if (skin.hbmpSkinParts[i][SP_CORNER_TL]) // TL + { + SelectObject(hdcMem, skin.hbmpSkinParts[i][SP_CORNER_TL]); + AlphaBlend(skin.hdc, 0, 0, left, top, hdcMem, 0, 0, left, top, blend); + } + if (skin.hbmpSkinParts[i][SP_CORNER_TR]) // TR + { + SelectObject(hdcMem, skin.hbmpSkinParts[i][SP_CORNER_TR]); + AlphaBlend(skin.hdc, rcWidth - right, 0, right, top, hdcMem, 0, 0, right, top, blend); + } + if (skin.hbmpSkinParts[i][SP_CORNER_BR]) // BR + { + SelectObject(hdcMem, skin.hbmpSkinParts[i][SP_CORNER_BR]); + AlphaBlend(skin.hdc, rcWidth - right, rcHeight - bottom, right, bottom, hdcMem, 0, 0, right, bottom, blend); + } + if (skin.hbmpSkinParts[i][SP_CORNER_BL]) // BL + { + SelectObject(hdcMem, skin.hbmpSkinParts[i][SP_CORNER_BL]); + AlphaBlend(skin.hdc, 0, rcHeight - bottom, left, bottom, hdcMem, 0, 0, left, bottom, blend); + } + } + + for (int j = 0; j < SP_CORNER_TL; j++) + { + if (skin.hbmpSkinParts[i][j]) + { + DeleteObject(skin.hbmpSkinParts[i][j]); + skin.hbmpSkinParts[i][j] = NULL; + } + } + + if (MyUpdateLayeredWindow) + skin.bNeedLayerUpdate = true; + + DeleteDC(hdcMem); + } + } + + skin.bCached = true; +} + +void SolidColorFill(bool bServiceTip) +{ + RECT rc = {0}; + rc.right = skin.iWidth; + rc.bottom = skin.iHeight; + HBRUSH hBrush = CreateSolidBrush(opt.colBg); + FillRect(skin.hdc, &rc, hBrush); + DeleteObject(hBrush); + + if (opt.iSidebarWidth > 0 && !bServiceTip) + { + rc.right = opt.iSidebarWidth; + hBrush = CreateSolidBrush(opt.colSidebar); + FillRect(skin.hdc, &rc, hBrush); + DeleteObject(hBrush); + } +} + +void CreateSkinBitmap(int iWidth, int iHeight, bool bServiceTip) +{ + if (skin.hBitmap) DeleteObject(skin.hBitmap); + if (skin.hdc) DeleteDC(skin.hdc); + skin.hBitmap = NULL; + skin.hdc = NULL; + + skin.iWidth = iWidth; + skin.iHeight = iHeight; + skin.bNeedLayerUpdate = false; + + BITMAPINFO bi; + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = skin.iWidth; + bi.bmiHeader.biHeight = -skin.iHeight; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + skin.hBitmap = (HBITMAP)CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void **)&skin.colBits, 0, 0); + + if (!skin.hBitmap) + return; + + skin.hdc = CreateCompatibleDC(0); + DeleteObject(SelectObject(skin.hdc, skin.hBitmap)); + + if (opt.skinMode == SM_COLORFILL) + { + SolidColorFill(bServiceTip); + } + else + { + CreateFromBitmaps(bServiceTip); + if (opt.iEnableColoring == 1) + ColorizeBitmap(); + } +} + +void DestroySkinBitmap() +{ + for (int i = 0; i < SKIN_ITEMS_COUNT; i++) + { + if (skin.fib[i]) + { + fii->FI_Unload(skin.fib[i]); + skin.fib[i] = NULL; + } + + for (int j = SP_CORNER_TL; j < SKIN_PARTS_COUNT; j++) + { + if (skin.hbmpSkinParts[i][j]) + { + DeleteObject(skin.hbmpSkinParts[i][j]); + skin.hbmpSkinParts[i][j] = NULL; + } + } + } + + skin.bCached = false; +} + +void SaveAlpha(LPRECT lpRect) +{ + if (skin.colSavedBits) + { + mir_free(skin.colSavedBits); + skin.colSavedBits = 0; + } + GdiFlush(); + + if (lpRect->left < 0) lpRect->left = 0; + if (lpRect->top < 0) lpRect->top = 0; + if (lpRect->right > skin.iWidth) lpRect->right = skin.iWidth; + if (lpRect->bottom > skin.iHeight) lpRect->bottom = skin.iHeight; + + int x = lpRect->left; + int y = lpRect->top; + int w = lpRect->right - lpRect->left; + int h = lpRect->bottom - lpRect->top; + + skin.colSavedBits = (COLOR32 *)mir_alloc(sizeof(COLOR32) * w * h); + COLOR32 *p1 = skin.colSavedBits; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= skin.iHeight) break; + COLOR32 *p2 = skin.colBits + (y+i)*skin.iWidth + x; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= skin.iWidth) break; + *p1++ = *p2++; + } + } +} + +void RestoreAlpha(LPRECT lpRect, BYTE alpha) +{ + if (!skin.colSavedBits) + return; + + GdiFlush(); + + if (lpRect->left < 0) lpRect->left = 0; + if (lpRect->top < 0) lpRect->top = 0; + if (lpRect->right > skin.iWidth) lpRect->right = skin.iWidth; + if (lpRect->bottom > skin.iHeight) lpRect->bottom = skin.iHeight; + + int x = lpRect->left; + int y = lpRect->top; + int w = lpRect->right - lpRect->left; + int h = lpRect->bottom - lpRect->top; + + COLOR32 *p1 = skin.colSavedBits; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= skin.iHeight) break; + COLOR32 *p2 = skin.colBits + (y+i)*skin.iWidth + x; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= skin.iWidth) break; + if ((*p1&0x00ffffff) != (*p2&0x00ffffff)) + { + *p2 |= (alpha << 24); + } + else + { + *p2 = (*p2&0x00ffffff) | (*p1&0xff000000); + } + ++p1; + ++p2; + } + } + + mir_free(skin.colSavedBits); + skin.colSavedBits = 0; +} + +BOOL IsAlphaTransparent(HBITMAP hBitmap) +{ + BITMAP bmp; + DWORD dwLen; + BYTE *p; + + GetObject(hBitmap, sizeof(bmp), &bmp); + + if (bmp.bmBitsPixel != 32) + return FALSE; + + dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8); + p = (BYTE *)mir_alloc(dwLen); + if (p == NULL) return FALSE; + memset(p, 0, dwLen); + + GetBitmapBits(hBitmap, dwLen, p); + + for (int y = 0; y < bmp.bmHeight; y++) + { + BYTE *px = p + bmp.bmWidth * 4 * y; + for (int x = 0; x < bmp.bmWidth; x++) + { + if (px[3] != 0) + { + mir_free(p); + return TRUE; + } + + px += 4; + } + } + + mir_free(p); + return FALSE; +} + +void DrawIconExAlpha(HDC hdc, int xLeft, int yTop, HICON hIcon, int cxWidth, int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags, bool bIsSmiley) +{ + bool restore = false; + + if (skin.bNeedLayerUpdate && !bIsSmiley) + { + ICONINFO icon; + if (GetIconInfo(hIcon, &icon)) + { + if (!IsAlphaTransparent(icon.hbmColor)) + { + RECT rc; + SetRect(&rc, xLeft, yTop, xLeft + cxWidth, yTop + cyWidth); + SaveAlpha(&rc); + restore = true; + } + + DeleteObject(icon.hbmColor); + DeleteObject(icon.hbmMask); + } + } + + DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, hbrFlickerFreeDraw, diFlags); + + if (skin.bNeedLayerUpdate && restore) + { + RECT rc; + SetRect(&rc, xLeft, yTop, xLeft + cxWidth, yTop + cyWidth); + RestoreAlpha(&rc); + } +} + +int DrawTextAlpha(HDC hdc, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat) +{ + RECT rc; + SetRect(&rc, lpRect->left - 1, lpRect->top - 1, lpRect->right + 1, lpRect->bottom + 1); + + if (skin.bNeedLayerUpdate) SaveAlpha(&rc); + int result = DrawText(hdc, lpString, nCount, lpRect, uFormat); + if (skin.bNeedLayerUpdate) RestoreAlpha(&rc); + + return result; +} + +static __forceinline COLOR32 rgba(COLOR32 r, COLOR32 g, COLOR32 b, COLOR32 a) +{ + return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); +} + +static __forceinline COLOR32 getr(COLOR32 c) +{ + return (c >> 16) & 0xff; +} + +static __forceinline COLOR32 getg(COLOR32 c) +{ + return (c >> 8) & 0xff; +} + +static __forceinline COLOR32 getb(COLOR32 c) +{ + return c & 0xff; +} + +static __forceinline COLOR32 geta(COLOR32 c) +{ + return (c >> 24) & 0xff; +} + +void PremultipleChannels() +{ + for (int i = 0; i < skin.iWidth * skin.iHeight; i++) + skin.colBits[i] = rgba( getr(skin.colBits[i])*geta(skin.colBits[i])/255, + getg(skin.colBits[i])*geta(skin.colBits[i])/255, + getb(skin.colBits[i])*geta(skin.colBits[i])/255, + geta(skin.colBits[i])); +} + +#define PU_DIV255(x) ((x)/255) + +void ColorizeBitmap() +{ + if (!skin.colBits) + return; + + GdiFlush(); + + int w = skin.iWidth; + int h = skin.iHeight; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(opt.colBg)) / 128.0; + float koef1g = (255 - getg(opt.colBg)) / 128.0; + float koef1b = (255 - getr(opt.colBg)) / 128.0; + + int br = - 255 + 2 * getb(opt.colBg); + int bg = - 255 + 2 * getg(opt.colBg); + int bb = - 255 + 2 * getr(opt.colBg); + + float koef2r = (getb(opt.colBg)) / 128.0; + float koef2g = (getg(opt.colBg)) / 128.0; + float koef2b = (getr(opt.colBg)) / 128.0; + + for (int i = 0; i < w * h; i++) + { + long alpha = geta(skin.colBits[i]); + COLOR32 cl = alpha ? getr(skin.colBits[i])*255/alpha : 0; + + skin.colBits[i] = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); + } +} + +// code from Clist Modern by FYR +HRGN CreateOpaqueRgn(BYTE level, bool bOpaque) +{ + if (!skin.colBits) + return NULL; + + GdiFlush(); + + RGBQUAD *buff = (RGBQUAD *)skin.colBits; + + int x,y; + unsigned int cRect = 64; + PRGNDATA pRgnData = (PRGNDATA)malloc(sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); + memset(pRgnData, 0, sizeof(RGNDATAHEADER)); + pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); + pRgnData->rdh.iType = RDH_RECTANGLES; + + for (y = 0; y < skin.iHeight; ++y) + { + bool inside = false; + bool lastin = false; + unsigned int entry = 0; + + for (x = 0; x < skin.iWidth; ++x) + { + inside = bOpaque ? (buff->rgbReserved > level) : (buff->rgbReserved < level); + ++buff; + + if (inside != lastin) + { + if (inside) + { + lastin = true; + entry = x; + } + else + { + if (pRgnData->rdh.nCount == cRect) + { + cRect = cRect + 64; + pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); + } + + SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, skin.iHeight - y, x, skin.iHeight - y + 1); + pRgnData->rdh.nCount++; + lastin = false; + } + } + } + + if (lastin) + { + if (pRgnData->rdh.nCount == cRect) + { + cRect = cRect + 64; + pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); + } + + SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, skin.iHeight - y, x, skin.iHeight - y + 1); + pRgnData->rdh.nCount++; + } + } + + HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData); + free(pRgnData); + return hRgn; +} \ No newline at end of file diff --git a/plugins/TipperYM/src/bitmap_func.h b/plugins/TipperYM/src/bitmap_func.h new file mode 100644 index 0000000000..e6ffbc4880 --- /dev/null +++ b/plugins/TipperYM/src/bitmap_func.h @@ -0,0 +1,71 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _BITMAP_FUNC_INC +#define _BITMAP_FUNC_INC + +// tooltip skin +#define SKIN_ITEMS_COUNT 2 +#define SKIN_PARTS_COUNT 9 +#define SKIN_ITEM_BG 0 +#define SKIN_ITEM_SIDEBAR 1 + +// skin parts +#define SP_CENTRE_AREA 0 +#define SP_EDGE_TOP 1 +#define SP_EDGE_RIGHT 2 +#define SP_EDGE_BOTTOM 3 +#define SP_EDGE_LEFT 4 +#define SP_CORNER_TL 5 +#define SP_CORNER_TR 6 +#define SP_CORNER_BR 7 +#define SP_CORNER_BL 8 + +// image paint options +typedef enum { + TM_NONE = 0, TM_CENTRE = 1, TM_STRECH_ALL = 2, TM_STRECH_HORIZONTAL = 3, TM_STRECH_VERTICAL = 4, + TM_TILE_ALL = 5, TM_TILE_HORIZONTAL = 6, TM_TILE_VERTICAL = 7 +} TransformationMode; + +typedef unsigned long COLOR32; +typedef struct { + HDC hdc; + HBITMAP hBitmap; + HBITMAP hbmpSkinParts[SKIN_ITEMS_COUNT][SKIN_PARTS_COUNT]; + FIBITMAP *fib[SKIN_ITEMS_COUNT]; + COLOR32 *colBits; + COLOR32 *colSavedBits; + int iWidth; + int iHeight; + bool bNeedLayerUpdate; + bool bCached; +} TOOLTIPSKIN; + +void CreateSkinBitmap(int iWidth, int iHeight, bool bServiceTip); +void DestroySkinBitmap(); +int DrawTextAlpha(HDC hdc, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat); +void DrawIconExAlpha(HDC hdc, int xLeft, int yTop, HICON hIcon, int cxWidth, int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags, bool bIsSmiley); +void SaveAlpha(LPRECT lpRect); +void RestoreAlpha(LPRECT lpRect, BYTE alpha = 0xff); +void PremultipleChannels(); +void ColorizeBitmap(); +HRGN CreateOpaqueRgn(BYTE level, bool bOpaque); + +#endif diff --git a/plugins/TipperYM/src/common.h b/plugins/TipperYM/src/common.h new file mode 100644 index 0000000000..9098589d1c --- /dev/null +++ b/plugins/TipperYM/src/common.h @@ -0,0 +1,105 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#pragma once + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows XP or later. +#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. +#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. +#endif + +#define MIRANDA_VER 0x0A00 + +#define _CRT_SECURE_NO_WARNINGS + +#include + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "m_tipper.h" +#include "m_fingerprint.h" +#include "m_flags.h" +#include "m_folders.h" +#include "m_metacontacts.h" +#include "m_variables.h" +#include "m_smileyadd.h" + +// {8392DF1D-9090-4f8e-9DF6-2FE058EDD800} +#define MIID_TIPPER { 0x8392df1d, 0x9090, 0x4f8e, { 0x9d, 0xf6, 0x2f, 0xe0, 0x58, 0xed, 0xd8, 0x00 } } + +#define MODULE "Tipper" +#define MODULE_ITEMS "Tipper_Items" +#define DEFAULT_SKIN_FOLDER "Skins\\Tipper" + +extern HMODULE hInst; + +extern HFONT hFontTitle, hFontLabels, hFontValues, hFontTrayTitle; +extern COLORREF colTitle, colLabels, colBg, colValues; + +extern int iCodePage; +extern char szMetaModuleName[256]; + +extern FI_INTERFACE *fii; \ No newline at end of file diff --git a/plugins/TipperYM/src/message_pump.cpp b/plugins/TipperYM/src/message_pump.cpp new file mode 100644 index 0000000000..7032ad84b2 --- /dev/null +++ b/plugins/TipperYM/src/message_pump.cpp @@ -0,0 +1,413 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "message_pump.h" +#include "popwin.h" +#include "options.h" +#include "str_utils.h" +#include "subst.h" + +BOOL (WINAPI *MySetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD) = 0; +BOOL (WINAPI *MyUpdateLayeredWindow)(HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags) = 0; +BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags) = 0; +HMONITOR (WINAPI *MyMonitorFromPoint)(POINT, DWORD); +BOOL (WINAPI *MyGetMonitorInfo)(HMONITOR, LPMONITORINFO); +HRESULT (WINAPI *MyDwmEnableBlurBehindWindow)(HWND hWnd, DWM_BLURBEHIND *pBlurBehind) = 0; + +unsigned int uintMessagePumpThreadId = 0; +POINT pt = {-1}; +UINT WaitForContentTimerID = 0; +bool bAvatarReady = false; +bool bStatusMsgReady = false; + +__inline bool IsContactTooltip(CLCINFOTIPEX *clc) +{ + return (clc->szProto || clc->swzText) == false; +} + +void CALLBACK TimerProcWaitForContent(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + KillTimer(0, WaitForContentTimerID); + WaitForContentTimerID = 0; + bStatusMsgReady = true; + bAvatarReady = true; + PostMPMessage(MUM_CREATEPOPUP, 0, 0); +} + +bool NeedWaitForContent(CLCINFOTIPEX *clcitex) +{ + bool bNeedWait = false; + + if (opt.bWaitForContent && IsContactTooltip(clcitex)) + { + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)clcitex->hItem, 0); + if (!szProto) return false; + + if (opt.bWaitForStatusMsg && !bStatusMsgReady) + { + DBDeleteContactSetting(clcitex->hItem, MODULE, "TempStatusMsg"); + if (CanRetrieveStatusMsg(clcitex->hItem, szProto) && + CallContactService(clcitex->hItem, PSS_GETAWAYMSG, 0, 0)) + { + if (WaitForContentTimerID) + KillTimer(0, WaitForContentTimerID); + + WaitForContentTimerID = SetTimer(NULL, 0, WAIT_TIMER_INTERVAL, TimerProcWaitForContent); + bNeedWait = true; + } + } + + if (opt.bWaitForAvatar && !bAvatarReady && + CallProtoService(szProto, PS_GETAVATARCAPS, AF_ENABLED, 0)) + { + DBVARIANT dbv; + if (!DBGetContactSettingString(clcitex->hItem, "ContactPhoto", "File", &dbv)) + { + if (!strstr(dbv.pszVal, ".xml")) + { + AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)clcitex->hItem, 0); + if (!ace) + { + if (WaitForContentTimerID) + KillTimer(0, WaitForContentTimerID); + + WaitForContentTimerID = SetTimer(NULL, 0, WAIT_TIMER_INTERVAL, TimerProcWaitForContent); + bNeedWait = true; + } + else + bAvatarReady = true; + } + else + bAvatarReady = true; + + DBFreeVariant(&dbv); + } + else + bAvatarReady = true; + } + + } + + return bNeedWait; +} + +unsigned int CALLBACK MessagePumpThread(void *param) +{ + HWND hwndTip = 0; + CLCINFOTIPEX *clcitex = 0; + + MSG hwndMsg = {0}; + while (GetMessage(&hwndMsg, 0, 0, 0) > 0 && !Miranda_Terminated()) + { + if (!IsDialogMessage(hwndMsg.hwnd, &hwndMsg)) + { + switch (hwndMsg.message) + { + case MUM_CREATEPOPUP: + { + if (!clcitex) + { + if (hwndMsg.lParam) clcitex = (CLCINFOTIPEX *)hwndMsg.lParam; + else break; + } + + if (!NeedWaitForContent(clcitex)) + { + if (hwndTip) MyDestroyWindow(hwndTip); + hwndTip = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, POP_WIN_CLASS, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, hInst, (LPVOID)clcitex); + + if (clcitex) + { + mir_free(clcitex); + clcitex = 0; + } + + bStatusMsgReady = false; + bAvatarReady = false; + } + break; + } + case MUM_DELETEPOPUP: + { + if (hwndTip) + { + MyDestroyWindow(hwndTip); + hwndTip = 0; + } + + if (clcitex) + { + mir_free(clcitex); + clcitex = 0; + } + + bStatusMsgReady = false; + bAvatarReady = false; + break; + } + case MUM_GOTSTATUS: + { + HANDLE hContact = (HANDLE)hwndMsg.wParam; + TCHAR *swzMsg = (TCHAR *)hwndMsg.lParam; + + if (opt.bWaitForContent && + bStatusMsgReady == false && + clcitex && + clcitex->hItem == hContact) + { + if (WaitForContentTimerID) + { + KillTimer(0, WaitForContentTimerID); + WaitForContentTimerID = 0; + } + + if (swzMsg) + { + DBWriteContactSettingTString(clcitex->hItem, MODULE, "TempStatusMsg", swzMsg); + mir_free(swzMsg); + } + + bStatusMsgReady = true; + PostMPMessage(MUM_CREATEPOPUP, 0, 0); + } + else if (!opt.bWaitForContent && hwndTip) + SendMessage(hwndTip, PUM_SETSTATUSTEXT, (WPARAM)hContact, (LPARAM)swzMsg); + else if (swzMsg) + mir_free(swzMsg); + + break; + } + case MUM_GOTXSTATUS: + { + if (hwndTip && !opt.bWaitForContent) + SendMessage(hwndTip, PUM_SHOWXSTATUS, hwndMsg.wParam, 0); + break; + } + case MUM_GOTAVATAR: + { + HANDLE hContact = (HANDLE)hwndMsg.wParam; + + if (opt.bWaitForContent && + bAvatarReady == false && + clcitex && + clcitex->hItem == hContact) + { + if (WaitForContentTimerID) + { + KillTimer(0, WaitForContentTimerID); + WaitForContentTimerID = 0; + } + + bAvatarReady = true; + PostMPMessage(MUM_CREATEPOPUP, 0, 0); + } + else if (!opt.bWaitForContent && hwndTip) + SendMessage(hwndTip, PUM_SETAVATAR, hwndMsg.wParam, 0); + + break; + } + default: + { + TranslateMessage(&hwndMsg); + DispatchMessage(&hwndMsg); + break; + } + } + } + } + + return 0; +} + +void PostMPMessage(UINT msg, WPARAM wParam, LPARAM lParam) +{ + PostThreadMessage(uintMessagePumpThreadId, msg, wParam, lParam); +} + +void InitMessagePump() +{ + WNDCLASSEX wcl = {0}; + wcl.cbSize = sizeof(wcl); + wcl.lpfnWndProc = PopupWindowProc; + wcl.hInstance = hInst; + wcl.hCursor = LoadCursor(NULL, IDC_ARROW); + wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); + wcl.lpszClassName = POP_WIN_CLASS; + RegisterClassEx(&wcl); + + HMODULE hUserDll = LoadLibrary(_T("user32.dll")); + if (hUserDll) + { + MySetLayeredWindowAttributes = (BOOL (WINAPI *)(HWND,COLORREF,BYTE,DWORD))GetProcAddress(hUserDll, "SetLayeredWindowAttributes"); + MyUpdateLayeredWindow = (BOOL (WINAPI *)(HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags))GetProcAddress(hUserDll, "UpdateLayeredWindow"); + MyAnimateWindow =(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(hUserDll, "AnimateWindow"); + MyMonitorFromPoint = (HMONITOR (WINAPI*)(POINT, DWORD))GetProcAddress(hUserDll, "MonitorFromPoint"); + MyGetMonitorInfo = (BOOL (WINAPI*)(HMONITOR, LPMONITORINFO))GetProcAddress(hUserDll, "GetMonitorInfoW"); + + } + + HMODULE hDwmapiDll = LoadLibrary(_T("dwmapi.dll")); + if (hDwmapiDll) + MyDwmEnableBlurBehindWindow = (HRESULT (WINAPI *)(HWND, DWM_BLURBEHIND *))GetProcAddress(hDwmapiDll, "DwmEnableBlurBehindWindow"); + + CloseHandle(mir_forkthreadex(MessagePumpThread, NULL, &uintMessagePumpThreadId)); +} + +void DeinitMessagePump() +{ + PostMPMessage(WM_QUIT, 0, 0); + UnregisterClass(POP_WIN_CLASS, hInst); +} + +INT_PTR ShowTip(WPARAM wParam, LPARAM lParam) +{ + CLCINFOTIP *clcit = (CLCINFOTIP *)lParam; + HWND clist = (HWND)CallService(MS_CLUI_GETHWNDTREE, 0, 0); + + if (clcit->isGroup) return 0; // no group tips (since they're pretty useless) + if (clcit->isTreeFocused == 0 && opt.bShowNoFocus == false && clist == WindowFromPoint(clcit->ptCursor)) return 0; + if (clcit->ptCursor.x == pt.x && clcit->ptCursor.y == pt.y) return 0; + pt.x = pt.y = 0; + + CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)mir_alloc(sizeof(CLCINFOTIPEX)); + memcpy(clcit2, clcit, sizeof(CLCINFOTIP)); + clcit2->cbSize = sizeof(CLCINFOTIPEX); + clcit2->szProto = NULL; + clcit2->swzText = NULL; + + if (wParam) // wParam is char pointer containing text - e.g. status bar tooltip + { + clcit2->swzText = a2t((char *)wParam); + GetCursorPos(&clcit2->ptCursor); + } + + PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2); + return 1; +} + +int ShowTipHook(WPARAM wParam, LPARAM lParam) +{ + ShowTip(wParam, lParam); + return 0; +} + +INT_PTR ShowTipW(WPARAM wParam, LPARAM lParam) +{ + CLCINFOTIP *clcit = (CLCINFOTIP *)lParam; + HWND clist = (HWND)CallService(MS_CLUI_GETHWNDTREE, 0, 0); + + if (clcit->isGroup) return 0; // no group tips (since they're pretty useless) + if (clcit->isTreeFocused == 0 && opt.bShowNoFocus == false && clist == WindowFromPoint(clcit->ptCursor)) return 0; + if (clcit->ptCursor.x == pt.x && clcit->ptCursor.y == pt.y) return 0; + pt.x = pt.y = -1; + + CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)mir_alloc(sizeof(CLCINFOTIPEX)); + memcpy(clcit2, clcit, sizeof(CLCINFOTIP)); + clcit2->cbSize = sizeof(CLCINFOTIPEX); + clcit2->szProto = NULL; + clcit2->swzText = NULL; + + if (wParam) // wParam is char pointer containing text - e.g. status bar tooltip + { + clcit2->swzText = mir_tstrdup((TCHAR *)wParam); + GetCursorPos(&clcit2->ptCursor); + } + + PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2); + return 1; +} + +INT_PTR HideTip(WPARAM wParam, LPARAM lParam) +{ + //CLCINFOTIP *clcit = (CLCINFOTIP *)lParam; + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + return 0; + + GetCursorPos(&pt); + PostMPMessage(MUM_DELETEPOPUP, 0, 0); + return 1; +} + +int HideTipHook(WPARAM wParam, LPARAM lParam) +{ + HideTip(wParam, lParam); + return 0; +} + +int ProtoAck(WPARAM wParam, LPARAM lParam) +{ + ACKDATA *ack = (ACKDATA *)lParam; + if (ack->result != ACKRESULT_SUCCESS) + return 0; + + if (ack->type == ACKTYPE_AWAYMSG) { + TCHAR* tszMsg = ( TCHAR* )ack->lParam; + if ( lstrlen(tszMsg)) + PostMPMessage(MUM_GOTSTATUS, (WPARAM)ack->hContact, (LPARAM)mir_tstrdup(tszMsg)); + } + else if (ack->type == ICQACKTYPE_XSTATUS_RESPONSE) + { + PostMPMessage(MUM_GOTXSTATUS, (WPARAM)ack->hContact, 0); + } + + return 0; +} + +int AvatarChanged(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + PostMPMessage(MUM_GOTAVATAR, (WPARAM)hContact, 0); + return 0; +} + +int FramesShowSBTip(WPARAM wParam, LPARAM lParam) +{ + if (opt.bStatusBarTips) + { + char *szProto = (char *)wParam; + + CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)mir_alloc(sizeof(CLCINFOTIPEX)); + memset(clcit2, 0, sizeof(CLCINFOTIPEX)); + clcit2->cbSize = sizeof(CLCINFOTIPEX); + clcit2->szProto= szProto; // assume static string + GetCursorPos(&clcit2->ptCursor); + + PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2); + return 1; + } + return 0; +} + +int FramesHideSBTip(WPARAM wParam, LPARAM lParam) +{ + if (opt.bStatusBarTips) + { + PostMPMessage(MUM_DELETEPOPUP, 0, 0); + return 1; + } + return 0; +} + +BOOL MyDestroyWindow(HWND hwnd) +{ + SendMessage(hwnd, PUM_FADEOUTWINDOW, 0, 0); + return DestroyWindow(hwnd); +} \ No newline at end of file diff --git a/plugins/TipperYM/src/message_pump.h b/plugins/TipperYM/src/message_pump.h new file mode 100644 index 0000000000..a8858e3865 --- /dev/null +++ b/plugins/TipperYM/src/message_pump.h @@ -0,0 +1,71 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _MESSAGE_PUMP_INC +#define _MESSAGE_PUMP_INC + +#define WAIT_TIMER_INTERVAL 500 + +#define MUM_CREATEPOPUP (WM_USER + 0x011) +#define MUM_DELETEPOPUP (WM_USER + 0x012) +#define MUM_GOTSTATUS (WM_USER + 0x013) +#define MUM_GOTAVATAR (WM_USER + 0x014) +#define MUM_GOTXSTATUS (WM_USER + 0x015) + +extern BOOL (WINAPI *MySetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); +extern BOOL (WINAPI *MyUpdateLayeredWindow)(HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags); +extern BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags); +extern HMONITOR (WINAPI *MyMonitorFromPoint)(POINT, DWORD); +extern BOOL (WINAPI *MyGetMonitorInfo)(HMONITOR, LPMONITORINFO); + +#define DWM_BB_ENABLE 0x00000001 +#define DWM_BB_BLURREGION 0x00000002 +#define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 +struct DWM_BLURBEHIND +{ + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; +}; + +extern HRESULT (WINAPI *MyDwmEnableBlurBehindWindow)(HWND hWnd, DWM_BLURBEHIND *pBlurBehind); + +void InitMessagePump(); +void DeinitMessagePump(); + +INT_PTR ShowTip(WPARAM wParam, LPARAM lParam); +INT_PTR ShowTipW(WPARAM wParam, LPARAM lParam); +INT_PTR HideTip(WPARAM wParam, LPARAM lParam); + +int ShowTipHook(WPARAM wParam, LPARAM lParam); +int HideTipHook(WPARAM wParam, LPARAM lParam); + +int FramesShowSBTip(WPARAM wParam, LPARAM lParam); +int FramesHideSBTip(WPARAM wParam, LPARAM lParam); + +int ProtoAck(WPARAM wParam, LPARAM lParam); +int AvatarChanged(WPARAM wParam, LPARAM lParam); + +BOOL MyDestroyWindow(HWND hwnd); +void PostMPMessage(UINT msg, WPARAM, LPARAM); + + +#endif diff --git a/plugins/TipperYM/src/mir_smileys.cpp b/plugins/TipperYM/src/mir_smileys.cpp new file mode 100644 index 0000000000..5af05c4b22 --- /dev/null +++ b/plugins/TipperYM/src/mir_smileys.cpp @@ -0,0 +1,514 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci +Copyright (C) 2007-2010 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "options.h" +#include "mir_smileys.h" + + + +void *mir_alloc0(size_t size) +{ + void *ptr = mir_alloc(size); + if (ptr) memset(ptr, 0, size); + + return ptr; +} + +int InitTipperSmileys() +{ + // Register smiley category + if (ServiceExists(MS_SMILEYADD_REGISTERCATEGORY)) + { + SMADD_REGCAT rc; + rc.cbSize = sizeof(rc); + rc.name = "tipper"; + rc.dispname = Translate("Tipper smileys"); + CallService(MS_SMILEYADD_REGISTERCATEGORY, 0, (LPARAM)&rc); + } + + return 0; +} + +SMILEYPARSEINFO Smileys_PreParse(LPCTSTR lpString, int nCount, const char *protocol) +{ + if (!(opt.iSmileyAddFlags & SMILEYADD_ENABLE)) + return NULL; + + if (nCount == -1) + nCount = (int)lstrlen(lpString); + + SMILEYPARSEINFO info = (SMILEYPARSEINFO) mir_alloc0(sizeof(tagSMILEYPARSEINFO)); + info->pieces = ReplaceSmileys(lpString, nCount, protocol, &info->max_height); + + if (!info->pieces) + { + mir_free(info); + return NULL; + } + + return info; +} + +void Smileys_FreeParse(SMILEYPARSEINFO parseInfo) +{ + if (parseInfo != NULL) + { + if (parseInfo->pieces != NULL) + DestroySmileyList(parseInfo->pieces); + + mir_free(parseInfo); + } +} + +// Similar to DrawText win32 api function +// Pass uFormat | DT_CALCRECT to calc rectangle to be returned by lpRect +// parseInfo is optional (pass NULL and it will be calculated and deleted inside function +int Smileys_DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, const char *protocol, SMILEYPARSEINFO parseInfo) +{ + int result; + + if (nCount == -1) + nCount = (int)lstrlen(lpString); + + if (uFormat & DT_CALCRECT) + { + SIZE text_size = GetTextSize(hDC, lpString, parseInfo, uFormat, parseInfo->max_height, (lpRect->right - lpRect->left)); + lpRect->bottom = text_size.cy; + + if (text_size.cx < lpRect->right - lpRect->left) + { + if (uFormat & DT_RIGHT) + lpRect->left = lpRect->right - text_size.cx; + else + lpRect->right = lpRect->left + text_size.cx; + } + + result = text_size.cy; + } + else + { + // Draw + if (parseInfo->pieces == NULL) + { + result = DrawText(hDC, lpString, nCount, lpRect, uFormat); + } + else + { + RECT rc = *lpRect; + SIZE text_size = GetTextSize(hDC, lpString, parseInfo, uFormat, parseInfo->max_height, (lpRect->right - lpRect->left)); + + if (text_size.cx < rc.right - rc.left) + { + if (uFormat & DT_RIGHT) + rc.left = rc.right - text_size.cx; + else + rc.right = rc.left + text_size.cx; + } + + result = text_size.cy; + DrawTextSmiley(hDC, rc, lpString, nCount, parseInfo, uFormat, parseInfo->max_height); + } + } + + return result; +} + +SIZE GetTextSize(HDC hdcMem, const TCHAR *szText, SMILEYPARSEINFO info, UINT uTextFormat, int max_smiley_height, int max_width) +{ + SIZE text_size = {0}; + int text_height; + int row_count = 0, pos_x = 0; + + if (szText == NULL || _tcsclen(szText) == 0) + { + text_size.cy = 0; + text_size.cx = 0; + } + else + { + RECT text_rc = {0, 0, 2048, 2048}; + + if (info->pieces == NULL) + { + DrawText(hdcMem, szText, -1, &text_rc, DT_CALCRECT | uTextFormat); + text_size.cx = text_rc.right - text_rc.left; + text_size.cy = text_rc.bottom - text_rc.top; + } + else + { + // Get real height of the line + text_height = DrawText(hdcMem, _T("A"), 1, &text_rc, DT_CALCRECT | uTextFormat); + + // See each item of list + int i; + for (i = 0; i < info->pieces->realCount; i++) + { + TEXTPIECE *piece = (TEXTPIECE *) info->pieces->items[i]; + info->row_height[row_count] = max(info->row_height[row_count], text_height); + + if (piece->type == TEXT_PIECE_TYPE_TEXT) + { + RECT text_rc = {0, 0, 2048, 2048}; + + DrawText(hdcMem, szText + piece->start_pos, piece->len, &text_rc, DT_CALCRECT | uTextFormat); + pos_x += (text_rc.right - text_rc.left); + if (pos_x > max_width) + { + text_size.cx = max(text_size.cx, pos_x - (text_rc.right - text_rc.left)); + pos_x = text_rc.right - text_rc.left; + info->row_height[++row_count] = text_height; + } + + if (szText[piece->start_pos + piece->len - 1] == '\n') + { + text_size.cx = max(text_size.cx, pos_x); + pos_x = 0; + info->row_height[++row_count] = 0; + } + + } + else + { + double factor; + + if (uTextFormat & DT_RESIZE_SMILEYS && piece->smiley_height > text_height) + factor = text_height / (double) piece->smiley_height; + else + factor = 1; + + info->row_height[row_count] = max(info->row_height[row_count], piece->smiley_height * factor); + + pos_x += piece->smiley_width * factor; + if (pos_x > max_width) + { + text_size.cx = max(text_size.cx, pos_x - (piece->smiley_width * factor)); + pos_x = piece->smiley_width * factor; + info->row_height[++row_count] = piece->smiley_height * factor; + } + } + } + + text_size.cx = max(text_size.cx, pos_x); + for (i = 0; i < row_count + 1; i++) + text_size.cy += info->row_height[i]; + } + } + + return text_size; +} + +void DrawTextSmiley(HDC hdcMem, RECT free_rc, const TCHAR *szText, int len, SMILEYPARSEINFO info, UINT uTextFormat, int max_smiley_height) +{ + if (szText == NULL) + return; + + uTextFormat &= ~DT_RIGHT; + + // Draw list + int text_height, i, shift; + int row_count = 0, pos_x = 0; + + RECT tmp_rc = free_rc; + + if (uTextFormat & DT_RTLREADING) + i = info->pieces->realCount - 1; + else + i = 0; + + // Get real height of the line + text_height = DrawText(hdcMem, _T("A"), 1, &tmp_rc, DT_CALCRECT | uTextFormat); + + if (IsWinVer2000Plus()) + SaveAlpha(&free_rc); + + // Just draw ellipsis + if (free_rc.right <= free_rc.left) + { + DrawText(hdcMem, _T("..."), 3, &free_rc, uTextFormat & ~DT_END_ELLIPSIS); + } + else + { + // Draw text and smileys + RECT text_rc = free_rc; + for (; i < info->pieces->realCount && i >= 0 && len > 0; i += (uTextFormat & DT_RTLREADING ? -1 : 1)) + { + TEXTPIECE *piece = (TEXTPIECE *) info->pieces->items[i]; + + if (uTextFormat & DT_RTLREADING) + text_rc.right = free_rc.right - pos_x; + else + text_rc.left = free_rc.left + pos_x; + + if (piece->type == TEXT_PIECE_TYPE_TEXT) + { + tmp_rc = text_rc; + tmp_rc.right = 2048; + + DrawText(hdcMem, szText + piece->start_pos, min(len, piece->len), &tmp_rc, DT_CALCRECT | (uTextFormat & ~DT_END_ELLIPSIS)); + + pos_x += (tmp_rc.right - tmp_rc.left); + if (pos_x > (free_rc.right - free_rc.left)) + { + pos_x = tmp_rc.right - tmp_rc.left; + text_rc.left = free_rc.left; + text_rc.right = free_rc.right; + text_rc.top += info->row_height[row_count]; + row_count++; + } + + shift = (info->row_height[row_count] - text_height) >> 1; + text_rc.top += shift; + + if (uTextFormat & DT_RTLREADING) + text_rc.left = max(text_rc.left, text_rc.right - (tmp_rc.right - tmp_rc.left)); + + DrawText(hdcMem, szText + piece->start_pos, min(len, piece->len), &text_rc, uTextFormat); + len -= piece->len; + text_rc.top -= shift; + + if (szText[piece->start_pos + piece->len - 1] == '\n') + { + text_rc.left = free_rc.left; + text_rc.right = free_rc.right; + text_rc.top += info->row_height[row_count]; + pos_x = 0; + row_count++; + } + } + else + { + double factor; + + if (len < piece->len) + { + len = 0; + } + else + { + len -= piece->len; + + if (uTextFormat & DT_RESIZE_SMILEYS && piece->smiley_height > text_height) + factor = text_height / (double) piece->smiley_height; + else + factor = 1; + + if (uTextFormat & DT_RTLREADING) + text_rc.left = max(text_rc.right - (int)(piece->smiley_width * factor), text_rc.left); + + pos_x += piece->smiley_width * factor; + if (pos_x > (free_rc.right - free_rc.left)) + { + pos_x = piece->smiley_width * factor; + text_rc.left = free_rc.left; + text_rc.right = free_rc.right; + text_rc.top += info->row_height[row_count]; + row_count++; + } + + shift = (info->row_height[row_count] - (LONG)(piece->smiley_height * factor)) >> 1; + DrawIconExAlpha(hdcMem, text_rc.left, text_rc.top + shift, piece->smiley, piece->smiley_width * factor, piece->smiley_height * factor, 0, NULL, DI_NORMAL, true); + } + } + } + } + + if (IsWinVer2000Plus()) + RestoreAlpha(&free_rc); +} + +void DestroySmileyList(SortedList* p_list) +{ + if (p_list == NULL) + return; + + if (p_list->items != NULL) + { + int i; + for (i = 0 ; i < p_list->realCount ; i++) + { + TEXTPIECE *piece = (TEXTPIECE *)p_list->items[i]; + if (piece != NULL) + { + if (piece->type == TEXT_PIECE_TYPE_SMILEY) + DestroyIcon(piece->smiley); + + mir_free(piece); //this free the p_list->items[i] + } + } + } + List_Destroy(p_list); //this free the p_list->items member + mir_free(p_list); //this free the p_list itself (alloc by List_Create) +} + +// Generete the list of smileys / text to be drawn +SortedList *ReplaceSmileys(const TCHAR *text, int text_size, const char *protocol, int *max_smiley_height) +{ + SMADD_BATCHPARSE2 sp = {0}; + SMADD_BATCHPARSERES *spres; + char smileyProto[64]; + + *max_smiley_height = 0; + + if (!text || !text[0] || !ServiceExists(MS_SMILEYADD_BATCHPARSE)) + return NULL; + + if (protocol == NULL) + strcpy(smileyProto, "tipper"); + else if (strcmp(protocol, szMetaModuleName) == 0) + strcpy(smileyProto, "tipper"); + else + strcpy(smileyProto, protocol); + + // Parse it! + sp.cbSize = sizeof(sp); + sp.str = (TCHAR *)text; + sp.flag = SAFL_TCHAR; + sp.Protocolname = (opt.iSmileyAddFlags & SMILEYADD_USEPROTO) ? smileyProto : "tipper"; + spres = (SMADD_BATCHPARSERES *)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp); + + if (!spres) // Did not find a smiley + return NULL; + + // Lets add smileys + SortedList *plText = List_Create(0, 10); + + TCHAR *word_start, *word_end; + TCHAR *smiley_start, *smiley_end; + TCHAR *last_text_pos = _tcsninc(text, text_size); + + word_start = word_end = (TCHAR *)text; + + for (unsigned i = 0; i < sp.numSmileys; i++) + { + // Get smile position + smiley_start = _tcsninc(text, spres[i].startChar); + smiley_end = _tcsninc(smiley_start, spres[i].size); + + if (spres[i].hIcon) // For deffective smileypacks + { + if (opt.iSmileyAddFlags & SMILEYADD_ONLYISOLATED) + { + if ((smiley_start > text && *(smiley_start - 1) != ' ' && *(smiley_start - 1) != '\n' && *smiley_end != '\r') || + (*smiley_end != '\0' && *smiley_end != ' ' && *smiley_end != '\n' && *smiley_end != '\r')) + continue; + } + + // Add text + while (word_end != smiley_start) + { + while (word_end[0] != ' ' && word_end[0] != '\n') + word_end++; + + if (word_end > smiley_start) + word_end = smiley_start; + else + word_end++; + + if (word_end > word_start) + { + TEXTPIECE *piece = (TEXTPIECE *)mir_alloc0(sizeof(TEXTPIECE)); + piece->type = TEXT_PIECE_TYPE_TEXT; + piece->start_pos = word_start - text; + piece->len = word_end - word_start; + List_Insert(plText, piece, plText->realCount); + word_start = word_end; + } + } + + // Add smiley + { + BITMAP bm; + ICONINFO icon; + TEXTPIECE *piece = (TEXTPIECE *) mir_alloc0(sizeof(TEXTPIECE)); + + piece->type = TEXT_PIECE_TYPE_SMILEY; + piece->len = spres[i].size; + piece->smiley = spres[i].hIcon; + + piece->smiley_width = 16; + piece->smiley_height = 16; + if (GetIconInfo(piece->smiley, &icon)) + { + if (GetObject(icon.hbmColor, sizeof(BITMAP), &bm)) + { + piece->smiley_width = bm.bmWidth; + piece->smiley_height = bm.bmHeight; + } + + DeleteObject(icon.hbmMask); + DeleteObject(icon.hbmColor); + } + + *max_smiley_height = max(piece->smiley_height, *max_smiley_height); + List_Insert(plText, piece, plText->realCount); + } + + word_start = word_end = smiley_end; + } + } + + // Add rest of the text + while (word_end != last_text_pos) + { + while (word_end[0] && word_end[0] != ' ' && word_end[0] != '\n') + word_end++; + + if (word_end[0]) + word_end++; + + if (word_end > word_start) + { + TEXTPIECE *piece = (TEXTPIECE *)mir_alloc0(sizeof(TEXTPIECE)); + piece->type = TEXT_PIECE_TYPE_TEXT; + piece->start_pos = word_start - text; + piece->len = word_end - word_start; + List_Insert(plText, piece, plText->realCount); + word_start = word_end; + } + + } + + CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)spres); + + return plText; +} + +int DrawTextExt(HDC hdc, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, LPCSTR lpProto, SMILEYPARSEINFO spi) +{ + if ((opt.iSmileyAddFlags & SMILEYADD_ENABLE) && spi != NULL) + { + if (opt.iSmileyAddFlags & SMILEYADD_RESIZE) + uFormat |= DT_RESIZE_SMILEYS; + + return Smileys_DrawText(hdc, lpString, nCount, lpRect, uFormat, lpProto, spi); + } + else + { + if (uFormat & DT_CALCRECT) + { + return DrawText(hdc, lpString, nCount, lpRect, uFormat); + } + else + { + return DrawTextAlpha(hdc, lpString, nCount, lpRect, uFormat); + } + } +} diff --git a/plugins/TipperYM/src/mir_smileys.h b/plugins/TipperYM/src/mir_smileys.h new file mode 100644 index 0000000000..5f78ac8f09 --- /dev/null +++ b/plugins/TipperYM/src/mir_smileys.h @@ -0,0 +1,70 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef __MIR_SMILEYS_H__ +#define __MIR_SMILEYS_H__ + +#define DT_RESIZE_SMILEYS 0x10000000 + +// smileyadd options +#define SMILEYADD_ENABLE 1 +#define SMILEYADD_USEPROTO 2 +#define SMILEYADD_ONLYISOLATED 4 +#define SMILEYADD_RESIZE 8 + +#define TEXT_PIECE_TYPE_TEXT 0 +#define TEXT_PIECE_TYPE_SMILEY 1 + +typedef struct { + int type; + int len; + union + { + struct + { + int start_pos; + }; + struct + { + HICON smiley; + int smiley_width; + int smiley_height; + }; + }; +} TEXTPIECE; + +typedef struct tagSMILEYPARSEINFO { + SortedList *pieces; + int row_height[512]; // max 512 rows + int max_height; +} *SMILEYPARSEINFO; + +int InitTipperSmileys(); +SMILEYPARSEINFO Smileys_PreParse(LPCTSTR lpString, int nCount, const char *protocol); +void Smileys_FreeParse(SMILEYPARSEINFO parseInfo); + +SortedList *ReplaceSmileys(const TCHAR *text, int text_size, const char *protocol, int *max_smiley_height); +SIZE GetTextSize(HDC hdcMem, const TCHAR *szText, SMILEYPARSEINFO info, UINT uTextFormat, int max_smiley_height, int max_width); +void DrawTextSmiley(HDC hdcMem, RECT free_rc, const TCHAR *szText, int len, SMILEYPARSEINFO info, UINT uTextFormat, int max_smiley_height); +void DestroySmileyList(SortedList* p_list); + +int Smileys_DrawText(HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, const char *protocol, SMILEYPARSEINFO parseInfo); +int DrawTextExt(HDC hdc, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat, LPCSTR lpProto, SMILEYPARSEINFO spi); + +#endif // __MIR_SMILEYS_H__ diff --git a/plugins/TipperYM/src/options.cpp b/plugins/TipperYM/src/options.cpp new file mode 100644 index 0000000000..ceb4a223b5 --- /dev/null +++ b/plugins/TipperYM/src/options.cpp @@ -0,0 +1,2495 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "options.h" +#include "popwin.h" +#include "str_utils.h" +#include "message_pump.h" +#include "preset_items.h" +#include "skin_parser.h" + +OPTIONS opt; +ICONSTATE exIcons[EXICONS_COUNT]; + +extern TOOLTIPSKIN skin; +extern int ReloadFont(WPARAM wParam, LPARAM lParam); + + +extern int IsTrayProto(const TCHAR *swzProto, BOOL bExtendedTip) +{ + if (swzProto == NULL) + return 0; + + char szSetting[64]; + if (bExtendedTip) + strcpy(szSetting, "TrayProtocolsEx"); + else + strcpy(szSetting, "TrayProtocols"); + + DBVARIANT dbv; + int result = 1; + if (!DBGetContactSettingTString(NULL, MODULE, szSetting, &dbv)) + { + result = _tcsstr(dbv.ptszVal, swzProto) ? 1 : 0; + DBFreeVariant(&dbv); + } + + return result; +} + +void CreateDefaultItems() +{ + DSListNode *ds_node; + DIListNode *di_node; + + for (int i = 0; defaultItemList[i].szName; i++) + { + if (defaultItemList[i].szName[0] == '-') + { + di_node = (DIListNode *)mir_alloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.swzLabel, _T(""), LABEL_LEN); + _tcsncpy(di_node->di.swzValue, _T(""), VALUE_LEN); + di_node->di.bLineAbove = true; + di_node->di.bIsVisible = true; + di_node->di.bParseTipperVarsFirst = false; + di_node->next = opt.diList; + opt.diList = di_node; + opt.iDiCount++; + } + else + { + PRESETITEM *item = GetPresetItemByName(defaultItemList[i].szName); + if (item == NULL) continue; + + for (int j = 0; j < MAX_PRESET_SUBST_COUNT; j++) + { + PRESETSUBST *subst = GetPresetSubstByName(item->szNeededSubst[j]); + if (subst == NULL) continue; + + ds_node = (DSListNode *)mir_alloc(sizeof(DSListNode)); + _tcsncpy(ds_node->ds.swzName, subst->swzName, LABEL_LEN); + ds_node->ds.type = subst->type; + strncpy(ds_node->ds.szSettingName, subst->szSettingName, SETTING_NAME_LEN); + ds_node->ds.iTranslateFuncId = subst->iTranslateFuncId; + ds_node->next = opt.dsList; + opt.dsList = ds_node; + opt.iDsCount++; + } + + di_node = (DIListNode *)mir_alloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.swzLabel, TranslateTS(item->swzLabel), LABEL_LEN); + _tcsncpy(di_node->di.swzValue, item->swzValue, VALUE_LEN); + di_node->di.bLineAbove = false; + di_node->di.bValueNewline = defaultItemList[i].bValueNewline; + di_node->di.bIsVisible = true; + di_node->di.bParseTipperVarsFirst = false; + di_node->next = opt.diList; + opt.diList = di_node; + opt.iDiCount++; + } + } +} + + +bool LoadDS(DISPLAYSUBST *ds, int index) +{ + char setting[512]; + DBVARIANT dbv; + + mir_snprintf(setting, SIZEOF(setting), "Name%d", index); + ds->swzName[0] = 0; + if (!DBGetContactSettingTString(0, MODULE_ITEMS, setting, &dbv)) + { + _tcsncpy(ds->swzName, dbv.ptszVal, SIZEOF(ds->swzName)); + ds->swzName[SIZEOF(ds->swzName) - 1] = 0; + DBFreeVariant(&dbv); + } else + return false; + + mir_snprintf(setting, SIZEOF(setting), "Type%d", index); + ds->type = (DisplaySubstType)DBGetContactSettingByte(0, MODULE_ITEMS, setting, DVT_PROTODB); + + mir_snprintf(setting, SIZEOF(setting), "Module%d", index); + ds->szModuleName[0] = 0; + if (!DBGetContactSetting(0, MODULE_ITEMS, setting, &dbv)) + { + strncpy(ds->szModuleName, dbv.pszVal, MODULE_NAME_LEN); + ds->szModuleName[MODULE_NAME_LEN - 1] = 0; + DBFreeVariant(&dbv); + } + + mir_snprintf(setting, SIZEOF(setting), "Setting%d", index); + ds->szSettingName[0] = 0; + if (!DBGetContactSetting(0, MODULE_ITEMS, setting, &dbv)) + { + strncpy(ds->szSettingName, dbv.pszVal, SETTING_NAME_LEN); + ds->szSettingName[SETTING_NAME_LEN - 1] = 0; + DBFreeVariant(&dbv); + } + + mir_snprintf(setting, SIZEOF(setting), "TransFuncId%d", index); + ds->iTranslateFuncId = DBGetContactSettingDword(0, MODULE_ITEMS, setting, (DWORD)-1); + + // a little backward compatibility + if ((DWORD)ds->iTranslateFuncId == (DWORD)-1) + { + mir_snprintf(setting, SIZEOF(setting), "TransFunc%d", index); + ds->iTranslateFuncId = (DWORD)DBGetContactSettingWord(0, MODULE_ITEMS, setting, 0); + } + + return true; +} + + +void SaveDS(DISPLAYSUBST *ds, int index) +{ + char setting[512]; + + mir_snprintf(setting, SIZEOF(setting), "Name%d", index); + DBWriteContactSettingTString(0, MODULE_ITEMS, setting, ds->swzName); + mir_snprintf(setting, SIZEOF(setting), "Type%d", index); + DBWriteContactSettingByte(0, MODULE_ITEMS, setting, (BYTE)ds->type); + mir_snprintf(setting, SIZEOF(setting), "Module%d", index); + DBWriteContactSettingString(0, MODULE_ITEMS, setting, ds->szModuleName); + mir_snprintf(setting, SIZEOF(setting), "Setting%d", index); + DBWriteContactSettingString(0, MODULE_ITEMS, setting, ds->szSettingName); + mir_snprintf(setting, SIZEOF(setting), "TransFuncId%d", index); + DBWriteContactSettingDword(0, MODULE_ITEMS, setting, (WORD)ds->iTranslateFuncId); +} + + +bool LoadDI(DISPLAYITEM *di, int index) +{ + char setting[512]; + DBVARIANT dbv; + + mir_snprintf(setting, SIZEOF(setting), "DILabel%d", index); + di->swzLabel[0] = 0; + if (!DBGetContactSettingTString(0, MODULE_ITEMS, setting, &dbv)) + { + _tcsncpy( di->swzLabel, dbv.ptszVal, SIZEOF(di->swzLabel)); + di->swzLabel[SIZEOF(di->swzLabel) - 1] = 0; + DBFreeVariant(&dbv); + } else + return false; + + mir_snprintf(setting, SIZEOF(setting), "DIValue%d", index); + di->swzValue[0] = 0; + if (!DBGetContactSettingTString(0, MODULE_ITEMS, setting, &dbv)) + { + _tcsncpy(di->swzValue, dbv.ptszVal, SIZEOF(di->swzValue)); + di->swzValue[SIZEOF(di->swzValue) - 1] = 0; + DBFreeVariant(&dbv); + } + + mir_snprintf(setting, SIZEOF(setting), "DILineAbove%d", index); + di->bLineAbove = (DBGetContactSettingByte(0, MODULE_ITEMS, setting, 0) == 1); + mir_snprintf(setting, SIZEOF(setting), "DIValNewline%d", index); + di->bValueNewline = (DBGetContactSettingByte(0, MODULE_ITEMS, setting, 0) == 1); + mir_snprintf(setting, SIZEOF(setting), "DIVisible%d", index); + di->bIsVisible = (DBGetContactSettingByte(0, MODULE_ITEMS, setting, 1) == 1); + mir_snprintf(setting, SIZEOF(setting), "DITipperVarsFirst%d", index); + di->bParseTipperVarsFirst = (DBGetContactSettingByte(0, MODULE_ITEMS, setting, 0) == 1); + + return true; +} + + +void SaveDI(DISPLAYITEM *di, int index) +{ + char setting[512]; + + mir_snprintf(setting, SIZEOF(setting), "DILabel%d", index); + if (DBWriteContactSettingTString(0, MODULE_ITEMS, setting, di->swzLabel)) + { + char buff[LABEL_LEN]; + t2a(di->swzLabel, buff, LABEL_LEN); + DBWriteContactSettingString(0, MODULE_ITEMS, setting, buff); + } + + mir_snprintf(setting, SIZEOF(setting), "DIValue%d", index); + if (DBWriteContactSettingTString(0, MODULE_ITEMS, setting, di->swzValue)) + { + char buff[VALUE_LEN]; + t2a(di->swzValue, buff, VALUE_LEN); + DBWriteContactSettingString(0, MODULE_ITEMS, setting, buff); + } + + mir_snprintf(setting, SIZEOF(setting), "DILineAbove%d", index); + DBWriteContactSettingByte(0, MODULE_ITEMS, setting, di->bLineAbove ? 1 : 0); + mir_snprintf(setting, SIZEOF(setting), "DIValNewline%d", index); + DBWriteContactSettingByte(0, MODULE_ITEMS, setting, di->bValueNewline ? 1 : 0); + mir_snprintf(setting, SIZEOF(setting), "DIVisible%d", index); + DBWriteContactSettingByte(0, MODULE_ITEMS, setting, di->bIsVisible ? 1 : 0); + mir_snprintf(setting, SIZEOF(setting), "DITipperVarsFirst%d", index); + DBWriteContactSettingByte(0, MODULE_ITEMS, setting, di->bParseTipperVarsFirst ? 1 : 0); +} + + +void SaveOptions() +{ + DBWriteContactSettingDword(0, MODULE, "MaxWidth", opt.iWinWidth); + DBWriteContactSettingDword(0, MODULE, "MaxHeight", opt.iWinMaxHeight); + DBWriteContactSettingByte(0, MODULE, "AvatarOpacity", (BYTE)opt.iAvatarOpacity); + DBWriteContactSettingByte(0, MODULE, "AvatarRoundCorners", (opt.bAvatarRound ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "TitleLayout", (BYTE)opt.titleLayout); + if (ServiceExists(MS_AV_DRAWAVATAR)) + DBWriteContactSettingByte(0, MODULE, "AVLayout", (BYTE)opt.avatarLayout); + opt.bWaitForAvatar = (opt.avatarLayout == PAV_NONE) ? false : true; + + DBWriteContactSettingDword(0, MODULE, "AVSize", opt.iAvatarSize); + DBWriteContactSettingDword(0, MODULE, "TextIndent", opt.iTextIndent); + DBWriteContactSettingDword(0, MODULE, "TitleIndent", opt.iTitleIndent); + DBWriteContactSettingDword(0, MODULE, "ValueIndent", opt.iValueIndent); + DBWriteContactSettingByte(0, MODULE, "ShowNoFocus", (opt.bShowNoFocus ? 1 : 0)); + + DBWriteContactSettingWord(0, MODULE, "TimeIn", opt.iTimeIn); + CallService(MS_CLC_SETINFOTIPHOVERTIME, opt.iTimeIn, 0); + + DBWriteContactSettingWord(0, MODULE, "Padding", opt.iPadding); + DBWriteContactSettingWord(0, MODULE, "OuterAvatarPadding", opt.iOuterAvatarPadding); + DBWriteContactSettingWord(0, MODULE, "InnerAvatarPadding", opt.iInnerAvatarPadding); + DBWriteContactSettingWord(0, MODULE, "TextPadding", opt.iTextPadding); + DBWriteContactSettingByte(0, MODULE, "Position", (BYTE)opt.pos); + DBWriteContactSettingDword(0, MODULE, "MinWidth", (DWORD)opt.iMinWidth); + DBWriteContactSettingDword(0, MODULE, "MinHeight", (DWORD)opt.iMinHeight); + DBWriteContactSettingDword(0, MODULE, "SidebarWidth", (DWORD)opt.iSidebarWidth); + DBWriteContactSettingByte(0, MODULE, "MouseTollerance", (BYTE)opt.iMouseTollerance); + DBWriteContactSettingByte(0, MODULE, "SBarTips", (opt.bStatusBarTips ? 1 : 0)); + + DBWriteContactSettingWord(0, MODULE, "LabelVAlign", opt.iLabelValign); + DBWriteContactSettingWord(0, MODULE, "LabelHAlign", opt.iLabelHalign); + DBWriteContactSettingWord(0, MODULE, "ValueVAlign", opt.iValueValign); + DBWriteContactSettingWord(0, MODULE, "ValueHAlign", opt.iValueHalign); + + DBWriteContactSettingByte(0, MODULE, "OriginalAvSize", (opt.bOriginalAvatarSize ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "AvatarBorder", (opt.bAvatarBorder ? 1 : 0)); +} + +void SaveItems() +{ + int index = 0; + DSListNode *ds_node = opt.dsList; + while (ds_node) + { + SaveDS(&ds_node->ds, index); + ds_node = ds_node->next; + index++; + } + + DBWriteContactSettingWord(0, MODULE_ITEMS, "DSNumValues", index); + + index = 0; + DIListNode *di_node = opt.diList; + opt.bWaitForStatusMsg = false; + while (di_node) + { + SaveDI(&di_node->di, index); + if (di_node->di.bIsVisible && _tcsstr(di_node->di.swzValue, _T("sys:status_msg"))) + opt.bWaitForStatusMsg = true; + di_node = di_node->next; + index++; + } + + DBWriteContactSettingWord(0, MODULE_ITEMS, "DINumValues", index); +} + +void SaveSkinOptions() +{ + DBWriteContactSettingByte(0, MODULE, "Border", (opt.bBorder ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "DropShadow", (opt.bDropShadow ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "RoundCorners", (opt.bRound ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "AeroGlass", (opt.bAeroGlass ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "Opacity", (BYTE)opt.iOpacity); + DBWriteContactSettingByte(0, MODULE, "ShowEffect", (BYTE)opt.showEffect); + DBWriteContactSettingByte(0, MODULE, "ShowEffectSpeed", (BYTE)opt.iAnimateSpeed); + DBWriteContactSettingByte(0, MODULE, "LoadFonts", (opt.bLoadFonts ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "LoadProportions", (opt.bLoadProportions ? 1 : 0)); + DBWriteContactSettingDword(0, MODULE, "EnableColoring", opt.iEnableColoring); +} + +void LoadObsoleteSkinSetting() +{ + char setting[128]; + DBVARIANT dbv; + + for (int i = 0; i < SKIN_ITEMS_COUNT; i++) + { + mir_snprintf(setting, 128, "SPaintMode%d", i); + opt.transfMode[i] = (TransformationMode)DBGetContactSettingByte(0, MODULE, setting, 0); + mir_snprintf(setting, 128, "SImgFile%d", i); + if (!DBGetContactSettingTString(NULL, MODULE, setting, &dbv)) + { + opt.szImgFile[i] = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } + + mir_snprintf(setting, 128, "SGlyphMargins%d", i); + DWORD margins = DBGetContactSettingDword(NULL, MODULE, setting, 0); + opt.margins[i].top = LOBYTE(LOWORD(margins)); + opt.margins[i].right = HIBYTE(LOWORD(margins)); + opt.margins[i].bottom = LOBYTE(HIWORD(margins)); + opt.margins[i].left = HIBYTE(HIWORD(margins)); + } +} + +void LoadOptions() +{ + opt.iWinWidth = DBGetContactSettingDword(0, MODULE, "MaxWidth", 420); + opt.iWinMaxHeight = DBGetContactSettingDword(0, MODULE, "MaxHeight", 400); + opt.iAvatarOpacity = DBGetContactSettingByte(0, MODULE, "AvatarOpacity", 100); + if (opt.iAvatarOpacity > 100) opt.iAvatarOpacity = 100; + opt.bAvatarRound = (DBGetContactSettingByte(0, MODULE, "AvatarRoundCorners", opt.bRound ? 1 : 0) == 1); + opt.titleLayout = (PopupTitleLayout)DBGetContactSettingByte(0, MODULE, "TitleLayout", (BYTE)PTL_LEFTICON); + if (ServiceExists(MS_AV_DRAWAVATAR)) + opt.avatarLayout = (PopupAvLayout)DBGetContactSettingByte(0, MODULE, "AVLayout", PAV_RIGHT); + else + opt.avatarLayout = PAV_NONE; + + opt.bWaitForAvatar = (opt.avatarLayout == PAV_NONE) ? false : true; + opt.iAvatarSize = DBGetContactSettingDword(0, MODULE, "AVSize", 60); //tweety + opt.iTextIndent = DBGetContactSettingDword(0, MODULE, "TextIndent", 22); + opt.iTitleIndent = DBGetContactSettingDword(0, MODULE, "TitleIndent", 22); + opt.iValueIndent = DBGetContactSettingDword(0, MODULE, "ValueIndent", 10); + opt.iSidebarWidth = DBGetContactSettingDword(0, MODULE, "SidebarWidth", 22); + opt.bShowNoFocus = (DBGetContactSettingByte(0, MODULE, "ShowNoFocus", 1) == 1); + + int i, real_count = 0; + opt.dsList = 0; + DSListNode *ds_node; + + opt.iDsCount = DBGetContactSettingWord(0, MODULE_ITEMS, "DSNumValues", 0); + for (i = opt.iDsCount - 1; i >= 0; i--) + { + ds_node = (DSListNode *)mir_alloc(sizeof(DSListNode)); + if (LoadDS(&ds_node->ds, i)) + { + ds_node->next = opt.dsList; + opt.dsList = ds_node; + real_count++; + } + else + { + mir_free(ds_node); + } + } + opt.iDsCount = real_count; + + real_count = 0; + opt.diList = 0; + DIListNode *di_node; + + opt.bWaitForStatusMsg = false; + opt.iDiCount = DBGetContactSettingWord(0, MODULE_ITEMS, "DINumValues", 0); + for (i = opt.iDiCount - 1; i >= 0; i--) + { + di_node = (DIListNode *)mir_alloc(sizeof(DIListNode)); + if (LoadDI(&di_node->di, i)) + { + di_node->next = opt.diList; + opt.diList = di_node; + real_count++; + if (di_node->di.bIsVisible && _tcsstr(di_node->di.swzValue, _T("sys:status_msg"))) + opt.bWaitForStatusMsg = true; + } + else + { + mir_free(di_node); + } + } + opt.iDiCount = real_count; + + opt.iTimeIn = DBGetContactSettingWord(0, MODULE, "TimeIn", 750); + opt.iPadding = DBGetContactSettingWord(0, MODULE, "Padding", 4); + opt.iOuterAvatarPadding = DBGetContactSettingWord(0, MODULE, "OuterAvatarPadding", 6); + opt.iInnerAvatarPadding = DBGetContactSettingWord(0, MODULE, "InnerAvatarPadding", 10); + opt.iTextPadding = DBGetContactSettingWord(0, MODULE, "TextPadding", 4); + opt.pos = (PopupPosition)DBGetContactSettingByte(0, MODULE, "Position", (BYTE)PP_BOTTOMRIGHT); + opt.iMinWidth = DBGetContactSettingDword(0, MODULE, "MinWidth", 0); + opt.iMinHeight = DBGetContactSettingDword(0, MODULE, "MinHeight", 0); + + opt.iMouseTollerance = DBGetContactSettingByte(0, MODULE, "MouseTollerance", (BYTE)GetSystemMetrics(SM_CXSMICON)); + opt.bStatusBarTips = (DBGetContactSettingByte(0, MODULE, "SBarTips", 1) == 1); + + // convert defunct last message and status message options to new 'sys' items, and remove the old settings + if (DBGetContactSettingByte(0, MODULE, "ShowLastMessage", 0)) + { + DBDeleteContactSetting(0, MODULE, "ShowLastMessage"); + + // find end of list + di_node = opt.diList; + while(di_node && di_node->next) + di_node = di_node->next; + + // last message item + if (di_node) + { + di_node->next = (DIListNode *)mir_alloc(sizeof(DIListNode)); + di_node = di_node->next; + } + else + { + opt.diList = (DIListNode *)mir_alloc(sizeof(DIListNode)); + di_node = opt.diList; + } + + _tcsncpy(di_node->di.swzLabel, _T("Last message: (%sys:last_msg_reltime% ago)"), LABEL_LEN); + _tcsncpy(di_node->di.swzValue, _T("%sys:last_msg%"), VALUE_LEN); + di_node->di.bLineAbove = di_node->di.bValueNewline = true; + di_node->next = 0; + opt.iDiCount++; + } + + if (DBGetContactSettingByte(0, MODULE, "ShowStatusMessage", 0)) + { + DBDeleteContactSetting(0, MODULE, "ShowStatusMessage"); + + // find end of list + di_node = opt.diList; + while(di_node && di_node->next) + di_node = di_node->next; + + // status message item + if (di_node) + { + di_node->next = (DIListNode *)mir_alloc(sizeof(DIListNode)); + di_node = di_node->next; + } + else + { + opt.diList = (DIListNode *)mir_alloc(sizeof(DIListNode)); + di_node = opt.diList; + } + + _tcsncpy(di_node->di.swzLabel, _T("Status message:"), LABEL_LEN); + _tcsncpy(di_node->di.swzValue, _T("%sys:status_msg%"), VALUE_LEN); + di_node->di.bLineAbove = di_node->di.bValueNewline = true; + di_node->next = 0; + opt.iDiCount++; + } + + opt.iLabelValign = DBGetContactSettingWord(0, MODULE, "LabelVAlign", DT_TOP /*DT_VCENTER*/); + opt.iLabelHalign = DBGetContactSettingWord(0, MODULE, "LabelHAlign", DT_LEFT); + opt.iValueValign = DBGetContactSettingWord(0, MODULE, "ValueVAlign", DT_TOP /*DT_VCENTER*/); + opt.iValueHalign = DBGetContactSettingWord(0, MODULE, "ValueHAlign", DT_LEFT); + + // tray tooltip + opt.bTraytip = DBGetContactSettingByte(0, MODULE, "TrayTip", 1) ? true : false; + opt.bHandleByTipper = DBGetContactSettingByte(0, MODULE, "ExtendedTrayTip", 1) ? true : false; + opt.bExpandTraytip = DBGetContactSettingByte(0, MODULE, "ExpandTrayTip", 1) ? true : false; + opt.bHideOffline = DBGetContactSettingByte(0, MODULE, "HideOffline", 0) ? true : false; + opt.iExpandTime = DBGetContactSettingDword(0, MODULE, "ExpandTime", 1000); + opt.iFirstItems = DBGetContactSettingDword(0, MODULE, "TrayTipItems", TRAYTIP_NUMCONTACTS | TRAYTIP_LOGON | TRAYTIP_STATUS | TRAYTIP_CLIST_EVENT); + opt.iSecondItems = DBGetContactSettingDword(0, MODULE, "TrayTipItemsEx", TRAYTIP_NUMCONTACTS | TRAYTIP_LOGON | TRAYTIP_STATUS | TRAYTIP_STATUS_MSG | TRAYTIP_EXTRA_STATUS | TRAYTIP_MIRANDA_UPTIME | TRAYTIP_CLIST_EVENT); + opt.iFavoriteContFlags = DBGetContactSettingDword(0, MODULE, "FavContFlags", FAVCONT_APPEND_PROTO); + + // extra setting + opt.bWaitForContent= DBGetContactSettingByte(0, MODULE, "WaitForContent", 0) ? true : false; + opt.bGetNewStatusMsg = DBGetContactSettingByte(0, MODULE, "GetNewStatusMsg", 0) ? true : false; + opt.bDisableIfInvisible = DBGetContactSettingByte(0, MODULE, "DisableInvisible", 1) ? true : false; + opt.bRetrieveXstatus = DBGetContactSettingByte(0, MODULE, "RetrieveXStatus", 0) ? true : false; + opt.bOriginalAvatarSize = DBGetContactSettingByte(0, MODULE, "OriginalAvSize", 0) ? true : false; + opt.bAvatarBorder = DBGetContactSettingByte(0, MODULE, "AvatarBorder", 0) ? true : false; + opt.bLimitMsg = DBGetContactSettingByte(0, MODULE, "LimitMsg", 0) ? true : false; + opt.iLimitCharCount = DBGetContactSettingByte(0, MODULE, "LimitCharCount", 64); + opt.iSmileyAddFlags = DBGetContactSettingDword(0, MODULE, "SmileyAddFlags", SMILEYADD_ENABLE); + + DBVARIANT dbv; + // Load the icons order + for(i = 0; i < EXICONS_COUNT; i++) + { + opt.exIconsOrder[i]=i; + opt.exIconsVis[i]=1; + } + + if (!DBGetContactSetting(NULL, MODULE, "IconOrder", &dbv)) + { + CopyMemory(opt.exIconsOrder,dbv.pbVal,dbv.cpbVal); + DBFreeVariant(&dbv); + } + + if (!DBGetContactSetting(NULL, MODULE, "icons_vis", &dbv)) + { + CopyMemory(opt.exIconsVis,dbv.pbVal,dbv.cpbVal); + DBFreeVariant(&dbv); + } + + for(i = 0; i < EXICONS_COUNT; i++) + { + exIcons[i].order = opt.exIconsOrder[i]; + exIcons[i].vis = opt.exIconsVis[i]; + } + + opt.iOpacity = DBGetContactSettingByte(0, MODULE, "Opacity", 75); + opt.bBorder = DBGetContactSettingByte(0, MODULE, "Border", 1) ? true : false; + opt.bDropShadow = DBGetContactSettingByte(0, MODULE, "DropShadow", 1) ? true : false; + opt.bRound = DBGetContactSettingByte(0, MODULE, "RoundCorners", 1) ? true : false; + opt.bAeroGlass = DBGetContactSettingByte(0, MODULE, "AeroGlass", 0) ? true : false; + opt.showEffect = (PopupShowEffect)DBGetContactSettingByte(0, MODULE, "ShowEffect", (BYTE)PSE_FADE); + opt.iAnimateSpeed = DBGetContactSettingByte(0, MODULE, "ShowEffectSpeed", 12); + + if (opt.iAnimateSpeed < 1) + opt.iAnimateSpeed = 1; + else if (opt.iAnimateSpeed > 20) + opt.iAnimateSpeed = 20; + + int iBgImg = DBGetContactSettingByte(0, MODULE, "SBgImage", 0); + opt.skinMode = (SkinMode)DBGetContactSettingByte(0, MODULE, "SkinEngine", iBgImg ? SM_OBSOLOTE : SM_COLORFILL); + opt.bLoadFonts = DBGetContactSettingByte(0, MODULE, "LoadFonts", 1) ? true : false; + opt.bLoadProportions= DBGetContactSettingByte(0, MODULE, "LoadProportions", 1) ? true : false; + opt.iEnableColoring = DBGetContactSettingDword(0, MODULE, "EnableColoring", 0); + opt.szSkinName[0] = 0; + + if (opt.skinMode == SM_OBSOLOTE) + { + LoadObsoleteSkinSetting(); + } + else if (opt.skinMode == SM_IMAGE) + { + if (!DBGetContactSettingTString(NULL, MODULE, "SkinName", &dbv)) + { + _tcscpy(opt.szSkinName, dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + + if (opt.iDsCount == 0 && opt.iDiCount == 0) + { + // set up some reasonable defaults + CreateDefaultItems(); + SaveOptions(); + SaveItems(); + } +} + +INT_PTR CALLBACK DlgProcAddItem(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DISPLAYITEM *di = (DISPLAYITEM *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault( hwndDlg ); + di = (DISPLAYITEM *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)di); + + SetDlgItemText(hwndDlg, IDC_ED_LABEL, di->swzLabel); + SetDlgItemText(hwndDlg, IDC_ED_VALUE, di->swzValue); + + CheckDlgButton(hwndDlg, IDC_CHK_LINEABOVE, di->bLineAbove ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_VALNEWLINE, di->bValueNewline ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_PARSETIPPERFIRST, di->bParseTipperVarsFirst ? TRUE : FALSE); + + int i; + for (i = 0; presetItems[i].szID; i++) + SendDlgItemMessage(hwndDlg, IDC_CMB_PRESETITEMS, CB_ADDSTRING, 0, (LPARAM)TranslateTS(presetItems[i].swzName)); + + variables_skin_helpbutton(hwndDlg, IDC_BTN_VARIABLE); + + SetFocus(GetDlgItem(hwndDlg, IDC_ED_LABEL)); + return TRUE; + } + case WM_COMMAND: + { + if (HIWORD(wParam) == BN_CLICKED) + { + switch(LOWORD(wParam)) + { + case IDOK: + { + int sel; + GetDlgItemText(hwndDlg, IDC_ED_LABEL, di->swzLabel, LABEL_LEN); + GetDlgItemText(hwndDlg, IDC_ED_VALUE, di->swzValue, VALUE_LEN); + + di->bLineAbove = (IsDlgButtonChecked(hwndDlg, IDC_CHK_LINEABOVE) ? true : false); + di->bValueNewline = (IsDlgButtonChecked(hwndDlg, IDC_CHK_VALNEWLINE) ? true : false); + di->bParseTipperVarsFirst = (IsDlgButtonChecked(hwndDlg, IDC_CHK_PARSETIPPERFIRST) ? true : false); + + sel = SendDlgItemMessage(hwndDlg, IDC_CMB_PRESETITEMS, CB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + { + TCHAR buff[256]; int i; + SendDlgItemMessage(hwndDlg, IDC_CMB_PRESETITEMS, CB_GETLBTEXT, sel, (LPARAM)buff); + for (i = 0; presetItems[i].szID; i++) + { + if (_tcscmp(buff, TranslateTS(presetItems[i].swzName)) == 0) + break; + } + + if (presetItems[i].szNeededSubst[0]) + EndDialog(hwndDlg, IDPRESETITEM + i); + else + EndDialog(hwndDlg, IDOK); + } + else + { + EndDialog(hwndDlg, IDOK); + } + + return TRUE; + } + case IDCANCEL: + { + EndDialog(hwndDlg, IDCANCEL); + return TRUE; + } + case IDC_BTN_VARIABLE: + { + if (GetFocus() == GetDlgItem(hwndDlg, IDC_ED_LABEL)) + variables_showhelp(hwndDlg, IDC_ED_LABEL, VHF_FULLDLG, NULL, NULL); + else + variables_showhelp(hwndDlg, IDC_ED_VALUE, VHF_FULLDLG, NULL, NULL); + return TRUE; + } + } + } + else if (HIWORD(wParam) == CBN_SELCHANGE) + { + if (LOWORD(wParam) == IDC_CMB_PRESETITEMS) + { + int sel = SendDlgItemMessage(hwndDlg, IDC_CMB_PRESETITEMS, CB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + { + TCHAR buff[256]; int i; + SendDlgItemMessage(hwndDlg, IDC_CMB_PRESETITEMS, CB_GETLBTEXT, sel, (LPARAM)buff); + for (i = 0; presetItems[i].szID; i++) + { + if (_tcscmp(buff, TranslateTS(presetItems[i].swzName)) == 0) + break; + } + + SetDlgItemText(hwndDlg, IDC_ED_LABEL, TranslateTS(presetItems[i].swzLabel)); + SetDlgItemText(hwndDlg, IDC_ED_VALUE, presetItems[i].swzValue); + } + } + } + break; + } + } + + return 0; +} + +INT_PTR CALLBACK DlgProcAddSubst(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DISPLAYSUBST *ds = (DISPLAYSUBST *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault( hwndDlg ); + ds = (DISPLAYSUBST *)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)ds); + + SetDlgItemText(hwndDlg, IDC_ED_LABEL, ds->swzName); + + switch(ds->type) + { + case DVT_PROTODB: + CheckDlgButton(hwndDlg, IDC_CHK_PROTOMOD, TRUE); + SetDlgItemTextA(hwndDlg, IDC_ED_SETTING, ds->szSettingName); + break; + case DVT_DB: + SetDlgItemTextA(hwndDlg, IDC_ED_MODULE, ds->szModuleName); + SetDlgItemTextA(hwndDlg, IDC_ED_SETTING, ds->szSettingName); + break; + } + + int index, id, i; + for (i = 0; i < iTransFuncsCount; i++) + { + index = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_ADDSTRING, (WPARAM)-1, (LPARAM)TranslateTS(translations[i].swzName)); + SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_SETITEMDATA, index, (LPARAM)translations[i].id); + } + + for (i = 0; i < iTransFuncsCount; i++) + { + id = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_GETITEMDATA, i, 0); + if (id == ds->iTranslateFuncId) + SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_SETCURSEL, i, 0); + } + + SendMessage(hwndDlg, WMU_ENABLE_MODULE_ENTRY, 0, 0); + SetFocus(GetDlgItem(hwndDlg, IDC_ED_LABEL)); + return TRUE; + } + case WMU_ENABLE_MODULE_ENTRY: + { + HWND hw = GetDlgItem(hwndDlg, IDC_CHK_PROTOMOD); + EnableWindow(hw, TRUE); + hw = GetDlgItem(hwndDlg, IDC_ED_MODULE); + EnableWindow(hw, !IsDlgButtonChecked(hwndDlg, IDC_CHK_PROTOMOD)); + hw = GetDlgItem(hwndDlg, IDC_ED_SETTING); + EnableWindow(hw, TRUE); + return TRUE; + } + case WM_COMMAND: + { + if (HIWORD(wParam) == BN_CLICKED) + { + switch(LOWORD(wParam)) + { + case IDC_CHK_PROTOMOD: + { + SendMessage(hwndDlg, WMU_ENABLE_MODULE_ENTRY, 0, 0); + break; + } + case IDOK: + { + GetDlgItemText(hwndDlg, IDC_ED_LABEL, ds->swzName, LABEL_LEN); + if (ds->swzName[0] == 0) + { + MessageBox(hwndDlg, TranslateT("You must enter a label"), TranslateT("Invalid Substitution"), MB_OK | MB_ICONWARNING); + return TRUE; + } + + if (IsDlgButtonChecked(hwndDlg, IDC_CHK_PROTOMOD)) + { + ds->type = DVT_PROTODB; + } + else + { + ds->type = DVT_DB; + GetDlgItemTextA(hwndDlg, IDC_ED_MODULE, ds->szModuleName, MODULE_NAME_LEN); + } + + GetDlgItemTextA(hwndDlg, IDC_ED_SETTING, ds->szSettingName, SETTING_NAME_LEN); + + int sel = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_GETCURSEL, 0, 0); + ds->iTranslateFuncId = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_GETITEMDATA, sel, 0); + + EndDialog(hwndDlg, IDOK); + return TRUE; + } + case IDCANCEL: + { + EndDialog(hwndDlg, IDCANCEL); + return TRUE; + } + } + } + else if (HIWORD(wParam) == CBN_SELCHANGE) + { + return TRUE; + } + + break; + } + } + + return 0; +} + +static void SetTreeItemText(DIListNode *node, TCHAR **pszText) +{ + if (node->di.swzLabel[0] == 0) + { + if (node->di.swzValue[0] == 0 && node->di.bLineAbove) + *pszText = _T("--------------------------------------"); + else + *pszText = TranslateT(""); + } + else + { + *pszText = node->di.swzLabel; + } +} + + +static OPTBUTTON btns[9] = +{ + IDC_BTN_ADD, SKINICON_OTHER_ADDCONTACT, 0, LPGENT("Add item"), + IDC_BTN_SEPARATOR, 0, IDI_SEPARATOR, LPGENT("Add separator"), + IDC_BTN_EDIT, SKINICON_OTHER_RENAME, 0, LPGENT("Edit"), + IDC_BTN_REMOVE, SKINICON_OTHER_DELETE, 0, LPGENT("Remove"), + IDC_BTN_UP, 0, IDI_UP, LPGENT("Move up"), + IDC_BTN_DOWN, 0, IDI_DOWN, LPGENT("Move down"), + IDC_BTN_ADD2, SKINICON_OTHER_ADDCONTACT, 0, LPGENT("Add"), + IDC_BTN_REMOVE2, SKINICON_OTHER_DELETE, 0, LPGENT("Remove"), + IDC_BTN_EDIT2, SKINICON_OTHER_RENAME, 0, LPGENT("Edit") +}; + +INT_PTR CALLBACK DlgProcOptsContent(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + for (int i = 0; i < SIZEOF(btns); i++) + { + SendDlgItemMessage(hwndDlg, btns[i].id, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, btns[i].id, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(btns[i].swzTooltip), BATF_TCHAR); + if (btns[i].uintCoreIconId) + { + SendDlgItemMessage(hwndDlg, btns[i].id, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadSkinnedIcon(btns[i].uintCoreIconId)); + } + else + { + HICON hIcon = LoadIcon(hInst, MAKEINTRESOURCE(btns[i].uintResIconId)); + SendDlgItemMessage(hwndDlg, btns[i].id, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + DestroyIcon(hIcon); + } + } + + HIMAGELIST himlStates = ImageList_Create(16, 16, IsWinVerXPPlus() ? ILC_COLOR32 | ILC_MASK : ILC_COLOR8 | ILC_MASK, 3, 0); + ImageList_AddIcon(himlStates, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); + ImageList_AddIcon(himlStates, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); + ImageList_AddIcon(himlStates, LoadSkinnedIcon(SKINICON_OTHER_TICK)); + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), himlStates, TVSIL_STATE); + + TVINSERTSTRUCT tvi = {0}; + tvi.hInsertAfter = TVI_LAST; + tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE; + tvi.item.stateMask = TVIS_STATEIMAGEMASK; + + DIListNode *di_node = opt.diList, *di_value; + while (di_node) + { + di_value = (DIListNode *)mir_alloc(sizeof(DIListNode)); + *di_value = *di_node; + tvi.item.lParam = (LPARAM)di_value; + tvi.item.state = INDEXTOSTATEIMAGEMASK(di_value->di.bIsVisible ? 2 : 1); + SetTreeItemText(di_value, &tvi.item.pszText); + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &tvi); + di_node = di_node->next; + } + + DSListNode *ds_node = opt.dsList, *ds_value; + while (ds_node) + { + ds_value = (DSListNode *)mir_alloc(sizeof(DSListNode)); + *ds_value = *ds_node; + int index = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)ds_value->ds.swzName); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, index, (LPARAM)ds_value); + ds_node = ds_node->next; + } + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + return FALSE; + } + case WMU_ENABLE_LIST_BUTTONS: + { + HTREEITEM hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + if (hItem) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_REMOVE), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UP), TreeView_GetPrevSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hItem) ? TRUE : FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_DOWN), TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hItem) ? TRUE : FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_EDIT), TRUE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_REMOVE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UP), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_DOWN), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_EDIT), FALSE); + } + + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if (sel == -1) + { + HWND hw = GetDlgItem(hwndDlg, IDC_BTN_REMOVE2); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_BTN_EDIT2); + EnableWindow(hw, FALSE); + } + else + { + HWND hw = GetDlgItem(hwndDlg, IDC_BTN_REMOVE2); + EnableWindow(hw, TRUE); + hw = GetDlgItem(hwndDlg, IDC_BTN_EDIT2); + EnableWindow(hw, TRUE); + } + return TRUE; + } + case WM_COMMAND: + { + if (HIWORD(wParam) == LBN_SELCHANGE && LOWORD(wParam) == IDC_LST_SUBST) + { + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + } + else if (HIWORD(wParam) == CBN_SELCHANGE) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + else if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + else if (HIWORD(wParam) == LBN_DBLCLK && LOWORD(wParam) == IDC_LST_SUBST) + { + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if (sel != CB_ERR) + { + DSListNode *ds_value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, sel, 0); + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SUBST), hwndDlg, DlgProcAddSubst, (LPARAM)&ds_value->ds) == IDOK) + { + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_DELETESTRING, (WPARAM)sel, 0); + + sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)ds_value->ds.swzName); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, sel, (LPARAM)ds_value); + + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETCURSEL, sel, 0); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + else if (HIWORD(wParam) == BN_CLICKED) + { + switch(LOWORD(wParam)) + { + case IDC_BTN_ADD: + { + DIListNode *di_value = (DIListNode *)mir_alloc(sizeof(DIListNode)); + memset(di_value, 0, sizeof(DIListNode)); + di_value->di.bIsVisible = true; + + int result = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ITEM), hwndDlg, DlgProcAddItem, (LPARAM)&di_value->di); + if (result == IDOK || (result >= IDPRESETITEM && result < (IDPRESETITEM + 100))) + { + TVINSERTSTRUCT tvi = {0}; + tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE; + tvi.item.stateMask = TVIS_STATEIMAGEMASK; + tvi.item.lParam = (LPARAM)di_value; + tvi.item.state = INDEXTOSTATEIMAGEMASK(2); + SetTreeItemText(di_value, &tvi.item.pszText); + + HTREEITEM hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + if (hItem) tvi.hInsertAfter = hItem; + else tvi.hInsertAfter = TVI_LAST; + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &tvi); + + if (hItem) + { + HTREEITEM hNewItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hItem); + if (hNewItem) TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hNewItem); + } + + if (result >= IDPRESETITEM) + { + for (int i = 0; i < MAX_PRESET_SUBST_COUNT; i++) + { + + PRESETSUBST *subst = GetPresetSubstByName(presetItems[result - IDPRESETITEM].szNeededSubst[i]); + if (subst == NULL) break; + if (SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_FINDSTRING, -1, (LPARAM)subst->swzName) == LB_ERR) + { + DSListNode *ds_value = (DSListNode *)mir_alloc(sizeof(DSListNode)); + memset(ds_value, 0, sizeof(DSListNode)); + ds_value->next = NULL; + ds_value->ds.type = subst->type; + _tcscpy(ds_value->ds.swzName, subst->swzName); + + if (ds_value->ds.type == DVT_DB && subst->szModuleName) + strcpy(ds_value->ds.szModuleName, subst->szModuleName); + + if (subst->szSettingName) + strcpy(ds_value->ds.szSettingName, subst->szSettingName); + + ds_value->ds.iTranslateFuncId = subst->iTranslateFuncId; + + int index = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)ds_value->ds.swzName); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, index, (LPARAM)ds_value); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETCURSEL, index, 0); + } + } + } + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + + return TRUE; + } + case IDC_BTN_SEPARATOR: + { + DIListNode *di_value = (DIListNode *)mir_alloc(sizeof(DIListNode)); + memset(di_value, 0, sizeof(DIListNode)); + di_value->di.bIsVisible = true; + di_value->di.bLineAbove = true; + + TVINSERTSTRUCT tvi = {0}; + tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE; + tvi.item.stateMask = TVIS_STATEIMAGEMASK; + tvi.item.lParam = (LPARAM)di_value; + tvi.item.state = INDEXTOSTATEIMAGEMASK(2); + tvi.item.pszText = _T("---------------------------------"); + + HTREEITEM hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + if (hItem) tvi.hInsertAfter = hItem; + else tvi.hInsertAfter = TVI_LAST; + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &tvi); + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + case IDC_BTN_REMOVE: + { + TVITEM item = {0}; + item.mask = TVIF_PARAM; + item.hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + if (item.hItem) + { + if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item)) + { + DIListNode *di_value = (DIListNode *)item.lParam; + mir_free(di_value); + TreeView_DeleteItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), item.hItem); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + return TRUE; + } + case IDC_BTN_UP: + case IDC_BTN_DOWN: + { + HTREEITEM hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + if (hItem) + { + HTREEITEM hNewItem; + if (LOWORD(wParam) == IDC_BTN_UP) + hNewItem = TreeView_GetPrevSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hItem); + else + hNewItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hItem); + + if (hNewItem) + { + TCHAR buff[512], buff2[512]; + LPARAM tmpParam; + UINT tmpState; + + TVITEM item = {0}; + item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK; + item.hItem = hItem; + item.pszText = buff; + item.cchTextMax = 512; + if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item)) + { + tmpParam = item.lParam; + tmpState = item.state; + item.hItem = hNewItem; + item.pszText = buff2; + if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item)) + { + item.hItem = hItem; + TreeView_SetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item); + + item.hItem = hNewItem; + item.pszText = buff; + item.lParam = tmpParam; + item.state = tmpState; + TreeView_SetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item); + TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hNewItem); + } + } + } + } + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + case IDC_BTN_EDIT: + { + TVITEM item = {0}; + item.mask = TVIF_PARAM; + item.hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + if (item.hItem ) + { + if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item)) + { + DIListNode *di_value = (DIListNode *)item.lParam; + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ITEM), hwndDlg, DlgProcAddItem, (LPARAM)&di_value->di) == IDOK) + { + item.mask = TVIF_TEXT; + SetTreeItemText(di_value, &item.pszText); + TreeView_SetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + + return TRUE; + } + case IDC_BTN_ADD2: + { + DSListNode *ds_value = (DSListNode *)mir_alloc(sizeof(DSListNode)); + memset(ds_value, 0, sizeof(DSListNode)); + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SUBST), hwndDlg, DlgProcAddSubst, (LPARAM)&ds_value->ds) == IDOK) + { + int index = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)ds_value->ds.swzName); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, index, (LPARAM)ds_value); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETCURSEL, index, 0); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + + return TRUE; + } + case IDC_BTN_REMOVE2: + { + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if (sel != LB_ERR) + { + DSListNode *ds_value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, sel, 0); + mir_free(ds_value); + + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_DELETESTRING, (WPARAM)sel, 0); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + + return TRUE; + } + case IDC_BTN_EDIT2: + { + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if (sel != LB_ERR) + { + DSListNode *ds_value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, sel, 0); + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SUBST), hwndDlg, DlgProcAddSubst, (LPARAM)&ds_value->ds) == IDOK) + { + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_DELETESTRING, (WPARAM)sel, 0); + + sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)ds_value->ds.swzName); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, sel, (LPARAM)ds_value); + + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETCURSEL, sel, 0); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + + return TRUE; + } + default: + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + } + } + break; + } + case WM_NOTIFY: + { + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + DIListNode *di_node; + while (opt.diList) + { + di_node = opt.diList; + opt.diList = opt.diList->next; + mir_free(di_node); + } + + DIListNode *di_value; + opt.iDiCount = TreeView_GetCount(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + + TVITEM item = {0}; + item.mask = TVIF_PARAM; + item.hItem = TreeView_GetLastVisible(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + while (item.hItem != NULL) + { + if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item)) + { + di_node = (DIListNode *)item.lParam; + di_value = (DIListNode *)mir_alloc(sizeof(DIListNode)); + *di_value = *di_node; + di_value->next = opt.diList; + opt.diList = di_value; + } + item.hItem = TreeView_GetPrevSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), item.hItem); + } + + DSListNode *ds_node; + while (opt.dsList) + { + ds_node = opt.dsList; + opt.dsList = opt.dsList->next; + mir_free(ds_node); + } + + DSListNode *ds_value; + opt.iDsCount = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCOUNT, 0, 0); + for (int i = opt.iDsCount - 1; i >= 0; i--) + { + ds_node = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, i, 0); + ds_value = (DSListNode *)mir_alloc(sizeof(DSListNode)); + *ds_value = *ds_node; + ds_value->next = opt.dsList; + opt.dsList = ds_value; + } + + SaveItems(); + return TRUE; + } + case NM_DBLCLK: + { + TVITEM item = {0}; + item.mask = TVIF_PARAM; + item.hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + if (item.hItem) + { + if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item)) + { + DIListNode *di_value = (DIListNode *)item.lParam; + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ITEM), hwndDlg, DlgProcAddItem, (LPARAM)&di_value->di) == IDOK) + { + item.mask = TVIF_TEXT; + SetTreeItemText(di_value, &item.pszText); + TreeView_SetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &item); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + break; + } + case NM_CLICK: + { + TVHITTESTINFO hti; + hti.pt.x = (short)LOWORD(GetMessagePos()); + hti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt); + if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti)) + { + if (hti.flags & TVHT_ONITEMSTATEICON) + { + TVITEMA item = {0}; + item.hItem = hti.hItem; + item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK; + TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item); + + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 1) + { + item.state = INDEXTOSTATEIMAGEMASK(2); + ((DIListNode *)item.lParam)->di.bIsVisible = true; + } + else + { + item.state = INDEXTOSTATEIMAGEMASK(1); + ((DIListNode *)item.lParam)->di.bIsVisible = false; + } + + TreeView_SetItem(((LPNMHDR)lParam)->hwndFrom, &item); + SendMessage((GetParent(hwndDlg)), PSM_CHANGED, (WPARAM)hwndDlg, 0); + } + } + break; + } + case TVN_SELCHANGEDA: + case TVN_SELCHANGEDW: + { + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + break; + } + } + break; + } + case WM_DESTROY: + { + DIListNode *di_value; + TVITEM tvi = {0}; + tvi.mask = TVIF_PARAM; + HTREEITEM hItem = TreeView_GetRoot(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS)); + + while (hItem != NULL) + { + tvi.hItem = hItem; + if (TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &tvi)) + { + di_value = (DIListNode *)tvi.lParam; + mir_free(di_value); + } + hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), hItem); + } + + DSListNode *ds_value; + int count = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCOUNT, 0, 0); + for (int i = 0; i < count; i++) + { + ds_value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, i, 0); + mir_free(ds_value); + } + + ImageList_Destroy(TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), TVSIL_STATE)); + break; + } + } + + return 0; +} + +INT_PTR CALLBACK DlgProcOptsAppearance(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault( hwndDlg ); + + CheckDlgButton(hwndDlg, IDC_CHK_NOFOCUS, opt.bShowNoFocus ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_SBAR, opt.bStatusBarTips ? TRUE : FALSE); + + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("Icon on left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("Icon on right")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("No icon")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("No title")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_SETCURSEL, (int)opt.titleLayout, 0); + + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom right")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top right")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_SETCURSEL, (int)opt.pos, 0); + + SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top")); + SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Centre")); + SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom")); + switch (opt.iLabelValign) + { + case DT_TOP: SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_SETCURSEL, 0, 0); break; + case DT_VCENTER: SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_SETCURSEL, 1, 0); break; + case DT_BOTTOM: SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_SETCURSEL, 2, 0); break; + } + + SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top")); + SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Centre")); + SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom")); + switch (opt.iValueValign) + { + case DT_TOP: SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_SETCURSEL, 0, 0); break; + case DT_VCENTER: SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_SETCURSEL, 1, 0); break; + case DT_BOTTOM: SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_SETCURSEL, 2, 0); break; + } + + SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Right")); + switch (opt.iLabelHalign) + { + case DT_LEFT: SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_SETCURSEL, 0, 0); break; + case DT_RIGHT: SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_SETCURSEL, 1, 0); break; + } + + SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Right")); + switch (opt.iValueHalign) + { + case DT_LEFT: SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_SETCURSEL, 0, 0); break; + case DT_RIGHT: SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_SETCURSEL, 1, 0); break; + } + + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("No avatar")); + if (ServiceExists(MS_AV_DRAWAVATAR)) + { + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Left avatar")); + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Right avatar")); + } + else + { + HWND hw = GetDlgItem(hwndDlg, IDC_CMB_AV); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_SPIN_AVSIZE); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_ED_AVSIZE); + EnableWindow(hw, FALSE); + } + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_SETCURSEL, (int)opt.avatarLayout, 0); + + SendDlgItemMessage(hwndDlg, IDC_SPIN_WIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_MINWIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_MAXHEIGHT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_MINHEIGHT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_AVSIZE, UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_INDENT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(400, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_TITLEINDENT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(400, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_VALUEINDENT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(400, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_PADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(128, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_TEXTPADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(128, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_OUTAVPADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(128, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_INAVPADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(128, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_HOVER, UDM_SETRANGE, 0, (LPARAM)MAKELONG(5000, 5)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_SBWIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 0)); + + SetDlgItemInt(hwndDlg, IDC_ED_WIDTH, opt.iWinWidth, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_MAXHEIGHT, opt.iWinMaxHeight, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_MINWIDTH, opt.iMinWidth, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_MINHEIGHT, opt.iMinHeight, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_AVSIZE, opt.iAvatarSize, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_INDENT, opt.iTextIndent, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_TITLEINDENT, opt.iTitleIndent, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_VALUEINDENT, opt.iValueIndent, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_PADDING, opt.iPadding, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_TEXTPADDING, opt.iTextPadding, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_OUTAVPADDING, opt.iOuterAvatarPadding, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_INAVPADDING, opt.iInnerAvatarPadding, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_HOVER, opt.iTimeIn, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_SBWIDTH, opt.iSidebarWidth, FALSE); + + CheckDlgButton(hwndDlg, IDC_CHK_ROUNDCORNERSAV, opt.bAvatarRound); + CheckDlgButton(hwndDlg, IDC_CHK_AVBORDER, opt.bAvatarBorder); + CheckDlgButton(hwndDlg, IDC_CHK_ORIGINALAVSIZE, opt.bOriginalAvatarSize); + + if (opt.bOriginalAvatarSize) + SetDlgItemText(hwndDlg, IDC_STATIC_AVATARSIZE, TranslateT("Max avatar size:")); + + return FALSE; + } + case WM_COMMAND: + { + if (LOWORD(wParam) == IDC_CHK_ORIGINALAVSIZE) + { + if (IsDlgButtonChecked(hwndDlg, IDC_CHK_ORIGINALAVSIZE)) + SetDlgItemText(hwndDlg, IDC_STATIC_AVATARSIZE, TranslateT("Max avatar size:")); + else + SetDlgItemText(hwndDlg, IDC_STATIC_AVATARSIZE, TranslateT("Avatar size:")); + } + + if (HIWORD(wParam) == CBN_SELCHANGE) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + else if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus()) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + else if (HIWORD(wParam) == BN_CLICKED) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + } + case WM_NOTIFY: + { + if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY) + { + BOOL trans; + int new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_WIDTH, &trans, FALSE); + if (trans) opt.iWinWidth = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_MINWIDTH, &trans, FALSE); + if (trans) opt.iMinWidth = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_MAXHEIGHT, &trans, FALSE); + if (trans) opt.iWinMaxHeight = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_MINHEIGHT, &trans, FALSE); + if (trans) opt.iMinHeight = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_AVSIZE, &trans, FALSE); + if (trans) opt.iAvatarSize = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_INDENT, &trans, FALSE); + if (trans) opt.iTextIndent = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_TITLEINDENT, &trans, FALSE); + if (trans) opt.iTitleIndent = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_VALUEINDENT, &trans, FALSE); + if (trans) opt.iValueIndent = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_PADDING, &trans, FALSE); + if (trans) opt.iPadding = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_TEXTPADDING, &trans, FALSE); + if (trans) opt.iTextPadding = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_OUTAVPADDING, &trans, FALSE); + if (trans) opt.iOuterAvatarPadding = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_INAVPADDING, &trans, FALSE); + if (trans) opt.iInnerAvatarPadding = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_HOVER, &trans, FALSE); + if (trans) opt.iTimeIn = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_SBWIDTH, &trans, FALSE); + if (trans) opt.iSidebarWidth = new_val; + + opt.titleLayout = (PopupTitleLayout)SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_GETCURSEL, 0, 0); + opt.avatarLayout = (PopupAvLayout)SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_GETCURSEL, 0, 0); + opt.pos = (PopupPosition)SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_GETCURSEL, 0, 0); + + opt.bAvatarBorder = IsDlgButtonChecked(hwndDlg, IDC_CHK_AVBORDER) ? true : false; + opt.bAvatarRound = IsDlgButtonChecked(hwndDlg, IDC_CHK_ROUNDCORNERSAV) && IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHK_ROUNDCORNERSAV)) ? true : false; + opt.bOriginalAvatarSize = IsDlgButtonChecked(hwndDlg, IDC_CHK_ORIGINALAVSIZE) ? true : false; + + opt.bShowNoFocus = IsDlgButtonChecked(hwndDlg, IDC_CHK_NOFOCUS) ? true : false; + opt.bStatusBarTips = IsDlgButtonChecked(hwndDlg, IDC_CHK_SBAR) ? true : false; + + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_GETCURSEL, 0, 0)) + { + case 0: opt.iLabelValign = DT_TOP; break; + case 1: opt.iLabelValign = DT_VCENTER; break; + case 2: opt.iLabelValign = DT_BOTTOM; break; + } + + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_GETCURSEL, 0, 0)) + { + case 0: opt.iValueValign = DT_TOP; break; + case 1: opt.iValueValign = DT_VCENTER; break; + case 2: opt.iValueValign = DT_BOTTOM; break; + } + + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_GETCURSEL, 0, 0)) + { + case 0: opt.iLabelHalign = DT_LEFT; break; + case 1: opt.iLabelHalign = DT_RIGHT; break; + } + + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_GETCURSEL, 0, 0)) + { + case 0: opt.iValueHalign = DT_LEFT; break; + case 1: opt.iValueHalign = DT_RIGHT; break; + } + + SaveOptions(); + return TRUE; + } + break; + } + } + + return 0; +} + +INT_PTR CALLBACK DlgProcOptsExtra(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + EXTRAICONDATA *dat; + dat = (EXTRAICONDATA *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + CheckDlgButton(hwndDlg, IDC_CHK_WAITFORCONTENT, opt.bWaitForContent); + CheckDlgButton(hwndDlg, IDC_CHK_GETSTATUSMSG, opt.bGetNewStatusMsg); + CheckDlgButton(hwndDlg, IDC_CHK_DISABLEINVISIBLE, opt.bDisableIfInvisible); + CheckDlgButton(hwndDlg, IDC_CHK_RETRIEVEXSTATUS, opt.bRetrieveXstatus); + CheckDlgButton(hwndDlg, IDC_CHK_LIMITMSG, opt.bLimitMsg); + CheckDlgButton(hwndDlg, IDC_CHK_ENABLESMILEYS, opt.iSmileyAddFlags & SMILEYADD_ENABLE); + CheckDlgButton(hwndDlg, IDC_CHK_USEPROTOSMILEYS, opt.iSmileyAddFlags & SMILEYADD_USEPROTO); + CheckDlgButton(hwndDlg, IDC_CHK_ONLYISOLATED, opt.iSmileyAddFlags & SMILEYADD_ONLYISOLATED); + CheckDlgButton(hwndDlg, IDC_CHK_RESIZESMILEYS, opt.iSmileyAddFlags & SMILEYADD_RESIZE); + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_DISABLEINVISIBLE), opt.bGetNewStatusMsg); + + BOOL bEnable = opt.iSmileyAddFlags & SMILEYADD_ENABLE; + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_USEPROTOSMILEYS), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_ONLYISOLATED), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_RESIZESMILEYS), bEnable); + + SendDlgItemMessage(hwndDlg, IDC_SPIN_CHARCOUNT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(1024, 16)); + SetDlgItemInt(hwndDlg, IDC_ED_CHARCOUNT, opt.iLimitCharCount, FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_CHARCOUNT), opt.bLimitMsg); + + HIMAGELIST himlStates = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 2, 2); + ImageList_AddIcon(himlStates, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); + ImageList_AddIcon(himlStates, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); + ImageList_AddIcon(himlStates, LoadSkinnedIcon(SKINICON_OTHER_TICK)); + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), himlStates, TVSIL_STATE); + + int i; + for (i = 0; i < EXICONS_COUNT; i++) + { + exIcons[i].order = opt.exIconsOrder[i]; + exIcons[i].vis = opt.exIconsVis[i]; + } + + dat = (EXTRAICONDATA *)mir_alloc(sizeof(EXTRAICONDATA)); + dat->bDragging = false; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), GWL_STYLE) | TVS_NOHSCROLL); + + TVINSERTSTRUCT tvi = {0}; + tvi.hParent = 0; + tvi.hInsertAfter = TVI_LAST; + tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE; + tvi.item.stateMask = TVIS_STATEIMAGEMASK; + for (i = 0; i < SIZEOF(extraIconName); i++ ) + { + tvi.item.lParam = (LPARAM)(&exIcons[i]); + tvi.item.pszText = TranslateTS(extraIconName[exIcons[i].order]); + tvi.item.state = INDEXTOSTATEIMAGEMASK(exIcons[i].vis ? 2 : 1); + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &tvi); + } + + return TRUE; + } + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDC_CHK_ENABLESMILEYS: + { + BOOL bEnable; + bEnable = IsDlgButtonChecked(hwndDlg, IDC_CHK_ENABLESMILEYS); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_RESIZESMILEYS), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_USEPROTOSMILEYS), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_ONLYISOLATED), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_RESIZESMILEYS), bEnable); + break; + } + case IDC_CHK_LIMITMSG: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_CHARCOUNT), IsDlgButtonChecked(hwndDlg, IDC_CHK_LIMITMSG)); + break; + } + case IDC_CHK_GETSTATUSMSG: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_DISABLEINVISIBLE), IsDlgButtonChecked(hwndDlg, IDC_CHK_GETSTATUSMSG)); + break; + } + } + + if ((HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == EN_CHANGE) && (HWND)lParam == GetFocus()) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + } + case WM_NOTIFY: + { + switch (((LPNMHDR)lParam)->idFrom) + { + case 0: + { + if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY) + { + TVITEM item = {0}; + int i = 0; + DBCONTACTWRITESETTING cws; + cws.szModule = MODULE; + cws.szSetting = "IconOrder"; + cws.value.type = DBVT_BLOB; + cws.value.cpbVal = SIZEOF(extraIconName); + cws.value.pbVal = opt.exIconsOrder; + + item.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS)); + while (item.hItem != NULL) + { + item.mask = TVIF_HANDLE | TVIF_PARAM; + TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &item); + opt.exIconsOrder[i++] = ((ICONSTATE *)item.lParam)->order; + item.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg,IDC_TREE_EXTRAICONS), item.hItem); + } + CallService(MS_DB_CONTACT_WRITESETTING, 0,(LPARAM)&cws); + + i = 0; + cws.szModule = MODULE; + cws.szSetting = "icons_vis"; + cws.value.type = DBVT_BLOB; + cws.value.cpbVal = SIZEOF(extraIconName); + cws.value.pbVal = opt.exIconsVis; + item.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_TREE_EXTRAICONS)); + + while (item.hItem != NULL) + { + item.mask = TVIF_HANDLE | TVIF_PARAM; + TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &item); + opt.exIconsVis[i++] = ((ICONSTATE *)item.lParam)->vis; + item.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), item.hItem); + } + CallService(MS_DB_CONTACT_WRITESETTING, 0, (LPARAM)&cws); + + opt.iSmileyAddFlags = 0; + opt.iSmileyAddFlags |= (IsDlgButtonChecked(hwndDlg, IDC_CHK_ENABLESMILEYS) ? SMILEYADD_ENABLE : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_USEPROTOSMILEYS) ? SMILEYADD_USEPROTO : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_ONLYISOLATED) ? SMILEYADD_ONLYISOLATED : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_CHK_RESIZESMILEYS) ? SMILEYADD_RESIZE : 0); + + opt.bWaitForContent = IsDlgButtonChecked(hwndDlg, IDC_CHK_WAITFORCONTENT) ? true : false; + opt.bGetNewStatusMsg = IsDlgButtonChecked(hwndDlg, IDC_CHK_GETSTATUSMSG) ? true : false; + opt.bDisableIfInvisible = IsDlgButtonChecked(hwndDlg, IDC_CHK_DISABLEINVISIBLE) ? true : false; + opt.bRetrieveXstatus = IsDlgButtonChecked(hwndDlg, IDC_CHK_RETRIEVEXSTATUS) ? true : false; + opt.bLimitMsg = IsDlgButtonChecked(hwndDlg, IDC_CHK_LIMITMSG) ? true : false; + opt.iLimitCharCount = GetDlgItemInt(hwndDlg, IDC_ED_CHARCOUNT, 0, FALSE); + + DBWriteContactSettingDword(0, MODULE, "SmileyAddFlags", opt.iSmileyAddFlags); + DBWriteContactSettingByte(0, MODULE, "WaitForContent", opt.bWaitForContent ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "GetNewStatusMsg", opt.bGetNewStatusMsg ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "DisableInvisible", opt.bDisableIfInvisible ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "RetrieveXStatus", opt.bRetrieveXstatus ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "LimitMsg", opt.bLimitMsg ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "LimitCharCount", opt.iLimitCharCount); + + return TRUE; + } + break; + } + case IDC_TREE_EXTRAICONS: + { + switch (((LPNMHDR)lParam)->code) + { + case TVN_BEGINDRAGA: + case TVN_BEGINDRAGW: + { + SetCapture(hwndDlg); + dat->bDragging = true; + dat->hDragItem = ((LPNMTREEVIEW)lParam)->itemNew.hItem; + TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), dat->hDragItem); + break; + } + case NM_CLICK: + { + TVHITTESTINFO hti; + hti.pt.x = (short)LOWORD(GetMessagePos()); + hti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt); + if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti)) + { + if (hti.flags & TVHT_ONITEMSTATEICON) + { + TVITEMA item; + item.mask = TVIF_HANDLE | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK; + item.hItem = hti.hItem; + TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item); + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 1) + { + item.state = INDEXTOSTATEIMAGEMASK(2); + ((ICONSTATE *)item.lParam)->vis = 1; + } + else + { + item.state = INDEXTOSTATEIMAGEMASK(1); + ((ICONSTATE *)item.lParam)->vis = 0; + } + + TreeView_SetItem(((LPNMHDR)lParam)->hwndFrom, &item); + SendMessage((GetParent(hwndDlg)), PSM_CHANGED, (WPARAM)hwndDlg, 0); + } + } + break; + } + } + break; + } + } + break; + } + case WM_MOUSEMOVE: + { + if (!dat->bDragging) + break; + + TVHITTESTINFO hti; + hti.pt.x = (short)LOWORD(lParam); + hti.pt.y = (short)HIWORD(lParam); + ClientToScreen(hwndDlg, &hti.pt); + ScreenToClient(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &hti.pt); + TreeView_HitTest(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &hti); + if (hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT)) + { + HTREEITEM hItem = hti.hItem; + hti.pt.y -= TreeView_GetItemHeight(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS)) / 2; + TreeView_HitTest(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &hti); + if (!(hti.flags & TVHT_ABOVE)) + TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), hti.hItem, 1); + else + TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), hItem, 0); + } + else + { + if (hti.flags & TVHT_ABOVE) + SendDlgItemMessage(hwndDlg, IDC_TREE_EXTRAICONS, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0); + if (hti.flags & TVHT_BELOW) + SendDlgItemMessage(hwndDlg, IDC_TREE_EXTRAICONS, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0); + + TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), 0, 0); + } + break; + } + case WM_LBUTTONUP: + { + if (!dat->bDragging) + break; + + TreeView_SetInsertMark(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), 0, 0); + dat->bDragging = false; + ReleaseCapture(); + + TVHITTESTINFO hti; + hti.pt.x = (short)LOWORD(lParam); + hti.pt.y = (short)HIWORD(lParam); + ClientToScreen(hwndDlg, &hti.pt); + ScreenToClient(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &hti.pt); + hti.pt.y -= TreeView_GetItemHeight(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS)) / 2; + TreeView_HitTest(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &hti); + if (dat->hDragItem == hti.hItem) + break; + + if (hti.flags & TVHT_ABOVE) + hti.hItem = TVI_FIRST; + + TVITEM item; + item.mask = TVIF_HANDLE | TVIF_PARAM; + item.hItem = dat->hDragItem; + TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &item); + if (hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT) || (hti.hItem == TVI_FIRST)) + { + TVINSERTSTRUCT tvis; + TCHAR swzName[256]; + tvis.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT | TVIF_STATE; + tvis.item.stateMask = TVIS_STATEIMAGEMASK; + tvis.item.pszText = swzName; + tvis.item.cchTextMax = 256; + tvis.item.hItem = dat->hDragItem; + tvis.item.state = INDEXTOSTATEIMAGEMASK(((ICONSTATE *)item.lParam)->vis ? 2 : 1); + TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &tvis.item); + TreeView_DeleteItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), dat->hDragItem); + tvis.hParent = NULL; + tvis.hInsertAfter = hti.hItem; + TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), &tvis)); + SendMessage((GetParent(hwndDlg)), PSM_CHANGED, (WPARAM)hwndDlg, 0); + } + + break; + } + case WM_DESTROY: + { + ImageList_Destroy(TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_TREE_EXTRAICONS), TVSIL_STATE)); + mir_free(dat); + break; + } + } + return 0; +} + +void EnableControls(HWND hwndDlg, BOOL bEnableSkin) +{ + ShowWindow(GetDlgItem(hwndDlg, IDC_ST_PREVIEW), (bEnableSkin && opt.szPreviewFile[0]) ? SW_HIDE : SW_SHOW); + ShowWindow(GetDlgItem(hwndDlg, IDC_PIC_PREVIEW), (bEnableSkin && opt.szPreviewFile[0]) ? SW_SHOW : SW_HIDE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_SHADOW), !bEnableSkin); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_BORDER), !bEnableSkin); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_ROUNDCORNERS), !bEnableSkin); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_LOADFONTS), bEnableSkin); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_LOADPROPORTIONS), bEnableSkin); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_ENABLECOLORING), bEnableSkin && opt.iEnableColoring != -1); +} + +int iLastSel; +INT_PTR CALLBACK DlgProcOptsSkin(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + iLastSel = RefreshSkinList(hwndDlg); + + SendDlgItemMessage(hwndDlg, IDC_BTN_RELOADLIST, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_BTN_RELOADLIST, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Reload skin list"), BATF_TCHAR); + HICON hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_RELOAD)); + SendDlgItemMessage(hwndDlg, IDC_BTN_RELOADLIST, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + DestroyIcon(hIcon); + + SendDlgItemMessage(hwndDlg, IDC_BTN_APPLYSKIN, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_BTN_APPLYSKIN, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Apply skin"), BATF_TCHAR); + hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APPLY)); + SendDlgItemMessage(hwndDlg, IDC_BTN_APPLYSKIN, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + DestroyIcon(hIcon); + + SendDlgItemMessage(hwndDlg, IDC_BTN_GETSKINS, BUTTONSETASFLATBTN, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_BTN_GETSKINS, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Get more skins"), BATF_TCHAR); + SendDlgItemMessage(hwndDlg, IDC_BTN_GETSKINS, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_URL)); + + + SendDlgItemMessage(hwndDlg, IDC_SPIN_TRANS, UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 0)); + SetDlgItemInt(hwndDlg, IDC_ED_TRANS, opt.iOpacity, FALSE); + + CheckDlgButton(hwndDlg, IDC_CHK_BORDER, opt.bBorder); + CheckDlgButton(hwndDlg, IDC_CHK_ROUNDCORNERS, opt.bRound); + CheckDlgButton(hwndDlg, IDC_CHK_SHADOW, opt.bDropShadow); + CheckDlgButton(hwndDlg, IDC_CHK_AEROGLASS, opt.bAeroGlass); + CheckDlgButton(hwndDlg, IDC_CHK_LOADFONTS, opt.bLoadFonts); + CheckDlgButton(hwndDlg, IDC_CHK_LOADPROPORTIONS, opt.bLoadProportions); + if (opt.iEnableColoring != -1) + CheckDlgButton(hwndDlg, IDC_CHK_ENABLECOLORING, opt.iEnableColoring ? 1 : 0); + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_AEROGLASS), MyDwmEnableBlurBehindWindow != 0); + + SendDlgItemMessage(hwndDlg, IDC_CMB_EFFECT, CB_ADDSTRING, 0, (LPARAM)TranslateT("None")); + SendDlgItemMessage(hwndDlg, IDC_CMB_EFFECT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Animation")); + SendDlgItemMessage(hwndDlg, IDC_CMB_EFFECT, CB_ADDSTRING, 0, (LPARAM)TranslateT("Fade")); + SendDlgItemMessage(hwndDlg, IDC_CMB_EFFECT, CB_SETCURSEL, (int)opt.showEffect, 0); + + SendDlgItemMessage(hwndDlg, IDC_SPIN_SPEED, UDM_SETRANGE, 0, (LPARAM)MAKELONG(20, 1)); + SetDlgItemInt(hwndDlg, IDC_ED_SPEED, opt.iAnimateSpeed, FALSE); + + EnableControls(hwndDlg, opt.skinMode == SM_IMAGE); + return TRUE; + } + case WM_DRAWITEM: + { + if (wParam == IDC_PIC_PREVIEW) + { + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam; + HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE); + FillRect(dis->hDC, &dis->rcItem, hbr); + + if (opt.szPreviewFile[0]) + { + HDC hdcMem = CreateCompatibleDC(dis->hDC); + HBITMAP hbmpPreview = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)opt.szPreviewFile, IMGL_TCHAR); + if (hbmpPreview) + { + int iWidth = dis->rcItem.right - dis->rcItem.left; + int iHeight = dis->rcItem.bottom - dis->rcItem.top; + + ResizeBitmap rb = {0}; + rb.size = sizeof(rb); + rb.hBmp = hbmpPreview; + rb.max_width = iWidth; + rb.max_height = iHeight; + rb.fit = RESIZEBITMAP_KEEP_PROPORTIONS; + HBITMAP hbmpRes = (HBITMAP)CallService(MS_IMG_RESIZE, (WPARAM)&rb, 0); + if (hbmpRes) + { + BITMAP bmp; + GetObject(hbmpRes, sizeof(bmp), &bmp); + SelectObject(hdcMem, hbmpRes); + BitBlt(dis->hDC, (iWidth - bmp.bmWidth) / 2, (iHeight - bmp.bmHeight) / 2, iWidth, iHeight, hdcMem, 0, 0, SRCCOPY); + if (hbmpPreview != hbmpRes) + DeleteBitmap(hbmpRes); + } + + DeleteBitmap(hbmpPreview); + } + + DeleteDC(hdcMem); + } + } + break; + } + case WM_COMMAND: + { + switch (HIWORD(wParam)) + { + case LBN_SELCHANGE: + { + if (LOWORD(wParam) == IDC_LB_SKINS) + { + HWND hwndList = GetDlgItem(hwndDlg, IDC_LB_SKINS); + int iSel = ListBox_GetCurSel(hwndList); + if (iSel != iLastSel) + { + if (iSel == 0) + { + opt.szPreviewFile[0] = 0; + EnableControls(hwndDlg, FALSE); + } + else if (iSel != LB_ERR) + { + TCHAR swzSkinName[256]; + if (ListBox_GetText(hwndList, iSel, swzSkinName) > 0) + ParseSkinFile(swzSkinName, false, true); + EnableControls(hwndDlg, TRUE); + if (opt.iEnableColoring != -1) + CheckDlgButton(hwndDlg, IDC_CHK_ENABLECOLORING, opt.iEnableColoring ? 1 : 0); + } + + InvalidateRect(GetDlgItem(hwndDlg, IDC_PIC_PREVIEW), 0, FALSE); + iLastSel = iSel; + } + } + else if (LOWORD(wParam) == IDC_CMB_EFFECT) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + + break; + } + case BN_CLICKED: + { + if (LOWORD(wParam) == IDC_BTN_APPLYSKIN) + { + int iSel = ListBox_GetCurSel(GetDlgItem(hwndDlg, IDC_LB_SKINS)); + if (iSel == 0) + { + opt.skinMode = SM_COLORFILL; + opt.szSkinName[0] = 0; + } + else if (iSel != LB_ERR) + { + if (ListBox_GetText(GetDlgItem(hwndDlg, IDC_LB_SKINS), iSel, opt.szSkinName) > 0) + { + opt.skinMode = SM_IMAGE; + ParseSkinFile(opt.szSkinName, false, false); + ReloadFont(0, 0); + SaveOptions(); + } + } + + DBWriteContactSettingByte(0, MODULE, "SkinEngine", opt.skinMode); + DBWriteContactSettingTString(0, MODULE, "SkinName", opt.szSkinName); + + DestroySkinBitmap(); + SetDlgItemInt(hwndDlg, IDC_ED_TRANS, opt.iOpacity, FALSE); + } + else if (LOWORD(wParam) == IDC_BTN_RELOADLIST) + iLastSel = RefreshSkinList(hwndDlg); + else if (LOWORD(wParam) == IDC_CHK_LOADFONTS) + opt.bLoadFonts = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOADFONTS) ? true : false; + else if (LOWORD(wParam) == IDC_CHK_LOADPROPORTIONS) + opt.bLoadProportions = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOADPROPORTIONS) ? true : false; + else if (LOWORD(wParam) == IDC_BTN_GETSKINS) + CallService(MS_UTILS_OPENURL, 0, (LPARAM)"http://www.miranda-easy.net/tipper"); + + break; + } + } + + if ((HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == EN_CHANGE) && (HWND)lParam == GetFocus()) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + } + case WM_NOTIFY: + { + if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY ) + { + opt.iOpacity = GetDlgItemInt(hwndDlg, IDC_ED_TRANS, 0, 0); + opt.bDropShadow = IsDlgButtonChecked(hwndDlg, IDC_CHK_SHADOW) ? true : false; + opt.bBorder = IsDlgButtonChecked(hwndDlg, IDC_CHK_BORDER) ? true : false; + opt.bRound = IsDlgButtonChecked(hwndDlg, IDC_CHK_ROUNDCORNERS) ? true : false; + opt.bAeroGlass = IsDlgButtonChecked(hwndDlg, IDC_CHK_AEROGLASS) ? true : false; + opt.showEffect = (PopupShowEffect)SendDlgItemMessage(hwndDlg, IDC_CMB_EFFECT, CB_GETCURSEL, 0, 0); + opt.iAnimateSpeed = GetDlgItemInt(hwndDlg, IDC_ED_SPEED, 0, 0); + opt.bLoadFonts = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOADFONTS) ? true : false; + opt.bLoadProportions = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOADPROPORTIONS) ? true : false; + + if (opt.iEnableColoring != -1) + opt.iEnableColoring = IsDlgButtonChecked(hwndDlg, IDC_CHK_ENABLECOLORING) ? true : false; + + SaveSkinOptions(); + return TRUE; + } + } + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcFavouriteContacts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT)) + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) FALSE, 0); + else + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) TRUE, 0); + + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETHIDEEMPTYGROUPS, 1, 0); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETLEFTMARGIN, 2, 0); + + HANDLE hContact, hItem; + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem && DBGetContactSettingByte(hContact, MODULE, "FavouriteContact", 0)) + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM)hItem, 1); + + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } + + CheckDlgButton(hwndDlg, IDC_CHK_HIDEOFFLINE, opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE); + CheckDlgButton(hwndDlg, IDC_CHK_APPENDPROTO, opt.iFavoriteContFlags & FAVCONT_APPEND_PROTO); + + return TRUE; + } + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDC_BTN_OK: + { + HANDLE hContact, hItem; + BYTE isChecked; + int count = 0; + + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + { + isChecked = (BYTE)SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM)hItem, 0); + DBWriteContactSettingByte(hContact, MODULE, "FavouriteContact", isChecked); + if (isChecked) count++; + } + + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } + DBWriteContactSettingDword(0, MODULE, "FavouriteContactsCount", count); + + opt.iFavoriteContFlags = 0; + opt.iFavoriteContFlags |= IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDEOFFLINE) ? FAVCONT_HIDE_OFFLINE : 0 | + IsDlgButtonChecked(hwndDlg, IDC_CHK_APPENDPROTO) ? FAVCONT_APPEND_PROTO : 0; + + DBWriteContactSettingDword(0, MODULE, "FavContFlags", opt.iFavoriteContFlags); + } // fall through + case IDC_BTN_CANCEL: + { + DestroyWindow(hwndDlg); + break; + } + } + return TRUE; + } + case WM_CLOSE: + { + DestroyWindow(hwndDlg); + return TRUE; + } + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcOptsTraytip(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + CheckDlgButton(hwndDlg, IDC_CHK_ENABLETRAYTIP, opt.bTraytip); + CheckDlgButton(hwndDlg, IDC_CHK_HANDLEBYTIPPER, opt.bHandleByTipper); + CheckDlgButton(hwndDlg, IDC_CHK_EXPAND, opt.bExpandTraytip); + CheckDlgButton(hwndDlg, IDC_CHK_HIDEOFFLINE, opt.bHideOffline); + SendDlgItemMessage(hwndDlg, IDC_SPIN_EXPANDTIME, UDM_SETRANGE, 0, (LPARAM)MAKELONG(5000, 10)); + SetDlgItemInt(hwndDlg, IDC_ED_EXPANDTIME, opt.iExpandTime, FALSE); + SendMessage(hwndDlg, WM_COMMAND, MAKELONG(IDC_CHK_ENABLETRAYTIP, 0), 0); + + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_FIRST_PROTOS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_FIRST_PROTOS), GWL_STYLE) | TVS_NOHSCROLL); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_SECOND_PROTOS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_SECOND_PROTOS), GWL_STYLE) | TVS_NOHSCROLL); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), GWL_STYLE) | TVS_NOHSCROLL); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_SECOND_ITEMS), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TREE_SECOND_ITEMS), GWL_STYLE) | TVS_NOHSCROLL); + + HIMAGELIST himlCheckBoxes; + himlCheckBoxes = ImageList_Create(16, 16, IsWinVerXPPlus() ? ILC_COLOR32 | ILC_MASK : ILC_COLOR8 | ILC_MASK, 3, 0); + ImageList_AddIcon(himlCheckBoxes, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); + ImageList_AddIcon(himlCheckBoxes, LoadSkinnedIcon(SKINICON_OTHER_NOTICK)); + ImageList_AddIcon(himlCheckBoxes, LoadSkinnedIcon(SKINICON_OTHER_TICK)); + + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_FIRST_PROTOS), himlCheckBoxes, TVSIL_STATE); + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_SECOND_PROTOS), himlCheckBoxes, TVSIL_STATE); + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), himlCheckBoxes, TVSIL_STATE); + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_SECOND_ITEMS), himlCheckBoxes, TVSIL_STATE); + + TVINSERTSTRUCT tvi = {0}; + tvi.hParent = 0; + tvi.hInsertAfter = TVI_LAST; + tvi.item.mask = TVIF_TEXT | TVIF_STATE; + + int i, count = 0; + PROTOACCOUNT **accs; + ProtoEnumAccounts(&count, &accs); + + for (i = 0; i < count; i++) + { + if (accs[i]->type == PROTOTYPE_PROTOCOL && CallProtoService(accs[i]->szModuleName, PS_GETCAPS, PFLAGNUM_2, 0) != 0) + { + tvi.item.pszText = accs[i]->tszAccountName; + tvi.item.stateMask = TVIS_STATEIMAGEMASK; + tvi.item.state = INDEXTOSTATEIMAGEMASK(IsTrayProto(accs[i]->tszAccountName, false) ? 2 : 1); + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_PROTOS), &tvi); + tvi.item.state = INDEXTOSTATEIMAGEMASK(IsTrayProto(accs[i]->tszAccountName, true) ? 2 : 1); + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_SECOND_PROTOS), &tvi); + } + } + + for (i = 0; i < SIZEOF(trayTipItems); i++) + { + tvi.item.pszText = TranslateTS(trayTipItems[i]); + tvi.item.state = INDEXTOSTATEIMAGEMASK(opt.iFirstItems & (1 << i) ? 2 : 1); + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), &tvi); + tvi.item.state = INDEXTOSTATEIMAGEMASK(opt.iSecondItems & (1 << i) ? 2 : 1); + TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_TREE_SECOND_ITEMS), &tvi); + } + + return TRUE; + } + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + UINT state; + case IDC_CHK_ENABLETRAYTIP: + { + state = IsDlgButtonChecked(hwndDlg, IDC_CHK_ENABLETRAYTIP); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_HANDLEBYTIPPER), state); + } // fall through + case IDC_CHK_HANDLEBYTIPPER: + { + state = IsDlgButtonChecked(hwndDlg, IDC_CHK_HANDLEBYTIPPER) & + IsDlgButtonChecked(hwndDlg, IDC_CHK_ENABLETRAYTIP); + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_HIDEOFFLINE), state); + EnableWindow(GetDlgItem(hwndDlg, IDC_TREE_FIRST_PROTOS), state); + EnableWindow(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), state); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_FAVCONTACTS), state); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_EXPAND), state); + } // fall through + case IDC_CHK_EXPAND: + { + state = IsDlgButtonChecked(hwndDlg, IDC_CHK_HANDLEBYTIPPER) & + IsDlgButtonChecked(hwndDlg, IDC_CHK_ENABLETRAYTIP) & + IsDlgButtonChecked(hwndDlg, IDC_CHK_EXPAND); + EnableWindow(GetDlgItem(hwndDlg, IDC_TREE_SECOND_PROTOS), state); + EnableWindow(GetDlgItem(hwndDlg, IDC_TREE_SECOND_ITEMS), state); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_EXPANDTIME), state); + break; + } + case IDC_BTN_FAVCONTACTS: + { + CreateDialog(hInst, MAKEINTRESOURCE(IDD_FAVCONTACTS), 0, DlgProcFavouriteContacts); + break; + } + } + + if ((HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == EN_CHANGE) && (HWND)lParam == GetFocus()) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + + break; + } + case WM_NOTIFY: + { + switch (((LPNMHDR)lParam)->idFrom) + { + case 0: + { + if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY) + { + TCHAR buff[256]; + TCHAR swzProtos[1024] = {0}; + + TVITEM item; + item.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_TREE_FIRST_PROTOS)); + item.pszText = buff; + item.cchTextMax = 256; + item.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK; + while (item.hItem != NULL) + { + TreeView_GetItem(GetDlgItem(hwndDlg,IDC_TREE_FIRST_PROTOS), &item); + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 2) + { + _tcscat(swzProtos, buff); + _tcscat(swzProtos, _T(" ")); + } + + item.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_PROTOS), item.hItem); + } + + DBWriteContactSettingTString(0, MODULE, "TrayProtocols", swzProtos); + + swzProtos[0] = 0; + item.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_TREE_SECOND_PROTOS)); + item.pszText = buff; + while (item.hItem != NULL) + { + TreeView_GetItem(GetDlgItem(hwndDlg,IDC_TREE_SECOND_PROTOS), &item); + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 2) + { + _tcscat(swzProtos, buff); + _tcscat(swzProtos, _T(" ")); + } + + item.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_SECOND_PROTOS), item.hItem); + } + + DBWriteContactSettingTString(0, MODULE, "TrayProtocolsEx", swzProtos); + + int count = 0; + opt.iFirstItems = 0; + item.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_TREE_FIRST_ITEMS)); + item.mask = TVIF_HANDLE | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK; + while (item.hItem != NULL) + { + TreeView_GetItem(GetDlgItem(hwndDlg,IDC_TREE_FIRST_ITEMS), &item); + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 2) + opt.iFirstItems |= (1 << count); + + item.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_FIRST_ITEMS), item.hItem); + count++; + } + + count = 0; + opt.iSecondItems = 0; + item.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_TREE_SECOND_ITEMS)); + while (item.hItem != NULL) + { + TreeView_GetItem(GetDlgItem(hwndDlg,IDC_TREE_SECOND_ITEMS), &item); + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 2) + opt.iSecondItems |= (1 << count); + + item.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg, IDC_TREE_SECOND_ITEMS), item.hItem); + count++; + } + + opt.bTraytip = IsDlgButtonChecked(hwndDlg, IDC_CHK_ENABLETRAYTIP) ? true : false; + opt.bHandleByTipper = IsDlgButtonChecked(hwndDlg, IDC_CHK_HANDLEBYTIPPER) ? true : false; + opt.bExpandTraytip = IsDlgButtonChecked(hwndDlg, IDC_CHK_EXPAND) ? true : false; + opt.bHideOffline = IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDEOFFLINE) ? true : false; + opt.iExpandTime = max(min(GetDlgItemInt(hwndDlg, IDC_ED_EXPANDTIME, 0, FALSE), 5000), 10); + + DBWriteContactSettingByte(0, MODULE, "TrayTip", (opt.bTraytip ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "ExtendedTrayTip", (opt.bHandleByTipper ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "ExpandTrayTip", (opt.bExpandTraytip ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "HideOffline", (opt.bHideOffline ? 1 : 0)); + DBWriteContactSettingDword(0, MODULE, "ExpandTime", opt.iExpandTime); + DBWriteContactSettingDword(0, MODULE, "TrayTipItems", opt.iFirstItems); + DBWriteContactSettingDword(0, MODULE, "TrayTipItemsEx", opt.iSecondItems); + return TRUE; + } + break; + } + case IDC_TREE_FIRST_PROTOS: + case IDC_TREE_SECOND_PROTOS: + case IDC_TREE_FIRST_ITEMS: + case IDC_TREE_SECOND_ITEMS: + { + if (((LPNMHDR)lParam)->code == NM_CLICK) + { + TVHITTESTINFO hti; + hti.pt.x = (short)LOWORD(GetMessagePos()); + hti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt); + if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti)) + { + if (hti.flags & TVHT_ONITEMSTATEICON) + { + TVITEMA item = {0}; + item.hItem = hti.hItem; + item.mask = TVIF_HANDLE | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK; + TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &item); + + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 1) + item.state = INDEXTOSTATEIMAGEMASK(2); + else + item.state = INDEXTOSTATEIMAGEMASK(1); + + TreeView_SetItem(((LPNMHDR)lParam)->hwndFrom, &item); + SendMessage((GetParent(hwndDlg)), PSM_CHANGED, (WPARAM)hwndDlg, 0); + } + } + } + break; + } + } + break; + } + case WM_DESTROY: + { + ImageList_Destroy(TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_TREE_FIRST_PROTOS), TVSIL_STATE)); + break; + } + } + + return FALSE; +} + +int OptInit(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = {0}; + odp.cbSize = sizeof(odp); + odp.flags = ODPF_BOLDGROUPS; + odp.position = -790000000; + odp.hInstance = hInst; + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_APPEARANCE); + odp.pszTab = LPGEN("Appearance"); + odp.pszTitle = LPGEN("Tooltips"); + odp.pszGroup = LPGEN("Customize"); + odp.pfnDlgProc = DlgProcOptsAppearance; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SKIN); + odp.pszTab = LPGEN("Tooltips"); + odp.pszGroup = LPGEN("Skins"); + odp.pfnDlgProc = DlgProcOptsSkin; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CONTENT); + odp.pszTab = LPGEN("Content"); + odp.pszTitle = LPGEN("Tooltips"); + odp.pszGroup = LPGEN("Customize"); + odp.pfnDlgProc = DlgProcOptsContent; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_TRAYTIP); + odp.pszTab = LPGEN("Tray tooltip"); + odp.pszTitle = LPGEN("Tooltips"); + odp.pszGroup = LPGEN("Customize"); + odp.pfnDlgProc = DlgProcOptsTraytip; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_EXTRA); + odp.pszTab = LPGEN("Extra"); + odp.pszTitle = LPGEN("Tooltips"); + odp.pszGroup = LPGEN("Customize"); + odp.pfnDlgProc = DlgProcOptsExtra; + Options_AddPage(wParam, &odp); + + return 0; +} + +HANDLE hEventOptInit; + +void InitOptions() +{ + hEventOptInit = HookEvent(ME_OPT_INITIALISE, OptInit); +} + +void DeinitOptions() +{ + UnhookEvent(hEventOptInit); + + DIListNode *di_node = opt.diList; + while(opt.diList) + { + di_node = opt.diList; + opt.diList = opt.diList->next; + mir_free(di_node); + } + + DSListNode *ds_node = opt.dsList; + while(opt.dsList) + { + ds_node = opt.dsList; + opt.dsList = opt.dsList->next; + mir_free(ds_node); + } + + for (int i = 0; i < SKIN_ITEMS_COUNT; i++) + { + if (opt.szImgFile[i]) + mir_free(opt.szImgFile[i]); + } +} diff --git a/plugins/TipperYM/src/options.h b/plugins/TipperYM/src/options.h new file mode 100644 index 0000000000..52411110fb --- /dev/null +++ b/plugins/TipperYM/src/options.h @@ -0,0 +1,196 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _OPTIONS_INC +#define _OPTIONS_INC + +#include "translations.h" +#include "popwin.h" +#include "bitmap_func.h" +#include "skin_parser.h" + +#define WMU_ENABLE_LIST_BUTTONS (WM_USER + 0x030) +#define WMU_ENABLE_MODULE_ENTRY (WM_USER + 0x031) + +#define LABEL_LEN 1024 +#define VALUE_LEN 8192 +#define MODULE_NAME_LEN 512 +#define SETTING_NAME_LEN 512 + +// chekcbox icons +#define IDI_NOTICK 205 +#define IDI_TICK 206 +#define IDPRESETITEM 1000 + +#define MS_TOOLTIP_SHOWTIP "mToolTip/ShowTip" + +typedef struct { + UINT id, uintCoreIconId, uintResIconId; + TCHAR *swzTooltip; +} OPTBUTTON; + +typedef struct { + TCHAR swzLabel[LABEL_LEN]; + TCHAR swzValue[VALUE_LEN]; + bool bLineAbove, bValueNewline; + bool bIsVisible; + bool bParseTipperVarsFirst; +} DISPLAYITEM; + +typedef enum {DVT_DB = 0, DVT_PROTODB = 1} DisplaySubstType; +typedef struct { + TCHAR swzName[LABEL_LEN]; + DisplaySubstType type; + char szModuleName[MODULE_NAME_LEN]; + char szSettingName[SETTING_NAME_LEN]; + int iTranslateFuncId; +} DISPLAYSUBST; + +struct DSListNode { + DISPLAYSUBST ds; + DSListNode *next; +}; + +struct DIListNode { + DISPLAYITEM di; + DIListNode *next; +}; + +typedef struct { + BYTE top; + BYTE right; + BYTE bottom; + BYTE left; +} MARGINS; + +// tray tooltip items +static TCHAR* trayTipItems[TRAYTIP_ITEMS_COUNT] = +{ + LPGENT("Number of contacts"), + LPGENT("Protocol lock status"), + LPGENT("Logon time"), + LPGENT("Unread emails"), + LPGENT("Status"), + LPGENT("Status message"), + LPGENT("Extra status"), + LPGENT("Listening to"), + LPGENT("Favourite contacts"), + LPGENT("Miranda uptime"), + LPGENT("Clist event") +}; + +// extra icons +static TCHAR* extraIconName[6] = +{ + LPGENT("Status"), + LPGENT("Extra status"), + LPGENT("Jabber activity"), + LPGENT("Gender"), + LPGENT("Country flag"), + LPGENT("Client") +}; + +typedef struct { + bool bDragging; + HTREEITEM hDragItem; +} EXTRAICONDATA; + +typedef struct { + BYTE order; + BYTE vis; +} ICONSTATE; + +typedef enum {PAV_NONE=0, PAV_LEFT=1, PAV_RIGHT=2} PopupAvLayout; +typedef enum {PTL_LEFTICON=0, PTL_RIGHTICON=1, PTL_NOICON=2, PTL_NOTITLE=3} PopupTitleLayout; +typedef enum {PP_BOTTOMRIGHT=0, PP_BOTTOMLEFT=1, PP_TOPRIGHT=2, PP_TOPLEFT=3} PopupPosition; +typedef enum {PSE_NONE=0, PSE_ANIMATE=1, PSE_FADE=2} PopupShowEffect; + +typedef struct { + int iWinWidth, iWinMaxHeight, iAvatarSize; //tweety + PopupTitleLayout titleLayout; + PopupAvLayout avatarLayout; + int iTextIndent, iTitleIndent, iValueIndent; + bool bShowNoFocus; + DSListNode *dsList; + int iDsCount; + DIListNode *diList; + int iDiCount; + int iTimeIn; + int iPadding, iOuterAvatarPadding, iInnerAvatarPadding, iTextPadding; + PopupPosition pos; + int iMinWidth, iMinHeight; // no UI for these + int iMouseTollerance; + bool bStatusBarTips; + int iSidebarWidth; + COLORREF colBg, colBorder, colAvatarBorder, colDivider, colBar, colTitle, colLabel, colValue, colTrayTitle, colSidebar; + int iLabelValign, iLabelHalign, iValueValign, iValueHalign; + bool bWaitForStatusMsg, bWaitForAvatar; + + // tooltip skin + SkinMode skinMode; + TCHAR szSkinName[256]; + TCHAR szPreviewFile[1024]; + TCHAR *szImgFile[SKIN_ITEMS_COUNT]; + MARGINS margins[SKIN_ITEMS_COUNT]; + TransformationMode transfMode[SKIN_ITEMS_COUNT]; + PopupShowEffect showEffect; + bool bLoadFonts; + bool bLoadProportions; + int iEnableColoring; + int iAnimateSpeed; + int iOpacity; + int iAvatarOpacity; + bool bBorder; + bool bRound, bAvatarRound; + bool bDropShadow; + bool bAeroGlass; + + // tray tooltip + bool bTraytip; + bool bHandleByTipper; + bool bExpandTraytip; + bool bHideOffline; + int iExpandTime; + int iFirstItems, iSecondItems; + int iFavoriteContFlags; + + // extra setting + bool bOriginalAvatarSize; + bool bAvatarBorder; + bool bWaitForContent; + bool bGetNewStatusMsg; + bool bDisableIfInvisible; + bool bRetrieveXstatus; + bool bLimitMsg; + int iLimitCharCount; + int iSmileyAddFlags; + BYTE exIconsOrder[EXICONS_COUNT]; + BYTE exIconsVis[EXICONS_COUNT]; +} OPTIONS; + + +extern OPTIONS opt; + +void InitOptions(); +void LoadOptions(); +void SaveOptions(); +void DeinitOptions(); + +#endif diff --git a/plugins/TipperYM/src/popwin.cpp b/plugins/TipperYM/src/popwin.cpp new file mode 100644 index 0000000000..964069ce2d --- /dev/null +++ b/plugins/TipperYM/src/popwin.cpp @@ -0,0 +1,2016 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "subst.h" +#include "popwin.h" +#include "message_pump.h" +#include "str_utils.h" +#include "bitmap_func.h" +#include "translations.h" +#include "m_gender.h" + +extern TOOLTIPSKIN skin; + +__inline void AddRow(PopupWindowData *pwd, TCHAR *swzLabel, TCHAR *swzValue, char *szProto, bool bParseSmileys, bool bNewline, bool bLineAbove, bool bIsTitle = false, HICON hIcon = NULL) +{ + pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData) * (pwd->iRowCount + 1)); + pwd->rows[pwd->iRowCount].swzLabel = swzLabel ? mir_tstrdup(swzLabel) : NULL; + pwd->rows[pwd->iRowCount].swzValue = swzValue ? mir_tstrdup(swzValue) : NULL; + pwd->rows[pwd->iRowCount].spi = bParseSmileys ? Smileys_PreParse(swzValue, (int)_tcslen(swzValue), szProto) : NULL; + pwd->rows[pwd->iRowCount].bValueNewline = bNewline; + pwd->rows[pwd->iRowCount].bLineAbove = bLineAbove; + pwd->rows[pwd->iRowCount].bIsTitle = bIsTitle; + pwd->rows[pwd->iRowCount].hIcon = hIcon; + pwd->iRowCount++; +} + +LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PopupWindowData *pwd = (PopupWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch(uMsg) + { + case WM_CREATE: + { + CREATESTRUCT *cs = (CREATESTRUCT *)lParam; + pwd = (PopupWindowData *)mir_alloc(sizeof(PopupWindowData)); + memset(pwd, 0, sizeof(PopupWindowData)); + pwd->clcit = *(CLCINFOTIPEX *)cs->lpCreateParams; + pwd->iIconIndex = -1; + pwd->hpenBorder = CreatePen(PS_SOLID, 1, opt.bBorder ? opt.colBorder : opt.colBg); + pwd->hpenDivider = CreatePen(PS_SOLID, 1, opt.colDivider); + pwd->iTrans = (int)(opt.iOpacity / 100.0 * 255); + + // load icons order + for (int i = 0; i < EXICONS_COUNT; i++) + pwd->bIsIconVisible[opt.exIconsOrder[i]] = opt.exIconsVis[i] ? true : false; + + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pwd); + + // work around bug hiding tips + GetCursorPos(&pwd->ptCursorStartPos); + SetTimer(hwnd, ID_TIMER_CHECKMOUSE, CHECKMOUSE_ELAPSE, 0); + + //Register copy menu hotkey (CTRL+C) + pwd->iHotkeyId = GlobalAddAtom(_T("Tipper")); + RegisterHotKey(hwnd, pwd->iHotkeyId, MOD_CONTROL, 0x43); + + if (pwd->clcit.szProto) + { + pwd->bIsTextTip= false; + pwd->iIndent = opt.iTextIndent; + pwd->iSidebarWidth= opt.iSidebarWidth; + + if (ServiceExists(MS_PROTO_GETACCOUNT)) + { + PROTOACCOUNT *pa = ProtoGetAccount(pwd->clcit.szProto); + if (pa) _tcscpy(pwd->swzTitle, pa->tszAccountName); + } + + if (_tcslen(pwd->swzTitle) == 0) + a2t(pwd->clcit.szProto, pwd->swzTitle, TITLE_TEXT_LEN); + + if (CallService(MS_PROTO_ISACCOUNTLOCKED,0,(LPARAM)pwd->clcit.szProto)) + mir_sntprintf(pwd->swzTitle, SIZEOF(pwd->swzTitle), TranslateT("%s (locked)"), pwd->swzTitle); + + // protocol status + WORD wStatus = (WORD)CallProtoService(pwd->clcit.szProto, PS_GETSTATUS, 0, 0); + + // get status icon + if (pwd->bIsIconVisible[0]) + { + pwd->extraIcons[0].hIcon = LoadSkinnedProtoIcon(pwd->clcit.szProto, wStatus); + pwd->extraIcons[0].bDestroy = false; + } + + // get activity icon + if (pwd->bIsIconVisible[2]) + { + pwd->extraIcons[2].hIcon = GetJabberActivityIcon(0, pwd->clcit.szProto); + pwd->extraIcons[2].bDestroy = false; + } + + // uid info + TCHAR swzUid[256], swzUidName[256]; + if (Uid(0, pwd->clcit.szProto, swzUid, 256) && UidName(pwd->clcit.szProto, swzUidName, 253)) + { + _tcscat(swzUidName, _T(": ")); + AddRow(pwd, swzUidName, swzUid, NULL, false, false, false); + } + + // logon info + TCHAR swzLogon[64]; + if (TimestampToTimeDifference(NULL, pwd->clcit.szProto, "LogonTS", swzLogon, 59)) + { + _tcscat(swzLogon, TranslateT(" ago")); + AddRow(pwd, TranslateT("Log on:"), swzLogon, NULL, false, false, false); + } + + // logoff info + TCHAR swzLogoff[64]; + if (TimestampToTimeDifference(NULL, pwd->clcit.szProto, "LogoffTS", swzLogoff, 59)) + { + _tcscat(swzLogoff, TranslateT(" ago")); + AddRow(pwd, TranslateT("Log off:"), swzLogoff, NULL, false, false, false); + } + + // number of unread emails + TCHAR swzEmailCount[64]; + if (ProtoServiceExists(pwd->clcit.szProto, "/GetUnreadEmailCount")) + { + int iCount = (int)CallProtoService(pwd->clcit.szProto, "/GetUnreadEmailCount", 0, 0); + if (iCount > 0) + { + _itot(iCount, swzEmailCount, 10); + AddRow(pwd, TranslateT("Unread emails:"), swzEmailCount, NULL, false, false, false); + } + } + + TCHAR *swzText = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, wStatus, GSMDF_TCHAR); + if (swzText) + { + AddRow(pwd, TranslateT("Status:"), swzText, NULL, false, false, false); + } + + if (wStatus >= ID_STATUS_ONLINE && wStatus <= ID_STATUS_OUTTOLUNCH) + { + // status message + TCHAR *swzText = GetProtoStatusMessage(pwd->clcit.szProto, wStatus); + if (swzText) + { + StripBBCodesInPlace(swzText); + AddRow(pwd, TranslateT("Status message:"), swzText, pwd->clcit.szProto, true, true, true); + mir_free(swzText); + } + + // jabber mood or icq xstatus + TCHAR *swzAdvTitle = GetJabberAdvStatusText(pwd->clcit.szProto, "mood", "title"); + if (swzAdvTitle) + { + StripBBCodesInPlace(swzAdvTitle); + AddRow(pwd, TranslateT("Mood:"), swzAdvTitle, pwd->clcit.szProto, true, false, true); + + TCHAR *swzAdvText = GetJabberAdvStatusText(pwd->clcit.szProto, "mood", "text"); + if (swzAdvText) + { + StripBBCodesInPlace(swzAdvText); + AddRow(pwd, _T(""), swzAdvText, pwd->clcit.szProto, true, true, false); + mir_free(swzAdvText); + } + } + else + { + if (DBGetContactSettingByte(0, pwd->clcit.szProto, "XStatusId", 0)) + { + // xstatus title + swzAdvTitle = GetProtoExtraStatusTitle(pwd->clcit.szProto); + if (swzAdvTitle) + { + StripBBCodesInPlace(swzAdvTitle); + AddRow(pwd, TranslateT("XStatus:"), swzAdvTitle, pwd->clcit.szProto, true, false, true); + } + + // xstatus message + TCHAR *swzAdvText = GetProtoExtraStatusMessage(pwd->clcit.szProto); + if (swzAdvText) + { + StripBBCodesInPlace(swzAdvText); + AddRow(pwd, _T(""), swzAdvText, pwd->clcit.szProto, true, true, false); + mir_free(swzAdvText); + } + } + } + + if (swzAdvTitle) + { + mir_free(swzAdvTitle); + // get advanced status icon + if (pwd->bIsIconVisible[1]) + { + pwd->extraIcons[1].hIcon = (HICON)CallProtoService(pwd->clcit.szProto, PS_ICQ_GETCUSTOMSTATUSICON, 0, 0); + pwd->extraIcons[1].bDestroy = true; + } + } + + // jabber activity + TCHAR *swzActTitle = GetJabberAdvStatusText(pwd->clcit.szProto, "activity", "title"); + if (swzActTitle) + { + StripBBCodesInPlace(swzActTitle); + AddRow(pwd, TranslateT("Activity:"), swzActTitle, pwd->clcit.szProto, true, false, true); + mir_free(swzActTitle); + } + + TCHAR *swzActText = GetJabberAdvStatusText(pwd->clcit.szProto, "activity", "text"); + if (swzActText) + { + StripBBCodesInPlace(swzActText); + AddRow(pwd, _T(""), swzActText, pwd->clcit.szProto, true, true, false); + mir_free(swzActText); + } + + // listening to + TCHAR *swzListening = GetListeningTo(pwd->clcit.szProto); + if (swzListening) + { + StripBBCodesInPlace(swzListening); + AddRow(pwd, TranslateT("Listening to:"), swzListening, NULL, false, true, true); + mir_free(swzListening); + } + } + } + else if (pwd->clcit.swzText) + { + pwd->bIsTextTip = true; + pwd->iIndent = 0; + pwd->iSidebarWidth= 0; + + RECT rc = pwd->clcit.rcItem; + bool mirandaTrayTip = ((rc.right - rc.left) == 20) && ((rc.bottom - rc.top) == 20) ? true : false; + + if (mirandaTrayTip && !opt.bTraytip) + { + MyDestroyWindow(hwnd); + return 0; + } + + if (mirandaTrayTip && opt.bHandleByTipper) // extended tray tooltip + { + pwd->bIsTrayTip = true; + pwd->iIndent = opt.iTextIndent; + pwd->iSidebarWidth= opt.iSidebarWidth; + + SendMessage(hwnd, PUM_REFRESHTRAYTIP, 0, 0); + + if (opt.bExpandTraytip) + SetTimer(hwnd, ID_TIMER_TRAYTIP, opt.iExpandTime, 0); + } + else + { + + TCHAR buff[2048], *swzText = pwd->clcit.swzText; + size_t iBuffPos, i = 0, iSize = _tcslen(pwd->clcit.swzText); + bool bTopMessage = false; + + while (i < iSize && swzText[i] != _T('<')) + { + iBuffPos = 0; + while (swzText[i] != _T('\n') && swzText[i] != _T('\r') && i < iSize && iBuffPos < 2048) + { + if (swzText[i] != _T('\t')) + buff[iBuffPos++] = swzText[i]; + i++; + } + + buff[iBuffPos] = 0; + + if (iBuffPos) + { + AddRow(pwd, _T(""), buff, NULL, false, true, false); + bTopMessage = true; + } + + while (i < iSize && (swzText[i] == _T('\n') || swzText[i] == _T('\r'))) + i++; + } + + // parse bold bits into labels and the rest into items + while (i < iSize) + { + while (i + 2 < iSize + && (swzText[i] != _T('<') + || swzText[i + 1] != _T('b') + || swzText[i + 2] != _T('>'))) + { + i++; + } + + i += 3; + + iBuffPos = 0; + while (i + 3 < iSize + && iBuffPos < 2048 + && (swzText[i] != _T('<') + || swzText[i + 1] != _T('/') + || swzText[i + 2] != _T('b') + || swzText[i + 3] != _T('>'))) + { + if (swzText[i] != _T('\t')) + buff[iBuffPos++] = swzText[i]; + i++; + } + + i += 4; + + buff[iBuffPos] = 0; + + if (iBuffPos) + { + pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData) * (pwd->iRowCount + 1)); + pwd->rows[pwd->iRowCount].bValueNewline = false; + pwd->rows[pwd->iRowCount].swzLabel = mir_tstrdup(buff); + if (pwd->iRowCount == 1 && bTopMessage) + pwd->rows[pwd->iRowCount].bLineAbove = true; + else + pwd->rows[pwd->iRowCount].bLineAbove = false; + + iBuffPos = 0; + while (i < iSize + && iBuffPos < 2048 + && swzText[i] != _T('\n')) + { + if (swzText[i] != _T('\t') && swzText[i] != _T('\r')) + buff[iBuffPos++] = swzText[i]; + i++; + } + buff[iBuffPos] = 0; + + pwd->rows[pwd->iRowCount].swzValue = mir_tstrdup(buff); + pwd->rows[pwd->iRowCount].spi = NULL; + pwd->iRowCount++; + } + + i++; + } + + if (pwd->iRowCount == 0) + { + // single item + pwd->iRowCount = 1; + pwd->rows = (RowData *)mir_alloc(sizeof(RowData)); + pwd->rows[0].bLineAbove = pwd->rows[0].bValueNewline = false; + pwd->rows[0].swzLabel = 0; + pwd->rows[0].swzValue = swzText; + pwd->rows[0].spi = NULL; + } + } + } + else + { + pwd->bIsTextTip = false; + pwd->iIndent = opt.iTextIndent; + pwd->iSidebarWidth= opt.iSidebarWidth; + pwd->hContact = pwd->clcit.hItem; + pwd->iIconIndex = (int)CallService(MS_CLIST_GETCONTACTICON, (WPARAM)pwd->hContact, 0); + + // don't use stored status message + if (!opt.bWaitForContent) + DBDeleteContactSetting(pwd->hContact, MODULE, "TempStatusMsg"); + + TCHAR *swzNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pwd->hContact, GCDNF_TCHAR); + _tcsncpy(pwd->swzTitle, swzNick, TITLE_TEXT_LEN); + + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)pwd->hContact, 0); + pwd->spiTitle = Smileys_PreParse(pwd->swzTitle, -1, szProto); + + // get extra icons + DBVARIANT dbv = {0}; + int i = 0; + + if (szProto) + { + // status icon + if (pwd->bIsIconVisible[0]) + { + for (i = 0; opt.exIconsOrder[i] != 0; i++); + pwd->extraIcons[i].hIcon = ImageList_GetIcon((HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0), pwd->iIconIndex, 0); + pwd->extraIcons[i].bDestroy = true; + } + + // xstatus icon + if (pwd->bIsIconVisible[1]) + { + for (i = 0; opt.exIconsOrder[i] != 1; i++); + int iXstatus = DBGetContactSettingByte(pwd->hContact, szProto, "XStatusId", 0); + if (iXstatus) + { + char szIconProto[64]; + if (strcmp(szProto, szMetaModuleName) != 0) + { + strcpy(szIconProto, szProto); + } + else if (!DBGetContactSettingString(pwd->hContact, szProto, "XStatusProto", &dbv)) + { + strcpy(szIconProto, dbv.pszVal); + DBFreeVariant(&dbv); + } + + pwd->extraIcons[i].hIcon = (HICON)CallProtoService(szIconProto, PS_ICQ_GETCUSTOMSTATUSICON, (WPARAM)iXstatus, LR_SHARED); + pwd->extraIcons[i].bDestroy = false; + } + } + + // activity icon + if (pwd->bIsIconVisible[2]) + { + for (i = 0; opt.exIconsOrder[i] != 2; i++); + pwd->extraIcons[i].hIcon = GetJabberActivityIcon(pwd->hContact, szProto); + pwd->extraIcons[i].bDestroy = false; + } + + // gender icon + if (pwd->bIsIconVisible[3]) + { + for (i = 0; opt.exIconsOrder[i] != 3; i++); + if (ServiceExists(MS_GENDER_GETICON)) + { + pwd->extraIcons[i].hIcon = (HICON)CallService(MS_GENDER_GETICON, (WPARAM)pwd->hContact, 0); + } + else + { + int iGender = DBGetContactSettingByte(pwd->hContact, "UserInfo", "Gender", 0); + if (iGender == 0) + iGender = DBGetContactSettingByte(pwd->hContact, szProto, "Gender", 0); + + if (iGender == GEN_FEMALE) + pwd->extraIcons[i].hIcon = (HICON)CallService(MS_SKIN2_GETICON, NULL, (LPARAM)"UserInfoEx_common_female"); + else if (iGender == GEN_MALE) + pwd->extraIcons[i].hIcon = (HICON)CallService(MS_SKIN2_GETICON, NULL, (LPARAM)"UserInfoEx_common_male"); + } + pwd->extraIcons[i].bDestroy = false; + } + + // flags icon + if (pwd->bIsIconVisible[4]) + { + for (i = 0; opt.exIconsOrder[i] != 4; i++); + + int iCountry = 0; + if (ServiceExists(MS_FLAGS_DETECTCONTACTORIGINCOUNTRY)) + iCountry = CallService(MS_FLAGS_DETECTCONTACTORIGINCOUNTRY, (WPARAM)pwd->hContact, 0); + else if (ServiceExists(MS_FLAGS_GETCONTACTORIGINCOUNTRY)) + iCountry = CallService(MS_FLAGS_GETCONTACTORIGINCOUNTRY, (WPARAM)pwd->hContact, 0); + + if (iCountry != 0 && iCountry != CTRY_UNKNOWN && iCountry != CTRY_ERROR) + { + pwd->extraIcons[i].hIcon = LoadFlagIcon(iCountry); + pwd->extraIcons[i].bDestroy = false; + } + } + + // fingerprint icon + if (pwd->bIsIconVisible[5]) + { + + if (ServiceExists(MS_FP_GETCLIENTICONT)) + { + for (i = 0; opt.exIconsOrder[i] != 5; i++); + if (!DBGetContactSettingTString(pwd->hContact, szProto, "MirVer", &dbv)) + { + pwd->extraIcons[i].hIcon = (HICON)CallService(MS_FP_GETCLIENTICONT, (WPARAM)dbv.ptszVal, 0); + pwd->extraIcons[i].bDestroy = true; + DBFreeVariant(&dbv); + } + } + else + + if (ServiceExists(MS_FP_GETCLIENTICON)) + { + for (i = 0; opt.exIconsOrder[i] != 5; i++); + if (!DBGetContactSettingString(pwd->hContact, szProto, "MirVer", &dbv)) + { + pwd->extraIcons[i].hIcon = (HICON)CallService(MS_FP_GETCLIENTICON, (WPARAM)dbv.pszVal, 0); + pwd->extraIcons[i].bDestroy = true; + DBFreeVariant(&dbv); + } + } + } + + //request xstatus details + if (opt.bRetrieveXstatus) + { + if (!DBGetContactSettingByte(0, szProto, "XStatusAuto", 1) && ProtoServiceExists(szProto, PS_ICQ_REQUESTCUSTOMSTATUS)) + CallProtoService(szProto, PS_ICQ_REQUESTCUSTOMSTATUS, (WPARAM)pwd->hContact, 0); + } + } + + SendMessage(hwnd, PUM_REFRESH_VALUES, FALSE, 0); + } + + SendMessage(hwnd, PUM_GETHEIGHT, 0, 0); + SendMessage(hwnd, PUM_CALCPOS, 0, 0); + + // transparency + SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); + + if (opt.bDropShadow && opt.skinMode == SM_COLORFILL) + SetClassLongPtr(hwnd, GCL_STYLE, CS_DROPSHADOW); + else + SetClassLongPtr(hwnd, GCL_STYLE, 0); + + if (!skin.bNeedLayerUpdate && MySetLayeredWindowAttributes) + MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), 0, LWA_ALPHA); + + if (opt.showEffect) + SetTimer(hwnd, ID_TIMER_ANIMATE, ANIM_ELAPSE, 0); + + ShowWindow(hwnd, SW_SHOWNOACTIVATE); + InvalidateRect(hwnd, 0, FALSE); + + // since tipper win is topmost, this should put it at top of topmost windows + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + return 0; + } + case WM_ERASEBKGND: + { + if (!skin.bNeedLayerUpdate) + { + HDC hdc = (HDC)wParam; + RECT rc; + GetClientRect(hwnd, &rc); + + BitBlt(hdc, 0, 0, skin.iWidth, skin.iHeight, skin.hdc, 0, 0, SRCCOPY); + + // border + if (opt.bBorder) + { + HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); + HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenBorder); + + int h = 0; + if (opt.bRound) + { + int v; + int w = 14; + h = (rc.right-rc.left) > (w*2) ? w : (rc.right-rc.left); + v = (rc.bottom-rc.top) > (w*2) ? w : (rc.bottom-rc.top); + h = (h < v) ? h : v; + } + + RoundRect(hdc, 0, 0, (rc.right - rc.left), (rc.bottom - rc.top), h, h); + + SelectObject(hdc, hOldBrush); + SelectObject(hdc, hOldPen); + } + } + return TRUE; + } + case WM_PAINT: + { + RECT r, r2; + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + HDC hdc = skin.bNeedLayerUpdate ? skin.hdc : ps.hdc; + + GetClientRect(hwnd, &r); + r2 = r; + HFONT hOldFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT); + + // text background + SetBkMode(hdc, TRANSPARENT); + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + + // avatar + if (!pwd->bIsTextTip&& opt.avatarLayout != PAV_NONE && pwd->iAvatarHeight) + { + RECT rcAvatar; + rcAvatar.top = opt.iOuterAvatarPadding; + + if (opt.avatarLayout == PAV_LEFT) + { + rcAvatar.left = r.left + opt.iOuterAvatarPadding; + rcAvatar.right = rcAvatar.left + pwd->iRealAvatarWidth; + r2.left += pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding); // padding re-added for text + } + else if (opt.avatarLayout == PAV_RIGHT) + { + rcAvatar.right = r.right - opt.iOuterAvatarPadding; + rcAvatar.left = rcAvatar.right - pwd->iRealAvatarWidth; + r2.right -= pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding); + } + + rcAvatar.bottom = rcAvatar.top + pwd->iRealAvatarHeight; + + AVATARCACHEENTRY *ace = 0; + if (pwd->hContact) + ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)pwd->hContact, 0); + else + ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto); + + if (ace && ace->hbmPic && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) + { + ResizeBitmap rb = {0}; + rb.size = sizeof(rb); + rb.max_width = pwd->iRealAvatarWidth; + rb.max_height = pwd->iRealAvatarHeight; + rb.fit = RESIZEBITMAP_STRETCH | RESIZEBITMAP_KEEP_PROPORTIONS; + rb.hBmp = ace->hbmPic; + HBITMAP hbmpAvatar = (HBITMAP)CallService(MS_IMG_RESIZE, (WPARAM)&rb, 0); + + if (hbmpAvatar) + { + HRGN hrgnAvatar = 0; + if (opt.bAvatarRound) + { + hrgnAvatar = CreateRoundRectRgn(rcAvatar.left, rcAvatar.top, rcAvatar.right + 1, rcAvatar.bottom + 1, 9, 9); + SelectClipRgn(hdc, hrgnAvatar); + } + + BITMAP bm; + GetObject(hbmpAvatar, sizeof(bm), &bm); + HDC hdcMem = CreateCompatibleDC(hdc); + SelectObject(hdcMem, hbmpAvatar); + + blend.SourceConstantAlpha = (BYTE)(opt.iAvatarOpacity / 100.0 * 255); + AlphaBlend(hdc, rcAvatar.left, rcAvatar.top, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, blend); + blend.SourceConstantAlpha = 255; + + if (opt.bAvatarBorder) + { + SaveAlpha(&rcAvatar); + HBRUSH hbrBorder = CreateSolidBrush(opt.colAvatarBorder); + if (opt.bAvatarRound) + FrameRgn(hdc, hrgnAvatar, hbrBorder, 1, 1); + else + FrameRect(hdc, &rcAvatar, hbrBorder); + + DeleteObject(hbrBorder); + RestoreAlpha(&rcAvatar, (BYTE)(opt.iAvatarOpacity / 100.0 * 255)); + } + + if (hrgnAvatar) + { + SelectClipRgn(hdc, 0); + DeleteObject(hrgnAvatar); + } + + if (hbmpAvatar != ace->hbmPic) + DeleteObject(hbmpAvatar); + + DeleteDC(hdcMem); + } + } + } + + RECT tr; + tr.left = r2.left + opt.iPadding + opt.iTitleIndent; + tr.right = r2.right - opt.iPadding; + tr.top = 0; + tr.bottom = opt.iPadding; + + if (!pwd->bIsTextTip&& opt.titleLayout != PTL_NOTITLE) + { + if (opt.titleLayout != PTL_NOICON) + { + // draw icons + int iIconX, iIconY; + iIconY = opt.iPadding + opt.iTextPadding; + + if (opt.titleLayout == PTL_RIGHTICON) + iIconX = r2.right - 16 - opt.iPadding; + else + iIconX = r2.left + opt.iPadding; + + for (int i = 0; i < EXICONS_COUNT; i++) + { + if (pwd->extraIcons[i].hIcon) + { + DrawIconExAlpha(hdc, iIconX, iIconY, pwd->extraIcons[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false); + iIconY += 20; + } + } + } + + // title text + if (hFontTitle) SelectObject(hdc, (HGDIOBJ)hFontTitle); + SetTextColor(hdc, opt.colTitle); + tr.top = opt.iPadding; + tr.bottom = tr.top + pwd->iTitleHeight - opt.iPadding; + UINT uTextFormat = DT_TOP | DT_LEFT | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX; + DrawTextExt(hdc, pwd->swzTitle, -1, &tr, uTextFormat, NULL, pwd->spiTitle); + } + + // values + pwd->iTextHeight = 0; + bool bIconPainted, bUseRect = true; + int iRowHeight; + for (int i = 0; i < pwd->iRowCount; i++) + { + tr.top = tr.bottom; + bUseRect = (tr.top + opt.iTextPadding >= pwd->iAvatarHeight); + bIconPainted = false; + if (bUseRect) + { + if (pwd->rows[i].bLineAbove) + { + HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenDivider); + tr.top += opt.iTextPadding; + RECT rec; + SetRect(&rec, r.left + opt.iPadding + pwd->iIndent, tr.top, r.right - opt.iPadding, tr.top + 1); + SaveAlpha(&rec); + Rectangle(hdc, rec.left, rec.top, rec.right, rec.bottom ); + RestoreAlpha(&rec); + SelectObject(hdc, hOldPen); + } + + tr.left = r.left + opt.iPadding + pwd->iIndent; + if (pwd->rows[i].bValueNewline) + tr.right = r.right - opt.iPadding; + else + tr.right = r.left + opt.iPadding + pwd->iIndent + pwd->iLabelWidth; + } + else + { + if (pwd->rows[i].bLineAbove) + { + HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenDivider); + tr.top += opt.iTextPadding; + RECT rec; + SetRect(&rec, r2.left + opt.iPadding + pwd->iIndent, tr.top, r2.right - opt.iPadding, tr.top + 1); + SaveAlpha(&rec); + Rectangle(hdc, rec.left, rec.top, rec.right, rec.bottom ); + RestoreAlpha(&rec); + SelectObject(hdc, hOldPen); + } + + tr.left = r2.left + opt.iPadding + pwd->iIndent; + if (pwd->rows[i].bValueNewline) + tr.right = r2.right - opt.iPadding; + else + tr.right = r2.left + opt.iPadding + pwd->iIndent + pwd->iLabelWidth; + } + + if (pwd->rows[i].bValueNewline) + iRowHeight = pwd->rows[i].iLabelHeight; + else + iRowHeight = max(pwd->rows[i].iLabelHeight, pwd->rows[i].iValueHeight); + + if (pwd->rows[i].iLabelHeight) + { + tr.top += opt.iTextPadding; + tr.bottom = tr.top + iRowHeight; + + if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) + { + if (hFontTrayTitle) SelectObject(hdc, (HGDIOBJ)hFontTrayTitle); + SetTextColor(hdc, opt.colTrayTitle); + } + else + { + if (hFontLabels) SelectObject(hdc, (HGDIOBJ)hFontLabels); + SetTextColor(hdc, opt.colLabel); + } + + // status icon in tray tooltip + if (opt.titleLayout != PTL_NOICON && pwd->bIsTrayTip && pwd->rows[i].hIcon) + { + DrawIconExAlpha(hdc, opt.iPadding, tr.top + (pwd->rows[i].iLabelHeight - 16) / 2, pwd->rows[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false); + bIconPainted = true; + } + + DrawTextAlpha(hdc, pwd->rows[i].swzLabel, -1, &tr, opt.iLabelValign | ((opt.iLabelHalign == DT_RIGHT && !pwd->rows[i].bValueNewline) ? DT_RIGHT : DT_LEFT) | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX); + if (pwd->rows[i].bValueNewline) + tr.top = tr.bottom; + } + else + { + tr.bottom = tr.top; + } + + if (pwd->rows[i].bValueNewline) + iRowHeight = pwd->rows[i].iValueHeight; + + if (hFontValues) SelectObject(hdc, (HGDIOBJ)hFontValues); + SetTextColor(hdc, opt.colValue); + if (bUseRect) + { + tr.left = r.left + opt.iPadding + pwd->iIndent; + if (!pwd->rows[i].bValueNewline) + tr.left += pwd->iLabelWidth + opt.iValueIndent; + + tr.right = r.right - opt.iPadding; + } + else + { + tr.left = r2.left + opt.iPadding + pwd->iIndent; + if (!pwd->rows[i].bValueNewline) + tr.left += pwd->iLabelWidth + opt.iValueIndent; + + tr.right = r2.right - opt.iPadding; + } + + if (pwd->rows[i].iValueHeight) + { + if (pwd->rows[i].bValueNewline || !pwd->rows[i].iLabelHeight) tr.top += opt.iTextPadding; + if (pwd->rows[i].iLabelHeight > pwd->rows[i].iValueHeight && pwd->bIsTextTip&& pwd->rows[i].bIsTitle) + tr.top = tr.bottom - pwd->rows[i].iValueHeight - 2; + else + tr.bottom = tr.top + iRowHeight; + + if (opt.titleLayout != PTL_NOICON && pwd->bIsTrayTip && pwd->rows[i].hIcon && !bIconPainted) + DrawIconExAlpha(hdc, opt.iPadding, tr.top + (pwd->rows[i].iValueHeight - 16) / 2, pwd->rows[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false); + + UINT uFormat = opt.iValueValign | opt.iValueHalign | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX; + DrawTextExt(hdc, pwd->rows[i].swzValue, -1, &tr, uFormat, NULL, pwd->rows[i].spi); + } + } + + PremultipleChannels(); + + if (opt.showEffect == PSE_NONE) + { + if (skin.bNeedLayerUpdate) + { + POINT ptSrc = {0, 0}; + SIZE szTip = {r.right - r.left, r.bottom - r.top}; + blend.SourceConstantAlpha = pwd->iTrans; + MyUpdateLayeredWindow(hwnd, NULL, NULL, &szTip, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA); + + if (opt.bAeroGlass && MyDwmEnableBlurBehindWindow) + { + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.fEnable = TRUE; + bb.hRgnBlur = CreateOpaqueRgn(25, true); + MyDwmEnableBlurBehindWindow(hwnd, &bb); + } + } + else if (MySetLayeredWindowAttributes) + { + MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), pwd->iTrans, LWA_ALPHA); + } + } + + SelectObject(hdc, hOldFont); + EndPaint(hwnd, &ps); + pwd->bIsPainted = true; + return 0; + } + case WM_HOTKEY: + { + if (LOWORD(lParam) == MOD_CONTROL && HIWORD(lParam) == 0x43) // CTRL+C + { + ICONINFO iconInfo; + + if (pwd->iRowCount == 0) + return 0; + + ShowWindow(hwnd, SW_HIDE); + HMENU hMenu = CreatePopupMenu(); + if (!hMenu) return 0; + + HICON hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ITEM_ALL), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT); + if (!hIcon) + { + DestroyMenu(hMenu); + return 0; + } + + GetIconInfo(hIcon, &iconInfo); + HBITMAP hbmpAllItems = iconInfo.hbmColor; + DestroyIcon(hIcon); + + AppendMenu(hMenu, MF_STRING, COPYMENU_ALLITEMS_LABELS, LPGENT("Copy all items with labels")); + AppendMenu(hMenu, MF_STRING, COPYMENU_ALLITEMS, LPGENT("Copy all items")); + if (pwd->clcit.szProto || pwd->hContact) + AppendMenu(hMenu, MF_STRING, COPYMENU_AVATAR, LPGENT("Copy avatar")); + AppendMenu(hMenu, MF_SEPARATOR, 2000, 0); + TranslateMenu(hMenu); + + SetMenuItemBitmaps(hMenu, COPYMENU_ALLITEMS_LABELS, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems); + SetMenuItemBitmaps(hMenu, COPYMENU_ALLITEMS, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems); + SetMenuItemBitmaps(hMenu, COPYMENU_AVATAR, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems); + + hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ITEM), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT); + if (!hIcon) + { + DeleteObject(hbmpAllItems); + DestroyMenu(hMenu); + return 0; + } + + GetIconInfo(hIcon, &iconInfo); + HBITMAP hbmpItem = iconInfo.hbmColor; + DestroyIcon(hIcon); + + for (int i = 0; i < pwd->iRowCount; i++) + { + if (pwd->rows[i].swzValue) + { + TCHAR buff[128]; + int iLen = (int)_tcslen(pwd->rows[i].swzValue); + if (iLen) + { + if (iLen > MAX_VALUE_LEN) + { + _tcsncpy(buff, pwd->rows[i].swzValue, MAX_VALUE_LEN); + buff[MAX_VALUE_LEN] = 0; + _tcscat(buff, _T("...")); + } + else + { + _tcscpy(buff, pwd->rows[i].swzValue); + } + + AppendMenu(hMenu, MF_STRING, i + 1, buff); // first id = 1, because no select have id = 0 + SetMenuItemBitmaps(hMenu, i + 1, MF_BYCOMMAND, hbmpItem, hbmpItem); + } + else + { + AppendMenu(hMenu, MF_SEPARATOR, 0, 0); + } + } + } + + POINT pt; + GetCursorPos(&pt); + SetForegroundWindow(hwnd); + int iSelItem = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, 0); + DeleteObject(hbmpAllItems); + DeleteObject(hbmpItem); + DestroyMenu(hMenu); + + if (iSelItem == 0) + return 0; // no item was selected + + if (OpenClipboard(NULL)) + { + EmptyClipboard(); + if (iSelItem == COPYMENU_AVATAR) // copy avatar + { + AVATARCACHEENTRY *ace = 0; + if (pwd->hContact) ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)pwd->hContact, 0); + else ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto); + if (ace && ace->hbmPic && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) + { + HDC hdc = GetDC(hwnd); + HDC hdcSrc = CreateCompatibleDC(hdc); + HDC hdcDes = CreateCompatibleDC(hdc); + HBITMAP hbmAvr = CreateCompatibleBitmap(hdc, ace->bmWidth, ace->bmHeight); + SelectObject(hdcSrc, ace->hbmPic); + SelectObject(hdcDes, hbmAvr); + BitBlt(hdcDes, 0, 0, ace->bmWidth, ace->bmHeight, hdcSrc, 0, 0, SRCCOPY); + SetClipboardData(CF_BITMAP, hbmAvr); + ReleaseDC(hwnd, hdc); + DeleteDC(hdcSrc); + DeleteDC(hdcDes); + } + } + else // copy text + { + HGLOBAL hClipboardData = GlobalAlloc(GMEM_DDESHARE, 4096); + TCHAR *pchData = (TCHAR *)GlobalLock(hClipboardData); + pchData[0] = 0; + if (iSelItem == COPYMENU_ALLITEMS_LABELS) // copy all items with labels + { + for (int i = 0; i < pwd->iRowCount; i++) + { + if ((pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0]) || + (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0])) + { + if (pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0]) + { + _tcscat(pchData, pwd->rows[i].swzLabel); + _tcscat(pchData, _T(" ")); + } + else + { + _tcscat(pchData, TranslateT(": ")); + } + + if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0]) + _tcscat(pchData, pwd->rows[i].swzValue); + else + _tcscat(pchData, TranslateT("")); + + _tcscat(pchData, _T("\r\n")); + } + } + } + else if (iSelItem == COPYMENU_ALLITEMS) // copy all items + { + for (int i = 0; i < pwd->iRowCount; i++) + { + if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0]) + { + _tcscat(pchData, pwd->rows[i].swzValue); + _tcscat(pchData, _T("\r\n")); + } + } + } + else // single row + { + _tcscpy(pchData, pwd->rows[iSelItem - 1].swzValue); + } + + GlobalUnlock(hClipboardData); + + SetClipboardData(CF_UNICODETEXT, hClipboardData); + + } + + CloseClipboard(); + } + } + break; + } + case PUM_FADEOUTWINDOW: + { + // kill timers + KillTimer(hwnd, ID_TIMER_ANIMATE); + KillTimer(hwnd, ID_TIMER_CHECKMOUSE); + KillTimer(hwnd, ID_TIMER_TRAYTIP); + + if (opt.showEffect != PSE_NONE) + { + if (skin.bNeedLayerUpdate) + { + POINT ptSrc = {0, 0}; + SIZE sz = {pwd->rcWindow.right - pwd->rcWindow.left, pwd->rcWindow.bottom - pwd->rcWindow.top}; + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = pwd->iTrans; + blend.AlphaFormat = AC_SRC_ALPHA; + + while (blend.SourceConstantAlpha != 0) + { + MyUpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA); + blend.SourceConstantAlpha = max(blend.SourceConstantAlpha - opt.iAnimateSpeed, 0); + Sleep(ANIM_ELAPSE); + } + } + else if (MySetLayeredWindowAttributes) + { + int iTrans = pwd->iTrans; + while (iTrans != 0) + { + MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), iTrans, LWA_ALPHA); + iTrans = max(iTrans - opt.iAnimateSpeed, 0); + Sleep(ANIM_ELAPSE); + } + } + } + break; + } + case WM_DESTROY: + { + ShowWindow(hwnd, SW_HIDE); + + // unregister hotkey + UnregisterHotKey(hwnd, pwd->iHotkeyId); + + DeleteObject(pwd->hpenBorder); + DeleteObject(pwd->hpenDivider); + + if (pwd->hrgnAeroGlass) + DeleteObject(pwd->hrgnAeroGlass); + + Smileys_FreeParse(pwd->spiTitle); + + int i; + for (i = 0; i < pwd->iRowCount; i++) + { + mir_free(pwd->rows[i].swzLabel); + mir_free(pwd->rows[i].swzValue); + Smileys_FreeParse(pwd->rows[i].spi); + } + + if (pwd->rows) + mir_free(pwd->rows); + pwd->rows = NULL; + + // destroy icons + for (i = 0; i < EXICONS_COUNT; i++) + { + if (pwd->extraIcons[i].bDestroy) + DestroyIcon(pwd->extraIcons[i].hIcon); + } + + if (pwd->clcit.swzText) + { + mir_free(pwd->clcit.swzText); + pwd->clcit.swzText = NULL; + } + + mir_free(pwd); + pwd = NULL; + + if (skin.colSavedBits) mir_free(skin.colSavedBits); + if (skin.hBitmap)DeleteObject(skin.hBitmap); + if (skin.hdc) DeleteDC(skin.hdc); + skin.colSavedBits = NULL; + skin.hBitmap = NULL; + skin.hdc = NULL; + + SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); + break; + } + case WM_TIMER: + { + if (wParam == ID_TIMER_ANIMATE) + { + pwd->iAnimStep++; + if (pwd->iAnimStep == ANIM_STEPS) + KillTimer(hwnd, ID_TIMER_ANIMATE); + + SendMessage(hwnd, PUM_UPDATERGN, 1, 0); + } + else if (wParam == ID_TIMER_CHECKMOUSE) + { + // workaround for tips that just won't go away + POINT pt; + GetCursorPos(&pt); + + if (abs(pt.x - pwd->ptCursorStartPos.x) > opt.iMouseTollerance + || abs(pt.y - pwd->ptCursorStartPos.y) > opt.iMouseTollerance) // mouse has moved beyond tollerance + { + PostMPMessage(MUM_DELETEPOPUP, 0, 0); + } + } + else if (wParam == ID_TIMER_TRAYTIP) + { + KillTimer(hwnd, ID_TIMER_TRAYTIP); + SendMessage(hwnd, PUM_EXPANDTRAYTIP, 0, 0); + } + + break; + } + case PUM_SETSTATUSTEXT: + { + if (pwd && (HANDLE)wParam == pwd->hContact) + { + DBWriteContactSettingTString(pwd->hContact, MODULE, "TempStatusMsg", (TCHAR *)lParam); + pwd->bIsPainted = false; + pwd->bNeedRefresh = true; + SendMessage(hwnd, PUM_REFRESH_VALUES, TRUE, 0); + InvalidateRect(hwnd, 0, TRUE); + } + + if (lParam) mir_free((void *)lParam); + return TRUE; + } + case PUM_SHOWXSTATUS: + { + if (pwd && (HANDLE)wParam == pwd->hContact) + { + // in case we have retrieve xstatus + pwd->bIsPainted = false; + SendMessage(hwnd, PUM_REFRESH_VALUES, TRUE, 0); + InvalidateRect(hwnd, 0, TRUE); + } + return TRUE; + } + case PUM_SETAVATAR: + { + if (pwd && (HANDLE)wParam == pwd->hContact) + { + pwd->bIsPainted = false; + SendMessage(hwnd, PUM_GETHEIGHT, 0, 0); + SendMessage(hwnd, PUM_CALCPOS, 0, 0); + InvalidateRect(hwnd, 0, TRUE); + } + return TRUE; + } + case PUM_EXPANDTRAYTIP: + { + pwd->bIsPainted = false; + if (skin.bNeedLayerUpdate) + { + RECT r = pwd->rcWindow; + POINT ptSrc = {0, 0}; + SIZE sz = {r.right - r.left, r.bottom - r.top}; + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 0; + blend.AlphaFormat = AC_SRC_ALPHA; + + MyUpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA); + } + else if (MySetLayeredWindowAttributes) + { + MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), 0, LWA_ALPHA); + } + + SendMessage(hwnd, PUM_REFRESHTRAYTIP, 1, 0); + SendMessage(hwnd, PUM_GETHEIGHT, 0, 0); + SendMessage(hwnd, PUM_CALCPOS, 0, 0); + InvalidateRect(hwnd, 0, TRUE); + + if (opt.showEffect) + { + KillTimer(hwnd, ID_TIMER_ANIMATE); + SetTimer(hwnd, ID_TIMER_ANIMATE, ANIM_ELAPSE, 0); + pwd->iAnimStep = 0; + pwd->iCurrentTrans = 0; + } + + return TRUE; + } + case PUM_REFRESH_VALUES: + { + if (pwd && pwd->clcit.szProto == 0 && !pwd->bIsTextTip) + { + for (int i = 0; i < pwd->iRowCount; i++) + { + mir_free(pwd->rows[i].swzLabel); + mir_free(pwd->rows[i].swzValue); + Smileys_FreeParse(pwd->rows[i].spi); + } + + if (pwd->rows) + { + mir_free(pwd->rows); + pwd->rows = 0; + } + pwd->iRowCount = 0; + + DIListNode *node = opt.diList; + TCHAR buff_label[LABEL_LEN], buff[VALUE_LEN]; + while (node) + { + if (node->di.bIsVisible) + { + if (GetLabelText(pwd->hContact, node->di, buff_label, LABEL_LEN) && GetValueText(pwd->hContact, node->di, buff, VALUE_LEN)) + { + if (node->di.bLineAbove // we have a line above + && pwd->iRowCount > 0 // and we're not the first row + && pwd->rows[pwd->iRowCount - 1].bLineAbove // and above us there's a line above + && pwd->rows[pwd->iRowCount - 1].swzLabel[0] == 0 // with no label + && pwd->rows[pwd->iRowCount - 1].swzValue[0] == 0) // and no value + { + // overwrite item above + pwd->iRowCount--; + mir_free(pwd->rows[pwd->iRowCount].swzLabel); + mir_free(pwd->rows[pwd->iRowCount].swzValue); + Smileys_FreeParse(pwd->rows[pwd->iRowCount].spi); //prevent possible mem leak + } + else + { + pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData) * (pwd->iRowCount + 1)); + } + + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)pwd->hContact, 0); + + pwd->rows[pwd->iRowCount].swzLabel = mir_tstrdup(buff_label); + pwd->rows[pwd->iRowCount].swzValue = mir_tstrdup(buff); + pwd->rows[pwd->iRowCount].spi = Smileys_PreParse(buff, (int)_tcslen(buff), szProto); + pwd->rows[pwd->iRowCount].bValueNewline = node->di.bValueNewline; + pwd->rows[pwd->iRowCount].bLineAbove = node->di.bLineAbove; + pwd->iRowCount++; + } + } + node = node->next; + } + + // if the last item is just a divider, remove it + if (pwd->iRowCount > 0 + && pwd->rows[pwd->iRowCount - 1].bLineAbove // and above us there's a line above + && pwd->rows[pwd->iRowCount - 1].swzLabel[0] == 0 // with no label + && pwd->rows[pwd->iRowCount - 1].swzValue[0] == 0) // and no value + { + pwd->iRowCount--; + mir_free(pwd->rows[pwd->iRowCount].swzLabel); + mir_free(pwd->rows[pwd->iRowCount].swzValue); + Smileys_FreeParse(pwd->rows[pwd->iRowCount].spi); //prevent possible mem leak + + if (pwd->iRowCount == 0) + { + mir_free(pwd->rows); + pwd->rows = 0; + } + } + + if (wParam == TRUE) + { + SendMessage(hwnd, PUM_GETHEIGHT, 0, 0); + SendMessage(hwnd, PUM_CALCPOS, 0, 0); + } + } + return TRUE; + } + case PUM_GETHEIGHT: + { + int *pHeight = (int *)wParam; + HDC hdc = GetDC(hwnd); + SIZE sz; + RECT rc, smr; + rc.top = rc.left = 0; + rc.right = opt.iWinWidth; + int iWidth = opt.iPadding; + int iWinAvatarHeight = 0; + bool bStatusMsg = false; + HFONT hOldFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT); + + // avatar height + pwd->iAvatarHeight = 0; + if (!pwd->bIsTextTip && opt.avatarLayout != PAV_NONE && ServiceExists(MS_AV_GETAVATARBITMAP)) + { + AVATARCACHEENTRY *ace = 0; + if (pwd->hContact) ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)pwd->hContact, 0); + else ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto); + + if (ace && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) + { + if (opt.bOriginalAvatarSize && max(ace->bmWidth, ace->bmHeight) <= opt.iAvatarSize) + { + pwd->iRealAvatarHeight = ace->bmHeight; + pwd->iRealAvatarWidth = ace->bmWidth; + } + else + { + if (ace->bmHeight >= ace->bmWidth) + { + pwd->iRealAvatarHeight = opt.iAvatarSize; + pwd->iRealAvatarWidth = (int)(opt.iAvatarSize * (ace->bmWidth / (double)ace->bmHeight)); + } + else + { + pwd->iRealAvatarHeight = (int)(opt.iAvatarSize * (ace->bmHeight / (double)ace->bmWidth)); + pwd->iRealAvatarWidth = opt.iAvatarSize; + } + } + + pwd->iAvatarHeight = opt.iOuterAvatarPadding + opt.iInnerAvatarPadding + pwd->iRealAvatarHeight; + iWinAvatarHeight = 2 * opt.iOuterAvatarPadding + pwd->iRealAvatarHeight; + iWidth += pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding); + } + } + + // titlebar height + if (!pwd->bIsTextTip && pwd->swzTitle && opt.titleLayout != PTL_NOTITLE) + { + smr.top = smr.bottom = 0; + smr.left = rc.left + opt.iPadding + pwd->iIndent; + smr.right = rc.right; + + if (pwd->iRealAvatarWidth > 0) + smr.right -= pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding; + else + smr.right -= opt.iPadding; + + if (hFontTitle) SelectObject(hdc, (HGDIOBJ)hFontTitle); + DrawTextExt(hdc, pwd->swzTitle, -1, &smr, DT_CALCRECT | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, NULL, pwd->spiTitle); + + iWidth += opt.iPadding + opt.iTitleIndent + smr.right; + pwd->iTitleHeight = opt.iPadding + smr.bottom; + } + else + { + pwd->iTitleHeight = opt.iPadding; + } + + // icon height + int i, iCount = 0; + if (pwd->hContact || pwd->clcit.szProto) + { + for(i = 0; i < EXICONS_COUNT; i++) + { + if ((INT_PTR)pwd->extraIcons[i].hIcon == CALLSERVICE_NOTFOUND) + pwd->extraIcons[i].hIcon = 0; + + if (pwd->extraIcons[i].hIcon) + iCount++; + } + } + pwd->iIconsHeight = (iCount * 20) + 20; + + // text height + pwd->iTextHeight = pwd->iLabelWidth = 0; + // iterate once to find max label width for items with label and value on same line, but don't consider width of labels on a new line + for (i = 0; i < pwd->iRowCount; i++) + { + if (pwd->rows[i].swzLabel && !pwd->rows[i].bValueNewline) + { + if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) + { + if (hFontTrayTitle) + SelectObject(hdc, (HGDIOBJ)hFontTrayTitle); + } + else + { + if (hFontLabels) + SelectObject(hdc, (HGDIOBJ)hFontLabels); + } + + GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, (int)_tcslen(pwd->rows[i].swzLabel), &sz); + if (sz.cx > pwd->iLabelWidth) + pwd->iLabelWidth = sz.cx; + } + } + + for (i = 0; i < pwd->iRowCount; i++) + { + if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) + { + if (hFontTrayTitle) + SelectObject(hdc, (HGDIOBJ)hFontTrayTitle); + } + else + { + if (hFontLabels) + SelectObject(hdc, (HGDIOBJ)hFontLabels); + } + + if (pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0]) + GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, (int)_tcslen(pwd->rows[i].swzLabel), &sz); + else + sz.cy = sz.cx = 0; + + // save so we don't have to recalculate + pwd->rows[i].iLabelHeight = sz.cy; + + smr.top = smr.bottom = 0; + smr.left = rc.left + opt.iPadding + pwd->iIndent; + smr.right = rc.right; + if (hFontValues) SelectObject(hdc, (HGDIOBJ)hFontValues); + if (pwd->iTitleHeight + pwd->iTextHeight + opt.iTextPadding < pwd->iAvatarHeight) + smr.right -= pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding; + else + smr.right -= opt.iPadding; + + if (!pwd->rows[i].bValueNewline) + smr.right -= pwd->iLabelWidth + opt.iValueIndent; + + if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0]) + { + if (!bStatusMsg && opt.bGetNewStatusMsg) + { + if (!_tcscmp(pwd->rows[i].swzValue, _T("%sys:status_msg%"))) + bStatusMsg = true; + } + + DrawTextExt(hdc, pwd->rows[i].swzValue, -1, &smr, DT_CALCRECT | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, NULL, pwd->rows[i].spi); + } + else + { + smr.left = smr.right = 0; + } + + // save so we don't have to recalculate + pwd->rows[i].iValueHeight = smr.bottom; + + pwd->rows[i].iTotalHeight = (pwd->rows[i].bLineAbove ? opt.iTextPadding : 0); + if (pwd->rows[i].bValueNewline) + { + if (sz.cy) pwd->rows[i].iTotalHeight += sz.cy + opt.iTextPadding; + if (smr.bottom) pwd->rows[i].iTotalHeight += smr.bottom + opt.iTextPadding; + } + else + { + int maxheight = max(sz.cy, smr.bottom); + if (maxheight) pwd->rows[i].iTotalHeight += maxheight + opt.iTextPadding; + } + + // only consider this item's width, and include it's height, if it doesn't make the window too big + if (max(pwd->iTitleHeight + pwd->iTextHeight + opt.iPadding + pwd->rows[i].iTotalHeight, pwd->iAvatarHeight) <= opt.iWinMaxHeight || pwd->bIsTrayTip) + { + if (iWidth < opt.iWinWidth) + { + int wid = opt.iPadding + pwd->iIndent + (pwd->rows[i].bValueNewline ? max(sz.cx, smr.right - smr.left) : pwd->iLabelWidth + opt.iValueIndent + (smr.right - smr.left)); + if (pwd->iTitleHeight + pwd->iTextHeight + opt.iTextPadding < pwd->iAvatarHeight) + iWidth = max(iWidth, wid + pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding); + else + iWidth = max(iWidth, wid + opt.iPadding); + } + + pwd->iTextHeight += pwd->rows[i].iTotalHeight; + } + } + + SelectObject(hdc, hOldFont); + ReleaseDC(hwnd, hdc); + + int iHeight = max(pwd->iTitleHeight + pwd->iTextHeight + opt.iPadding, iWinAvatarHeight); + iHeight = max(pwd->iIconsHeight, iHeight); + if (bStatusMsg) iHeight += 50; + + if (iHeight < opt.iMinHeight) iHeight = opt.iMinHeight; + // ignore minwidth for text tips + if (!pwd->bIsTextTip && iWidth < opt.iMinWidth) iWidth = opt.iMinWidth; + + // ignore maxheight for tray tip + if (!pwd->bIsTrayTip && iHeight > opt.iWinMaxHeight) iHeight = opt.iWinMaxHeight; + if (iWidth > opt.iWinWidth) iWidth = opt.iWinWidth; + + CreateSkinBitmap(iWidth, iHeight, pwd->bIsTextTip && !pwd->bIsTrayTip); + + GetWindowRect(hwnd, &rc); + if (rc.right - rc.left != iWidth || rc.bottom - rc.top != iHeight) + { + SetWindowPos(hwnd, 0, 0, 0, iWidth, iHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + GetWindowRect(hwnd, &pwd->rcWindow); + SendMessage(hwnd, PUM_UPDATERGN, 0, 0); + InvalidateRect(hwnd, 0, TRUE); + } + + if (pHeight) + *pHeight = iHeight; + + return TRUE; + } + case PUM_UPDATERGN: + { + HRGN hRgn; + RECT r = pwd->rcWindow; + int v, h; + int w = 11; + + r.right -= r.left; + r.left = 0; + r.bottom -= r.top; + r.top = 0; + + if (opt.showEffect == PSE_FADE && wParam == 1) + { + if (skin.bNeedLayerUpdate) + { + POINT ptSrc = {0, 0}; + SIZE sz = {r.right - r.left, r.bottom - r.top}; + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = pwd->iCurrentTrans; + blend.AlphaFormat = AC_SRC_ALPHA; + + pwd->iCurrentTrans += opt.iAnimateSpeed; + if (pwd->iCurrentTrans > pwd->iTrans) + { + pwd->iCurrentTrans = pwd->iTrans; + pwd->iAnimStep = ANIM_STEPS; + } + + MyUpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA); + + } + else if (MySetLayeredWindowAttributes) + { + pwd->iCurrentTrans += opt.iAnimateSpeed; + if (pwd->iCurrentTrans > pwd->iTrans) + { + pwd->iCurrentTrans = pwd->iTrans; + pwd->iAnimStep = ANIM_STEPS; + } + + MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), pwd->iCurrentTrans, LWA_ALPHA); + } + + } + else if (opt.showEffect == PSE_ANIMATE && pwd->bIsPainted) + { + if (pwd->iAnimStep <= (ANIM_STEPS / opt.iAnimateSpeed)) + { + float frac = 1.0f - pwd->iAnimStep / ((float)ANIM_STEPS / opt.iAnimateSpeed); + int wi = r.right, hi = r.bottom; + + r.left += (int)(wi / 2.0f * frac + 0.5f); + r.right -= (int)(wi / 2.0f * frac + 0.5f); + r.top += (int)(hi / 2.0f * frac + 0.5f); + r.bottom -= (int)(hi / 2.0f * frac + 0.5f); + } + else + { + pwd->iAnimStep = ANIM_STEPS; + } + + if (skin.bNeedLayerUpdate) + { + RECT r2 = pwd->rcWindow; + POINT ptPos = {r.left + r2.left, r.top + r2.top}; + POINT ptSrc = {r.left, r.top}; + + SIZE sz = {r.right - r.left, r.bottom - r.top}; + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = pwd->iTrans; + blend.AlphaFormat = AC_SRC_ALPHA; + + MyUpdateLayeredWindow(hwnd, NULL, &ptPos, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA); + } + } + + if (!skin.bNeedLayerUpdate) + { + // round corners + if (opt.bRound) + { + h = (r.right-r.left)>(w*2) ? w : (r.right-r.left); + v = (r.bottom-r.top)>(w*2) ? w : (r.bottom-r.top); + h = (hiAnimStep == 1) + { + if (MySetLayeredWindowAttributes) + MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), pwd->iTrans, LWA_ALPHA); + } + + } + else + { + // aero glass (vista+) + if (opt.bAeroGlass && MyDwmEnableBlurBehindWindow && pwd->iAnimStep > 5) + { + if (pwd->hrgnAeroGlass) + { + DeleteObject(pwd->hrgnAeroGlass); + pwd->hrgnAeroGlass = 0; + } + + pwd->hrgnAeroGlass = CreateOpaqueRgn(25, true); + + if (pwd->hrgnAeroGlass) + { + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.fEnable = TRUE; + bb.hRgnBlur = pwd->hrgnAeroGlass; + MyDwmEnableBlurBehindWindow(hwnd, &bb); + } + } + } + + return TRUE; + } + case PUM_CALCPOS: + { + RECT rcWork, rc; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, FALSE); + if (MyMonitorFromPoint) + { + HMONITOR hMon = MyMonitorFromPoint(pwd->clcit.ptCursor, MONITOR_DEFAULTTONEAREST); + MONITORINFO mi; + mi.cbSize = sizeof(mi); + if (MyGetMonitorInfo(hMon, &mi)) + rcWork = mi.rcWork; + } + + GetWindowRect(hwnd, &rc); + + int x = 0, y = 0, iWidth = (rc.right - rc.left), iHeight = (rc.bottom - rc.top); + + switch(opt.pos) + { + case PP_BOTTOMRIGHT: + x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON); // cursor size is too large - use small icon size + y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON); + break; + case PP_BOTTOMLEFT: + x = pwd->clcit.ptCursor.x - iWidth - GetSystemMetrics(SM_CXSMICON); + y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON); + break; + case PP_TOPRIGHT: + x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON); + y = pwd->clcit.ptCursor.y - iHeight - GetSystemMetrics(SM_CYSMICON); + break; + case PP_TOPLEFT: + x = pwd->clcit.ptCursor.x - iWidth - GetSystemMetrics(SM_CXSMICON); + y = pwd->clcit.ptCursor.y - iHeight - GetSystemMetrics(SM_CYSMICON); + break; + } + + + if (x + iWidth + 8 > rcWork.right) + x = rcWork.right - iWidth - 8; + if (x - 8 < rcWork.left) + x = rcWork.left + 8; + + if (pwd->bAllowReposition || !pwd->bNeedRefresh) + { + if (y + iHeight > rcWork.bottom) + { + y = pwd->clcit.ptCursor.y - iHeight - 8; + pwd->bAllowReposition = true; + } + + if (y - 8 < rcWork.top) + { + y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON); + pwd->bAllowReposition = true; + } + } + + SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + GetWindowRect(hwnd, &pwd->rcWindow); + return TRUE; + } + case PUM_REFRESHTRAYTIP: + { + int i, j; + for (i = 0; i < pwd->iRowCount; i++) + { + mir_free(pwd->rows[i].swzLabel); + mir_free(pwd->rows[i].swzValue); + Smileys_FreeParse(pwd->rows[i].spi); + } + + if (pwd->rows) + { + mir_free(pwd->rows); + pwd->rows = NULL; + } + + pwd->iRowCount = 0; + + DWORD dwItems = (wParam == 0) ? opt.iFirstItems : opt.iSecondItems; + bool bFirstItem = true; + TCHAR buff[64]; + + int oldOrder = -1, iProtoCount = 0; + PROTOACCOUNT **accs; + ProtoEnumAccounts(&iProtoCount, &accs); + + for (j = 0; j < iProtoCount; j++) + { + PROTOACCOUNT *pa = NULL; + for (i = 0; i < iProtoCount; i++) + { + + if (accs[i]->iOrder > oldOrder && (pa == NULL || accs[i]->iOrder < pa->iOrder)) + pa = accs[i]; + } + + oldOrder = pa->iOrder; + + WORD wStatus = CallProtoService(pa->szModuleName, PS_GETSTATUS, 0, 0); + if (opt.bHideOffline && wStatus == ID_STATUS_OFFLINE) + continue; + + if (!IsAccountEnabled(pa) || !IsTrayProto(pa->tszAccountName, (BOOL)wParam)) + continue; + + if (dwItems & TRAYTIP_NUMCONTACTS) + { + int iCount = 0, iCountOnline = 0; + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (proto && !strcmp(proto, pa->szModuleName)) + { + if (DBGetContactSettingWord(hContact, proto, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) + iCountOnline++; + iCount++; + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + mir_sntprintf(buff, 64, _T("(%d/%d)"), iCountOnline, iCount); + } + else + { + _tcscpy(buff, _T("")); + } + + TCHAR swzProto[256]; + _tcscpy(swzProto, pa->tszAccountName); + if (dwItems & TRAYTIP_LOCKSTATUS) + { + if (CallService(MS_PROTO_ISACCOUNTLOCKED,0,(LPARAM)pa->szModuleName)) + mir_sntprintf(swzProto, SIZEOF(swzProto), TranslateT("%s (locked)"), pa->tszAccountName); + } + + AddRow(pwd, swzProto, buff, NULL, false, false, !bFirstItem, true, LoadSkinnedProtoIcon(pa->szModuleName, wStatus)); + bFirstItem = false; + + if (dwItems & TRAYTIP_LOGON) + { + if (TimestampToTimeDifference(NULL, pa->szModuleName, "LogonTS", buff, 59)) + { + _tcscat(buff, TranslateT(" ago")); + AddRow(pwd, TranslateT("Log on:"), buff, NULL, false, false, false); + } + + if (TimestampToTimeDifference(NULL, pwd->clcit.szProto, "LogoffTS", buff, 59)) + { + _tcscat(buff, TranslateT(" ago")); + AddRow(pwd, TranslateT("Log off:"), buff, NULL, false, false, false); + } + } + + if (dwItems & TRAYTIP_UNREAD_EMAILS && ProtoServiceExists(pa->szModuleName, "/GetUnreadEmailCount")) + { + int iCount = (int)CallProtoService(pa->szModuleName, "/GetUnreadEmailCount", 0, 0); + if (iCount > 0) + { + _itot(iCount, buff, 10); + AddRow(pwd, TranslateT("Unread emails:"), buff, NULL, false, false, false); + } + } + + if (dwItems & TRAYTIP_STATUS) + { + TCHAR *swzText = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, wStatus, GSMDF_TCHAR); + if (swzText) + { + AddRow(pwd, TranslateT("Status:"), swzText, NULL, false, false, false); + } + } + + if (wStatus >= ID_STATUS_ONLINE && wStatus <= ID_STATUS_OUTTOLUNCH) + { + if (dwItems & TRAYTIP_STATUS_MSG) + { + TCHAR *swzText = GetProtoStatusMessage(pa->szModuleName, wStatus); + if (swzText) + { + StripBBCodesInPlace(swzText); + AddRow(pwd, TranslateT("Status message:"), swzText, pa->szModuleName, true, true, false); + mir_free(swzText); + } + } + + if (dwItems & TRAYTIP_EXTRA_STATUS) + { + // jabber mood or icq xstatus + TCHAR *swzAdvTitle = GetJabberAdvStatusText(pa->szModuleName, "mood", "title"); + if (swzAdvTitle) + { + StripBBCodesInPlace(swzAdvTitle); + AddRow(pwd, TranslateT("Mood:"), swzAdvTitle, pa->szModuleName, true, false, false); + mir_free(swzAdvTitle); + + TCHAR *swzAdvText = GetJabberAdvStatusText(pa->szModuleName, "mood", "text"); + if (swzAdvText) + { + StripBBCodesInPlace(swzAdvText); + AddRow(pwd, _T(""), swzAdvText, pa->szModuleName, true, true, false); + mir_free(swzAdvText); + } + } + else + { + if (DBGetContactSettingByte(0, pa->szModuleName, "XStatusId", 0)) + { + // xstatus title + swzAdvTitle = GetProtoExtraStatusTitle(pa->szModuleName); + if (swzAdvTitle) + { + StripBBCodesInPlace(swzAdvTitle); + AddRow(pwd, TranslateT("XStatus:"), swzAdvTitle, pa->szModuleName, true, false, false); + mir_free(swzAdvTitle); + } + + // xstatus message + TCHAR *swzAdvText = GetProtoExtraStatusMessage(pa->szModuleName); + if (swzAdvText) + { + StripBBCodesInPlace(swzAdvText); + AddRow(pwd, _T(""), swzAdvText, pa->szModuleName, true, true, false); + mir_free(swzAdvText); + } + } + } + + TCHAR *swzActTitle = GetJabberAdvStatusText(pa->szModuleName, "activity", "title"); + if (swzActTitle) + { + StripBBCodesInPlace(swzActTitle); + AddRow(pwd, TranslateT("Activity:"), swzActTitle, pa->szModuleName, true, false, false); + mir_free(swzActTitle); + } + + TCHAR *swzActText = GetJabberAdvStatusText(pa->szModuleName, "activity", "text"); + if (swzActText) + { + StripBBCodesInPlace(swzActText); + AddRow(pwd, _T(""), swzActText, pa->szModuleName, true, true, false); + mir_free(swzActText); + } + } + + if (dwItems & TRAYTIP_LISTENINGTO) + { + TCHAR *swzListening = GetListeningTo(pa->szModuleName); + if (swzListening) + { + StripBBCodesInPlace(swzListening); + AddRow(pwd, TranslateT("Listening to:"), swzListening, NULL, false, true, false); + mir_free(swzListening); + } + } + } + } + + if (dwItems & TRAYTIP_FAVCONTACTS) + { + if (DBGetContactSettingDword(0, MODULE, "FavouriteContactsCount", 0)) + { + TCHAR swzName[256]; + TCHAR swzStatus[256]; + bool bTitlePainted = false; + int iCount = 0, iCountOnline = 0; + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + if (DBGetContactSettingByte(hContact, MODULE, "FavouriteContact", 0)) + { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (proto) + { + WORD wStatus = DBGetContactSettingWord(hContact, proto, "Status", ID_STATUS_OFFLINE); + WordToStatusDesc(hContact, proto, "Status", swzStatus, 256); + + if (wStatus != ID_STATUS_OFFLINE) + iCountOnline++; + + iCount++; + + if (!(opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE && wStatus == ID_STATUS_OFFLINE)) + { + if (!bTitlePainted) + { + AddRow(pwd, TranslateT("Fav. contacts"), NULL, NULL, false, false, !bFirstItem, true, NULL); + bFirstItem = false; + bTitlePainted = true; + } + + TCHAR *swzNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); + if (opt.iFavoriteContFlags & FAVCONT_APPEND_PROTO) + { + TCHAR *swzProto = a2t(proto); + mir_sntprintf(swzName, 256, _T("%s (%s)"), swzNick, swzProto); + mir_free(swzProto); + } + else + { + _tcscpy(swzName, swzNick); + } + + AddRow(pwd, swzName, swzStatus, NULL, false, false, false); + } + } + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } + + int index = pwd->iRowCount - 1; + if (opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE) + index -= iCountOnline; + else + index -= iCount; + + if (index >= 0 && (dwItems & TRAYTIP_NUMCONTACTS) && !((opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE) && iCountOnline == 0)) + { + mir_sntprintf(buff, 64, _T("(%d/%d)"), iCountOnline, iCount); + pwd->rows[index].swzValue = mir_tstrdup(buff); + } + } + } + + if (dwItems & TRAYTIP_MIRANDA_UPTIME) + { + if (TimestampToTimeDifference(NULL, MODULE, "MirandaStartTS", buff, 64)) + { + AddRow(pwd, TranslateT("Other"), _T(""), NULL, false, false, !bFirstItem, true, NULL); + AddRow(pwd, TranslateT("Miranda uptime:"), buff, NULL, false, false, false); + } + } + + if (dwItems & TRAYTIP_CLIST_EVENT && pwd->clcit.swzText) + { + TCHAR *pchBr = _tcschr(pwd->clcit.swzText, '\n'); + TCHAR *pchBold = _tcsstr(pwd->clcit.swzText, _T("")); + + if (!pchBold || pchBold != pwd->clcit.swzText) + { + TCHAR swzText[256]; + _tcscpy(swzText, pwd->clcit.swzText); + if (pchBr) swzText[pchBr - pwd->clcit.swzText] = 0; + AddRow(pwd, swzText, _T(""), NULL, false, true, false, true, LoadSkinnedIcon(SKINICON_OTHER_FILLEDBLOB)); + } + } + + return TRUE; + } + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} \ No newline at end of file diff --git a/plugins/TipperYM/src/popwin.h b/plugins/TipperYM/src/popwin.h new file mode 100644 index 0000000000..b7ba674b08 --- /dev/null +++ b/plugins/TipperYM/src/popwin.h @@ -0,0 +1,140 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _POPWIN_INC +#define _POPWIN_INC + +#include "mir_smileys.h" + +#define POP_WIN_CLASS _T(MODULE) _T("MimTTClass") + +#define PUM_GETHEIGHT (WM_USER + 0x020) +#define PUM_CALCPOS (WM_USER + 0x021) +#define PUM_SETSTATUSTEXT (WM_USER + 0x022) +#define PUM_UPDATERGN (WM_USER + 0x023) +#define PUM_SETAVATAR (WM_USER + 0x024) +#define PUM_REFRESH_VALUES (WM_USER + 0x025) +#define PUM_SHOWXSTATUS (WM_USER + 0x026) +#define PUM_EXPANDTRAYTIP (WM_USER + 0x027) +#define PUM_REFRESHTRAYTIP (WM_USER + 0x028) +#define PUM_FADEOUTWINDOW (WM_USER + 0x029) + +// extra icons +#define EXICONS_COUNT 6 +#define CTRY_ERROR 42 //Flags - some strange value ??? +#define GEN_FEMALE 70 +#define GEN_MALE 77 + +// copy menu +#define COPYMENU_ALLITEMS_LABELS 1000 +#define COPYMENU_ALLITEMS 1001 +#define COPYMENU_AVATAR 1002 + +// tray tooltip items +#define TRAYTIP_ITEMS_COUNT 11 + +#define TRAYTIP_NUMCONTACTS 1 +#define TRAYTIP_LOCKSTATUS 2 +#define TRAYTIP_LOGON 4 +#define TRAYTIP_UNREAD_EMAILS 8 +#define TRAYTIP_STATUS 16 +#define TRAYTIP_STATUS_MSG 32 +#define TRAYTIP_EXTRA_STATUS 64 +#define TRAYTIP_LISTENINGTO 128 +#define TRAYTIP_FAVCONTACTS 256 +#define TRAYTIP_MIRANDA_UPTIME 512 +#define TRAYTIP_CLIST_EVENT 1024 + +// favorite contacts options +#define FAVCONT_HIDE_OFFLINE 1 +#define FAVCONT_APPEND_PROTO 2 + +// other +#define TITLE_TEXT_LEN 512 +#define MAX_VALUE_LEN 64 + +#define ANIM_ELAPSE 10 +#define ANIM_STEPS 255 +#define CHECKMOUSE_ELAPSE 250 + +#define ID_TIMER_ANIMATE 0x0100 +#define ID_TIMER_CHECKMOUSE 0x0101 +#define ID_TIMER_TRAYTIP 0x0102 + + +typedef struct { + HICON hIcon; + bool bDestroy; +} ExtraIcons; + +typedef struct { + int cbSize; + int isTreeFocused; //so the plugin can provide an option + int isGroup; //0 if it's a contact, 1 if it's a group + HANDLE hItem; //handle to group or contact + POINT ptCursor; + RECT rcItem; + TCHAR *swzText; // for tips with specific text + char *szProto; // for proto tips +} CLCINFOTIPEX; + +typedef struct { + TCHAR *swzLabel, *swzValue; + HICON hIcon; + bool bValueNewline; + bool bLineAbove; + bool bIsTitle; + int iLabelHeight, iValueHeight, iTotalHeight; + SMILEYPARSEINFO spi; +} RowData; + +typedef struct { + HPEN hpenBorder, hpenDivider; + int iTitleHeight, iAvatarHeight, iIconsHeight, iTextHeight, iLabelWidth; + int iRealAvatarWidth, iRealAvatarHeight; + HANDLE hContact; + int iIconIndex; + CLCINFOTIPEX clcit; + TCHAR swzTitle[TITLE_TEXT_LEN]; + SMILEYPARSEINFO spiTitle; + RowData *rows; + int iRowCount; + int iAnimStep; + int iCurrentTrans; + bool bIsTextTip, bIsTrayTip; + int iIndent, iSidebarWidth; + POINT ptCursorStartPos; // work around bugs with hiding tips (timer check mouse position) + ExtraIcons extraIcons[EXICONS_COUNT]; + bool bIsIconVisible[EXICONS_COUNT]; + int iTrans; + int iHotkeyId; + bool bIsPainted; + bool bNeedRefresh; + bool bAllowReposition; + RECT rcWindow; + HRGN hrgnAeroGlass; +} PopupWindowData; + + +LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +extern int IsTrayProto(const TCHAR *swzProto, BOOL bExtendedTip); + + +#endif diff --git a/plugins/TipperYM/src/preset_items.cpp b/plugins/TipperYM/src/preset_items.cpp new file mode 100644 index 0000000000..629a747a28 --- /dev/null +++ b/plugins/TipperYM/src/preset_items.cpp @@ -0,0 +1,131 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "preset_items.h" + +PRESETITEM presetItems[] = +{ + "birth", LPGENT("Birthday"), LPGENT("Birthday:"), _T("%birthday_date% (%birthday_age%) @ Next: %birthday_next%"), "birthdate", "birthage", "birthnext", + "client", LPGENT("Client"), LPGENT("Client:"), _T("%raw:/MirVer%"), 0, 0, 0, + "email", LPGENT("Email"), LPGENT("Email:"), _T("%raw:/e-mail%"), 0, 0, 0, + "gender", LPGENT("Gender"), LPGENT("Gender:"), _T("%gender%"), 0, 0, 0, + "homepage", LPGENT("Homepage"), LPGENT("Homepage:"), _T("%raw:/Homepage%"), 0, 0, 0, + "id", LPGENT("Identifier"), LPGENT("%sys:uidname|UID^!MetaContacts%:"), _T("%sys:uid%"), 0, 0, 0, + "idle", LPGENT("Idle"), LPGENT("Idle:"), _T("%idle% (%idle_diff% ago)"), "idle", "idlediff", 0, + "ip", LPGENT("IP"), LPGENT("IP:"), _T("%ip%"), "ip", 0, 0, + "ipint", LPGENT("IP internal"), LPGENT("IP internal:"), _T("%ip_internal%"), "ipint", 0, 0, + "lastmsg", LPGENT("Last message"), LPGENT("Last message: (%sys:last_msg_reltime% ago)"), _T("%sys:last_msg%"), 0, 0, 0, + "listening", LPGENT("Listening to"), LPGENT("Listening to:"), _T("%raw:/ListeningTo%"), 0, 0, 0, + "name", LPGENT("Name"), LPGENT("Name:"), _T("%raw:/FirstName|% %raw:/LastName%"), 0, 0, 0, + "received", LPGENT("Number of received messages"), LPGENT("Number of msg [IN]:"), _T("%sys:msg_count_in%"), 0, 0, 0, + "sended", LPGENT("Number of sended messages"), LPGENT("Number of msg [OUT]:"), _T("%sys:msg_count_out%"), 0, 0, 0, + "status", LPGENT("Status"), LPGENT("Status:"), _T("%Status%"), "status", 0, 0, + "statusmsg", LPGENT("Status message"), LPGENT("Status message:"), _T("%sys:status_msg%"), 0, 0, 0, + "time", LPGENT("Contact time"), LPGENT("Time:"), _T("%sys:time%"), 0, 0, 0, + "xtitle", LPGENT("XStatus title"), LPGENT("XStatus title:"), _T("%xsname%"), "xname", 0, 0, + "xtext", LPGENT("XStatus text"), LPGENT("XStatus text:"), _T("%raw:/XStatusMsg%"), 0, 0, 0, + "acttitle", LPGENT("[jabber.dll] Activity title"), LPGENT("Activity title:"), _T("%raw:AdvStatus/?dbsetting(%subject%,Protocol,p)/activity/title%"), 0, 0, 0, + "acttext", LPGENT("[jabber.dll] Activity text"), LPGENT("Activity text:"), _T("%raw:AdvStatus/?dbsetting(%subject%,Protocol,p)/activity/text%"), 0, 0, 0, + "logon", LPGENT("[menuex.dll] Logon time"), LPGENT("Logon time:"), _T("%logon_date% @ %logon_time% (%logon_ago%)"), "logondate", "logontime", "logonago", + "logoff", LPGENT("[menuex.dll] Logoff time"), LPGENT("Logoff time:"), _T("%logoff_date% @ %logoff_time% (%logoff_ago%)"), "logoffdate", "logofftime", "logoffago", + "lastseentime", LPGENT("[seenplugin.dll] Last seen time"), LPGENT("Last seen time:"), _T("%lastseen_date% @ %lastseen_time%"), "lsdate", "lstime", 0, + "lastseenstatus", LPGENT("[seenplugin.dll] Last seen status"), LPGENT("Last seen status:"), _T("%lastseen_status% (%lastseen_ago% ago)"), "lsstatus", "lsago", 0, + "cond", LPGENT("[weather.dll] Condition"), LPGENT("Condition:"), _T("%raw:Current/Condition%"), 0, 0, 0, + "humidity", LPGENT("[weather.dll] Humidity"), LPGENT("Humidity:"), _T("%raw:Current/Humidity%"), 0, 0, 0, + "minmaxtemp", LPGENT("[weather.dll] Max/Min temperature"), LPGENT("Max/Min:"), _T("%raw:Current/High%/%raw:Current/Low%"), 0, 0, 0, + "moon", LPGENT("[weather.dll] Moon"), LPGENT("Moon:"), _T("%raw:Current/Moon%"), 0, 0, 0, + "pressure", LPGENT("[weather.dll] Pressure"), LPGENT("Pressure:"), _T("%raw:Current/Pressure% (%raw:Current/Pressure Tendency%)"), 0, 0, 0, + "sunrise", LPGENT("[weather.dll] Sunrise"), LPGENT("Sunrise:"), _T("%raw:Current/Sunrise%"), 0, 0, 0, + "sunset", LPGENT("[weather.dll] Sunset"), LPGENT("Sunset:"), _T("%raw:Current/Sunset%"), 0, 0, 0, + "temp", LPGENT("[weather.dll] Temperature"), LPGENT("Temperature:"), _T("%raw:Current/Temperature%"), 0, 0, 0, + "uptime", LPGENT("[weather.dll] Update time"), LPGENT("Update time:"), _T("%raw:Current/Update%"), 0, 0, 0, + "uvindex", LPGENT("[weather.dll] UV Index"), LPGENT("UV Index:"), _T("%raw:Current/UV% - %raw:Current/UVI%"), 0, 0, 0, + "vis", LPGENT("[weather.dll] Visibility"), LPGENT("Visibility:"), _T("%raw:Current/Visibility%"), 0, 0, 0, + "wind", LPGENT("[weather.dll] Wind"), LPGENT("Wind:"), _T("%raw:Current/Wind Direction% (%raw:Current/Wind Direction DEG%)/%raw:Current/Wind Speed%"), 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 +}; + +PRESETSUBST presetSubsts[] = +{ + "gender", _T("gender"), DVT_PROTODB, NULL, "Gender", 5, + "status", _T("Status"), DVT_PROTODB, NULL, "Status", 1, + "ip", _T("ip"), DVT_PROTODB, NULL, "IP", 7, + "ipint", _T("ip_internal"), DVT_PROTODB, NULL, "RealIP", 7, + "idle", _T("idle"), DVT_PROTODB, NULL, "IdleTS", 2, + "idlediff", _T("idle_diff"), DVT_PROTODB, NULL, "IdleTS", 3, + "xname", _T("xsname"), DVT_PROTODB, NULL, "XStatusName", 17, + "lsdate", _T("lastseen_date"), DVT_DB, "SeenModule", NULL, 8, + "lstime", _T("lastseen_time"), DVT_DB, "SeenModule", NULL, 10, + "lsstatus", _T("lastseen_status"), DVT_DB, "SeenModule", "OldStatus", 1, + "lsago", _T("lastseen_ago"), DVT_DB, "SeenModule", "seenTS", 3, + "birthdate", _T("birthday_date"), DVT_PROTODB, NULL, "Birth", 8, + "birthage", _T("birthday_age"), DVT_PROTODB, NULL, "Birth", 9, + "birthnext", _T("birthday_next"), DVT_PROTODB, NULL, "Birth", 12, + "logondate", _T("logon_date"), DVT_PROTODB, NULL, "LogonTS", 15, + "logontime", _T("logon_time"), DVT_PROTODB, NULL, "LogonTS", 13, + "logonago", _T("logon_ago"), DVT_PROTODB, NULL, "LogonTS", 3, + "logoffdate", _T("logoff_date"), DVT_PROTODB, NULL, "LogoffTS", 15, + "logofftime", _T("logoff_time"), DVT_PROTODB, NULL, "LogoffTS", 13, + "logoffago", _T("logoff_ago"), DVT_PROTODB, NULL, "LogoffTS", 3, + 0, 0, DVT_DB, 0, 0, 0 +}; + +DEFAULTITEM defaultItemList[] = +{ + "statusmsg", true, + "-", false, + "lastmsg", true , + "-", false, + "client", false, + "homepage", false, + "email", false, + "birth", false, + "name", false, + "-", false, + "time", false, + "id", false, + "status", false, + 0,0 +}; + +PRESETITEM *GetPresetItemByName(char *szName) +{ + for (int i = 0; presetItems[i].szID; i++) + { + if (strcmp(presetItems[i].szID, szName) == 0) + return &presetItems[i]; + } + + return NULL; +} + +PRESETSUBST *GetPresetSubstByName(char *szName) +{ + if (!szName) return NULL; + for (int i = 0; presetSubsts[i].szID; i++) + { + if (strcmp(presetSubsts[i].szID, szName) == 0) + return &presetSubsts[i]; + } + + return NULL; +} + diff --git a/plugins/TipperYM/src/preset_items.h b/plugins/TipperYM/src/preset_items.h new file mode 100644 index 0000000000..5055db3dee --- /dev/null +++ b/plugins/TipperYM/src/preset_items.h @@ -0,0 +1,57 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _PRESETITEMS_INC +#define _PRESETITEMS_INC + +#include "options.h" + +#define MAX_PRESET_SUBST_COUNT 3 + +typedef struct { + char *szID; + TCHAR *swzName; + TCHAR *swzLabel; + TCHAR *swzValue; + char *szNeededSubst[MAX_PRESET_SUBST_COUNT]; +} PRESETITEM; + +typedef struct { + char *szID; + TCHAR *swzName; + DisplaySubstType type; + char *szModuleName; + char *szSettingName; + int iTranslateFuncId; +} PRESETSUBST; + +typedef struct { + char *szName; + bool bValueNewline; +} DEFAULTITEM; + +extern PRESETITEM presetItems[]; +extern PRESETSUBST presetSubsts[]; +extern DEFAULTITEM defaultItemList[]; + +PRESETITEM *GetPresetItemByName(char *szName); +PRESETSUBST *GetPresetSubstByName(char *szName); + +#endif \ No newline at end of file diff --git a/plugins/TipperYM/src/resource.h b/plugins/TipperYM/src/resource.h new file mode 100644 index 0000000000..0e850b25ea --- /dev/null +++ b/plugins/TipperYM/src/resource.h @@ -0,0 +1,137 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDD_OPT_APPEARANCE 101 +#define IDD_SUBST 103 +#define IDD_ITEM 104 +#define IDD_OPT_CONTENT 105 +#define IDD_OPT_SKIN 106 +#define IDI_ITEM 107 +#define IDI_ITEM_ALL 108 +#define IDD_OPT_EXTRA 109 +#define IDD_OPT_TRAYTIP 110 +#define IDD_FAVCONTACTS 111 +#define IDI_UP 112 +#define IDI_DOWN 113 +#define IDI_SEPARATOR 114 +#define IDI_RELOAD 116 +#define IDI_APPLY 117 +#define IDC_ED_WIDTH 1005 +#define IDC_ED_MAXHEIGHT 1006 +#define IDC_SPIN_WIDTH 1007 +#define IDC_SPIN_MAXHEIGHT 1008 +#define IDC_ED_INDENT 1009 +#define IDC_SPIN_INDENT 1010 +#define IDC_ED_PADDING 1011 +#define IDC_SPIN_PADDING 1012 +#define IDC_ED_TRANS 1013 +#define IDC_SPIN_TRANS 1014 +#define IDC_CHK_BORDER 1015 +#define IDC_CHK_ROUNDCORNERS 1016 +#define IDC_ED_MINWIDTH 1017 +#define IDC_ED_SPEED 1017 +#define IDC_CHK_AEROGLASS 1018 +#define IDC_SPIN_SPEED 1019 +#define IDC_CHK_SHADOW 1020 +#define IDC_SPIN_MINWIDTH 1021 +#define IDC_ED_MINHEIGHT 1022 +#define IDC_SPIN_MINHEIGHT 1023 +#define IDC_ED_SBWIDTH 1024 +#define IDC_SPIN_SBWIDTH 1025 +#define IDC_ED_TEXTPADDING 1026 +#define IDC_ED_AVSIZE 1027 +#define IDC_SPIN_AVSIZE 1028 +#define IDC_ED_HOVER 1029 +#define IDC_SPIN_HOVER 1030 +#define IDC_SPIN_TEXTPADDING 1031 +#define IDC_CMB_ICON 1032 +#define IDC_CMB_AV 1033 +#define IDC_CMB_POS 1034 +#define IDC_ED_OUTAVPADDING 1035 +#define IDC_BTN_ADD 1036 +#define IDC_SPIN_OUTAVPADDING 1036 +#define IDC_BTN_REMOVE 1037 +#define IDC_CHK_ROUNDCORNERSAV 1037 +#define IDC_BTN_UP 1038 +#define IDC_CHK_ORIGINALAVSIZE 1038 +#define IDC_BTN_DOWN 1039 +#define IDC_CHK_AVBORDER 1039 +#define IDC_CHK_NOFOCUS 1040 +#define IDC_BTN_ADD2 1040 +#define IDC_BTN_EDIT 1041 +#define IDC_ED_TITLEINDENT 1041 +#define IDC_LST_SUBST 1042 +#define IDC_SPIN_TITLEINDENT 1042 +#define IDC_ED_VALUEINDENT 1043 +#define IDC_BTN_REMOVE2 1043 +#define IDC_ED_MODULE 1044 +#define IDC_SPIN_VALUEINDENT 1044 +#define IDC_BTN_EDIT2 1044 +#define IDC_CHK_PROTOMOD 1045 +#define IDC_ED_INAVPADDING 1045 +#define IDC_BTN_SEPARATOR 1045 +#define IDC_ED_SETTING 1046 +#define IDC_SPIN_INAVPADDING 1046 +#define IDC_CMB_TRANSLATE 1047 +#define IDC_ED_LABEL 1048 +#define IDC_CHK_SBAR 1048 +#define IDC_ED_VALUE 1050 +#define IDC_CHK_LINEABOVE 1051 +#define IDC_CHK_VALNEWLINE 1052 +#define IDC_CMB_LV 1053 +#define IDC_CHK_PARSETIPPERFIRST 1053 +#define IDC_CMB_VV 1054 +#define IDC_CMB_LH 1055 +#define IDC_CMB_VH 1056 +#define IDC_CHK_DISABLEINVISIBLE 1059 +#define IDC_CHK_RETRIEVEXSTATUS 1060 +#define IDC_TREE_EXTRAICONS 1061 +#define IDC_CHK_ENABLESMILEYS 1062 +#define IDC_CHK_RESIZESMILEYS 1063 +#define IDC_CHK_GETSTATUSMSG 1064 +#define IDC_CHK_WAITFORCONTENT 1065 +#define IDC_STATIC_AVATARSIZE 1085 +#define IDC_CMB_EFFECT 1086 +#define IDC_TREE_FIRST_PROTOS 1087 +#define IDC_CHK_ENABLETRAYTIP 1088 +#define IDC_CHK_HANDLEBYTIPPER 1089 +#define IDC_TREE_SECOND_PROTOS 1090 +#define IDC_TREE_SECOND_ITEMS 1094 +#define IDC_TREE_FIRST_ITEMS 1095 +#define IDC_BTN_FAVCONTACTS 1096 +#define IDC_CHK_EXPAND 1097 +#define IDC_ED_EXPANDTIME 1098 +#define IDC_SPIN_EXPANDTIME 1099 +#define IDC_CLIST 1101 +#define IDC_BTN_OK 1102 +#define IDC_BTN_CANCEL 1103 +#define IDC_CHK_HIDEOFFLINE 1104 +#define IDC_CHK_APPENDPROTO 1105 +#define IDC_CHK_USEPROTOSMILEYS 1106 +#define IDC_CHK_ONLYISOLATED 1107 +#define IDC_CMB_PRESETITEMS 1111 +#define IDC_CHK_LIMITMSG 1113 +#define IDC_ED_CHARCOUNT 1114 +#define IDC_SPIN_CHARCOUNT 1115 +#define IDC_LB_SKINS 1116 +#define IDC_PIC_PREVIEW 1117 +#define IDC_ST_PREVIEW 1119 +#define IDC_CHK_LOADFONTS 1120 +#define IDC_CHK_ENABLECOLORING 1121 +#define IDC_CHK_LOADPROPORTIONS 1122 +#define IDC_BTN_RELOADLIST 1123 +#define IDC_BTN_APPLYSKIN 1124 +#define IDC_BTN_VARIABLE 1125 +#define IDC_BTN_GETSKINS 1125 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 118 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1127 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/TipperYM/src/skin_parser.cpp b/plugins/TipperYM/src/skin_parser.cpp new file mode 100644 index 0000000000..3c851e0039 --- /dev/null +++ b/plugins/TipperYM/src/skin_parser.cpp @@ -0,0 +1,417 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "options.h" +#include "str_utils.h" + +extern TCHAR SKIN_FOLDER[256]; + +int RefreshSkinList(HWND hwndDlg) +{ + HWND hwndSkins = GetDlgItem(hwndDlg, IDC_LB_SKINS); + ListBox_ResetContent(hwndSkins); + ListBox_AddString(hwndSkins, TranslateT("# Solid color fill")); + + TCHAR szDirSave[1024]; + GetCurrentDirectory(1024, szDirSave); + SetCurrentDirectory(SKIN_FOLDER); + + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(_T("*.*"), &ffd); + while (hFind != INVALID_HANDLE_VALUE) + { + if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && _tcscmp(_T("."), ffd.cFileName) && _tcscmp(_T(".."), ffd.cFileName)) + { + SetCurrentDirectory(ffd.cFileName); + WIN32_FIND_DATA ffd2; + HANDLE hFindFile = FindFirstFile(_T("*.tsf"), &ffd2); + if (hFindFile != INVALID_HANDLE_VALUE) + ListBox_AddString(hwndSkins, ffd.cFileName); + + FindClose(hFindFile); + SetCurrentDirectory(_T("..")); + } + + if (!FindNextFile(hFind, &ffd)) + break; + } + + FindClose(hFind); + SetCurrentDirectory(szDirSave); + + return ListBox_SelectString(GetDlgItem(hwndDlg, IDC_LB_SKINS), -1, opt.szSkinName); +} + +bool FileExists(TCHAR *filename) +{ + HANDLE hFile = CreateFile(filename, 0, 0, 0, OPEN_EXISTING, 0, 0); + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + return true; + } + + return false; +} + +void ParseAboutPart(FILE *fp, TCHAR *buff, TCHAR *szSkinName) +{ + myfgets(buff, 1024, fp); + while (buff[0] != '[') + { + if (buff[0] != ';') + { + TCHAR *pch = _tcschr(buff, '='); + if (pch++) + { + while (pch && (*pch == ' ' || *pch == '\t')) + pch++; + + if (pch) + { + if (_tcsstr(buff, _T("author"))) + {} + else if (_tcsstr(buff, _T("preview"))) + { + TCHAR szImgPath[1024]; + mir_sntprintf(szImgPath, SIZEOF(szImgPath), _T("%s\\%s\\%s"), SKIN_FOLDER, szSkinName, pch); + if (FileExists(szImgPath)) + _tcscpy(opt.szPreviewFile, szImgPath); + } + } + } + } + + if (feof(fp)) break; + myfgets(buff, 1024, fp); + } +} + +void ParseImagePart(FILE *fp, TCHAR *buff, int iPart) +{ + opt.szImgFile[iPart] = NULL; + opt.transfMode[iPart] = TM_NONE; + opt.margins[iPart].left = 0; + opt.margins[iPart].top = 0; + opt.margins[iPart].right = 0; + opt.margins[iPart].bottom = 0; + + myfgets(buff, 1024, fp); + while (buff[0] != '[') + { + if (buff[0] != ';') + { + TCHAR *pch = _tcschr(buff, '='); + if (pch++) + { + while (pch && (*pch == ' ' || *pch == '\t')) + pch++; + + if (pch) + { + if (_tcsstr(buff, _T("image"))) + { + TCHAR szImgPath[1024]; + mir_sntprintf(szImgPath, SIZEOF(szImgPath), _T("%s\\%s\\%s"), SKIN_FOLDER, opt.szSkinName, pch); + opt.szImgFile[iPart] = mir_tstrdup(szImgPath); + } + else if (_tcsstr(buff, _T("tm"))) + { + if (!lstrcmpi(pch, _T("TM_NONE"))) + opt.transfMode[iPart] = TM_NONE; + else if (!lstrcmpi(pch, _T("TM_CENTRE"))) + opt.transfMode[iPart] = TM_CENTRE; + else if (!lstrcmpi(pch, _T("TM_STRECH_ALL"))) + opt.transfMode[iPart] = TM_STRECH_ALL; + else if (!lstrcmpi(pch, _T("TM_STRECH_HORIZONTAL"))) + opt.transfMode[iPart] = TM_STRECH_HORIZONTAL; + else if (!lstrcmpi(pch, _T("TM_STRECH_VERTICAL"))) + opt.transfMode[iPart] = TM_STRECH_VERTICAL; + else if (!lstrcmpi(pch, _T("TM_TILE_ALL"))) + opt.transfMode[iPart] = TM_TILE_ALL; + else if (!lstrcmpi(pch, _T("TM_TILE_HORIZONTAL"))) + opt.transfMode[iPart] = TM_TILE_HORIZONTAL; + else if (!lstrcmpi(pch, _T("TM_TILE_VERTICAL"))) + opt.transfMode[iPart] = TM_TILE_VERTICAL; + else + opt.transfMode[iPart] = TM_NONE; + } + else if (_tcsstr(buff, _T("left"))) + opt.margins[iPart].left = _ttoi(pch); + else if (_tcsstr(buff, _T("top"))) + opt.margins[iPart].top = _ttoi(pch); + else if (_tcsstr(buff, _T("right"))) + opt.margins[iPart].right = _ttoi(pch); + else if (_tcsstr(buff, _T("bottom"))) + opt.margins[iPart].bottom = _ttoi(pch); + } + } + } + + if (feof(fp)) break; + myfgets(buff, 1024, fp); + } +} + +char *GetSettingName(TCHAR *szValue, char *szPostfix, char *buff) +{ + buff[0] = 0; + + if (_tcsstr(szValue, _T("traytitle"))) + mir_snprintf(buff, 64, "FontTrayTitle%s", szPostfix); + else if (_tcsstr(szValue, _T("title"))) + mir_snprintf(buff, 64, "FontFirst%s", szPostfix); + else if (_tcsstr(szValue, _T("label"))) + mir_snprintf(buff, 64, "FontLabels%s", szPostfix); + else if (_tcsstr(szValue, _T("value"))) + mir_snprintf(buff, 64, "FontValues%s", szPostfix); + else if (_tcsstr(szValue, _T("divider"))) + mir_snprintf(buff, 64, "Divider%s", szPostfix); + + if (buff[0]) return buff; + else return NULL; +} + +void ParseFontPart(FILE *fp, TCHAR *buff) +{ + char szSetting[64]; + + myfgets(buff, 1024, fp); + while (buff[0] != '[') + { + if (buff[0] != ';') + { + TCHAR *pch = _tcschr(buff, '='); + if (pch++) + { + while (pch && (*pch == ' ' || *pch == '\t')) + pch++; + + if (pch) + { + if (_tcsstr(buff, _T("face"))) + { + if (GetSettingName(buff, "", szSetting)) + { + if (_tcslen(pch) > 32) + pch[32] = 0; + + DBWriteContactSettingTString(0, MODULE, szSetting, pch); + } + } + else if (_tcsstr(buff, _T("color"))) + { + if (GetSettingName(buff, "Col", szSetting)) + { + BYTE r = _ttoi(pch); + pch = _tcschr(pch, ' '); + if (++pch) + { + BYTE g = _ttoi(pch); + pch = _tcschr(pch, ' '); + if (++pch) + { + BYTE b = _ttoi(pch); + COLORREF color = RGB(r, g ,b); + DBWriteContactSettingDword(0, MODULE, szSetting, color); + } + } + } + } + else if (_tcsstr(buff, _T("size"))) + { + if (GetSettingName(buff, "Size", szSetting)) + { + HDC hdc = GetDC(0); + int size = -MulDiv(_ttoi(pch), GetDeviceCaps(hdc, LOGPIXELSY), 72); + DBWriteContactSettingByte(0, MODULE, szSetting, (BYTE)size); + ReleaseDC(0, hdc); + } + } + else if (_tcsstr(buff, _T("effect"))) + { + if (GetSettingName(buff, "Sty", szSetting)) + { + BYTE effect = 0; + if (_tcsstr(pch, _T("font_bold"))) + effect |= DBFONTF_BOLD; + if (_tcsstr(pch, _T("font_italic"))) + effect |= DBFONTF_ITALIC; + if (_tcsstr(pch, _T("font_underline"))) + effect |= DBFONTF_UNDERLINE; + + DBWriteContactSettingByte(0, MODULE, szSetting, effect); + } + } + } + } + } + + if (feof(fp)) break; + myfgets(buff, 1024, fp); + } +} + +void ParseAppearancePart(FILE *fp, TCHAR *buff) +{ + myfgets(buff, 1024, fp); + while (buff[0] != '[') + { + if (buff[0] != ';') + { + TCHAR *pch = _tcschr(buff, '='); + if (pch++) + { + while (pch && (*pch == ' ' || *pch == '\t')) + pch++; + + if (pch) + { + if (_tcsstr(buff, _T("general-padding"))) + opt.iPadding = _ttoi(pch); + else if (_tcsstr(buff, _T("title-indent"))) + opt.iTitleIndent = _ttoi(pch); + else if (_tcsstr(buff, _T("text-indent"))) + opt.iTextIndent = _ttoi(pch); + else if (_tcsstr(buff, _T("value-indent"))) + opt.iValueIndent = _ttoi(pch); + else if (_tcsstr(buff, _T("text-padding"))) + opt.iTextPadding = _ttoi(pch); + else if (_tcsstr(buff, _T("outer-avatar-padding"))) + opt.iOuterAvatarPadding = _ttoi(pch); + else if (_tcsstr(buff, _T("inner-avatar-padding"))) + opt.iInnerAvatarPadding = _ttoi(pch); + else if (_tcsstr(buff, _T("sidebar-width"))) + opt.iSidebarWidth = _ttoi(pch); + else if (_tcsstr(buff, _T("opacity"))) + opt.iOpacity = _ttoi(pch); + } + } + } + + if (feof(fp)) break; + myfgets(buff, 1024, fp); + } +} + +void ParseOtherPart(FILE *fp, TCHAR *buff) +{ + myfgets(buff, 1024, fp); + while (buff[0] != '[') + { + if (buff[0] != ';') + { + TCHAR *pch = _tcschr(buff, '='); + if (pch++) + { + while (pch && (*pch == ' ' || *pch == '\t')) + pch++; + + if (pch) + { + if (_tcsstr(buff, _T("enable-coloring"))) + { + if (_tcsstr(pch, _T("false"))) + opt.iEnableColoring = -1; + } + } + } + } + + if (feof(fp)) break; + myfgets(buff, 1024, fp); + } +} + +void ParseSkinFile(TCHAR *szSkinName, bool bStartup, bool bOnlyPreview) +{ + TCHAR szDirSave[1024], buff[1024]; + + if (opt.skinMode == SM_OBSOLOTE && bStartup) + return; + + if (!bStartup) opt.iEnableColoring = 0; + opt.szPreviewFile[0] = 0; + + GetCurrentDirectory(1024, szDirSave); + SetCurrentDirectory(SKIN_FOLDER); + SetCurrentDirectory(szSkinName); + + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(_T("*.tsf"), &ffd); + if (hFind != INVALID_HANDLE_VALUE) + { + FILE *fp = _tfopen(ffd.cFileName, _T("r")); + if (fp) + { + myfgets(buff, 1024, fp); + while (!feof(fp)) + { + if (buff[0] == '[') + { + if (!_tcscmp(_T("[about]"), buff)) + { + ParseAboutPart(fp, buff, szSkinName); + continue; + } + else if (!_tcscmp(_T("[other]"), buff)) + { + ParseOtherPart(fp, buff); + continue; + } + else if (!bOnlyPreview) + { + if (!_tcscmp(_T("[background]"), buff)) + { + ParseImagePart(fp, buff, SKIN_ITEM_BG); + continue; + } + else if (!_tcscmp(_T("[sidebar]"), buff)) + { + ParseImagePart(fp, buff, SKIN_ITEM_SIDEBAR); + continue; + } + else if (!bStartup && opt.bLoadFonts && !_tcscmp(_T("[fonts]"), buff)) + { + ParseFontPart(fp, buff); + continue; + } + else if (!bStartup && opt.bLoadProportions && !_tcscmp(_T("[appearance]"), buff)) + { + ParseAppearancePart(fp, buff); + continue; + } + } + } + + myfgets(buff, 1024, fp); + } + fclose(fp); + } + } + else + { + opt.skinMode = SM_COLORFILL; + } + + FindClose(hFind); + SetCurrentDirectory(szDirSave); +} \ No newline at end of file diff --git a/plugins/TipperYM/src/skin_parser.h b/plugins/TipperYM/src/skin_parser.h new file mode 100644 index 0000000000..ca83f47915 --- /dev/null +++ b/plugins/TipperYM/src/skin_parser.h @@ -0,0 +1,30 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _SKIN_INC +#define _SKIN_INC + +typedef enum { + SM_COLORFILL = 0, SM_IMAGE = 1, SM_OBSOLOTE = 2 +} SkinMode; + +int RefreshSkinList(HWND hwndDlg); +void ParseSkinFile(TCHAR *szSkinName, bool bStartup, bool bOnlyPreview); +#endif \ No newline at end of file diff --git a/plugins/TipperYM/src/str_utils.cpp b/plugins/TipperYM/src/str_utils.cpp new file mode 100644 index 0000000000..112cc2678b --- /dev/null +++ b/plugins/TipperYM/src/str_utils.cpp @@ -0,0 +1,231 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "str_utils.h" + +int iCodePage = CP_ACP; + +bool a2w(const char *as, wchar_t *buff, int bufflen) +{ + if (as) MultiByteToWideChar(iCodePage, 0, as, -1, buff, bufflen); + return true; +} + +bool w2a(const wchar_t *ws, char *buff, int bufflen) +{ + if (ws) WideCharToMultiByte(iCodePage, 0, ws, -1, buff, bufflen, 0, 0); + return true; +} + +bool utf2w(const char *us, wchar_t *buff, int bufflen) +{ + if (us) MultiByteToWideChar(CP_UTF8, 0, us, -1, buff, bufflen); + return true; +} + +bool w2utf(const wchar_t *ws, char *buff, int bufflen) +{ + if (ws) WideCharToMultiByte(CP_UTF8, 0, ws, -1, buff, bufflen, 0, 0); + return true; +} + +bool a2utf(const char *as, char *buff, int bufflen) +{ + if (!as) return false; + + wchar_t *ws = a2w(as); + if (ws) WideCharToMultiByte(CP_UTF8, 0, ws, -1, buff, bufflen, 0, 0); + mir_free(ws); + return true; +} + +bool utf2a(const char *us, char *buff, int bufflen) +{ + if (!us) return false; + + wchar_t *ws = utf2w(us); + if (ws) WideCharToMultiByte(iCodePage, 0, ws, -1, buff, bufflen, 0, 0); + mir_free(ws); + return true; +} + + +bool t2w(const TCHAR *ts, wchar_t *buff, int bufflen) +{ + + wcsncpy(buff, ts, bufflen); + return true; + +} + +bool w2t(const wchar_t *ws, TCHAR *buff, int bufflen) +{ + + wcsncpy(buff, ws, bufflen); + return true; + +} + +bool t2a(const TCHAR *ts, char *buff, int bufflen) +{ + + return w2a(ts, buff, bufflen); + +} + +bool a2t(const char *as, TCHAR *buff, int bufflen) +{ + + return a2w(as, buff, bufflen); + +} + +bool t2utf(const TCHAR *ts, char *buff, int bufflen) +{ + + return w2utf(ts, buff, bufflen); + +} + +bool utf2t(const char *us, TCHAR *buff, int bufflen) +{ + + return utf2w(us, buff, bufflen); + +} + +wchar_t *utf2w(const char *us) +{ + if (us) + { + int size = MultiByteToWideChar(CP_UTF8, 0, us, -1, 0, 0); + wchar_t *buff = (wchar_t *)mir_alloc(size * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, us, -1, buff, size); + return buff; + } + else + { + return 0; + } +} + +char *w2utf(const wchar_t *ws) +{ + if (ws) + { + int size = WideCharToMultiByte(CP_UTF8, 0, ws, -1, 0, 0, 0, 0); + char *buff = (char *)mir_alloc(size); + WideCharToMultiByte(CP_UTF8, 0, ws, -1, buff, size, 0, 0); + return buff; + } + else + { + return 0; + } +} + +wchar_t *a2w(const char *as) +{ + int size = MultiByteToWideChar(iCodePage, 0, as, -1, 0, 0); + wchar_t *buff = (wchar_t *)mir_alloc(size * sizeof(wchar_t)); + MultiByteToWideChar(iCodePage, 0, as, -1, buff, size); + return buff; +} + +char *w2a(const wchar_t *ws) +{ + int size = WideCharToMultiByte(iCodePage, 0, ws, -1, 0, 0, 0, 0); + char *buff = (char *)mir_alloc(size); + WideCharToMultiByte(iCodePage, 0, ws, -1, buff, size, 0, 0); + return buff; +} + +char *utf2a(const char *utfs) +{ + wchar_t *ws = utf2w(utfs); + char *ret = w2a(ws); + mir_free(ws); + return ret; +} + +char *a2utf(const char *as) +{ + wchar_t *ws = a2w(as); + char *ret = w2utf(ws); + mir_free(ws); + return ret; +} + +TCHAR *w2t(const wchar_t *ws) +{ + + return mir_wstrdup(ws); + +} + +wchar_t *t2w(const TCHAR *ts) +{ + + return mir_tstrdup(ts); + +} + + +char *t2a(const TCHAR *ts) +{ + + return w2a(ts); + +} + +TCHAR *a2t(const char *as) +{ + + return a2w(as); + +} + +TCHAR *utf2t(const char *utfs) +{ + + return utf2w(utfs); +} + +char *t2utf(const TCHAR *ts) +{ + + return w2utf(ts); +} + +TCHAR *myfgets(TCHAR *Buf, int MaxCount, FILE *File) +{ + _fgetts(Buf, MaxCount, File); + for (size_t i = _tcslen(Buf) - 1; i >= 0; i--) + { + if (Buf[i] == '\n' || Buf[i] == ' ') + Buf[i] = 0; + else + break; + } + + CharLower(Buf); + return Buf; +} \ No newline at end of file diff --git a/plugins/TipperYM/src/str_utils.h b/plugins/TipperYM/src/str_utils.h new file mode 100644 index 0000000000..26fbb613fa --- /dev/null +++ b/plugins/TipperYM/src/str_utils.h @@ -0,0 +1,66 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _STR_UTILS_INC +#define _STR_UTILS_INC + +void set_codepage(); + +bool a2w(const char *as, wchar_t *buff, int bufflen); +bool w2a(const wchar_t *ws, char *buff, int bufflen); + +bool utf2w(const char *us, wchar_t *buff, int bufflen); +bool w2utf(const wchar_t *ws, char *buff, int bufflen); + +bool a2utf(const char *as, char *buff, int bufflen); +bool utf2a(const char *ws, char *buff, int bufflen); + +bool t2w(const TCHAR *ts, wchar_t *buff, int bufflen); +bool w2t(const wchar_t *ws, TCHAR *buff, int bufflen); + +bool t2a(const TCHAR *ts, char *buff, int bufflen); +bool a2t(const char *as, TCHAR *buff, int bufflen); + +bool t2utf(const TCHAR *ts, char *buff, int bufflen); +bool utf2t(const char *us, TCHAR *buff, int bufflen); + +// remember to free return value +wchar_t *a2w(const char *as); +char *w2a(const wchar_t *ws); + +wchar_t *utf2w(const char *us); +char *w2utf(const wchar_t *ws); + +char *utf2a(const char *us); +char *a2utf(const char *as); + +wchar_t *t2w(const TCHAR *ts); +TCHAR *w2t(const wchar_t *ws); + +TCHAR *utf2t(const char *us); +char *t2utf(const TCHAR *ts); + +char *t2a(const TCHAR *ts); +TCHAR *a2t(const char *as); + +TCHAR *myfgets(TCHAR *Buf, int MaxCount, FILE *File); + +#endif + diff --git a/plugins/TipperYM/src/subst.cpp b/plugins/TipperYM/src/subst.cpp new file mode 100644 index 0000000000..1d8c8837d9 --- /dev/null +++ b/plugins/TipperYM/src/subst.cpp @@ -0,0 +1,1011 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "subst.h" +#include "str_utils.h" +#include "popwin.h" + + +int ProtoServiceExists(const char *szModule, const char *szService) +{ + char str[MAXMODULELABELLENGTH]; + strcpy(str,szModule); + strcat(str,szService); + return ServiceExists(str); +} + +bool DBGetContactSettingAsString(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + buff[0] = 0; + + if (!szModuleName || !szSettingName) + return false; + + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + switch(dbv.type) + { + case DBVT_BYTE: + _itot(dbv.bVal, buff, 10); + break; + case DBVT_WORD: + _ltot(dbv.wVal, buff, 10); + break; + case DBVT_DWORD: + _ltot(dbv.dVal, buff, 10); + break; + case DBVT_ASCIIZ: + if (dbv.pszVal) a2t(dbv.pszVal, buff, bufflen); + buff[bufflen - 1] = 0; + break; + case DBVT_UTF8: + if (dbv.pszVal) utf2t(dbv.pszVal, buff, bufflen); + buff[bufflen - 1] = 0; + break; + + case DBVT_WCHAR: + if (dbv.pwszVal) wcsncpy(buff, dbv.pwszVal, bufflen); + buff[bufflen - 1] = 0; + break; + + } + + DBFreeVariant(&dbv); + } + + return buff[0] ? true : false; +} + +void StripBBCodesInPlace(TCHAR *swzText) +{ + if (!DBGetContactSettingByte(0, MODULE, "StripBBCodes", 1)) + return; + + if (swzText == 0) + return; + + size_t iRead = 0, iWrite = 0; + size_t iLen = _tcslen(swzText); + + while(iRead <= iLen) // copy terminating null too + { + while(iRead <= iLen && swzText[iRead] != '[') + { + if (swzText[iRead] != swzText[iWrite]) swzText[iWrite] = swzText[iRead]; + iRead++; iWrite++; + } + + if (iRead > iLen) + break; + + if (iLen - iRead >= 3 && (_tcsnicmp(swzText + iRead, _T("[b]"), 3) == 0 || _tcsnicmp(swzText + iRead, _T("[i]"), 3) == 0)) + iRead += 3; + else if (iLen - iRead >= 4 && (_tcsnicmp(swzText + iRead, _T("[/b]"), 4) == 0 || _tcsnicmp(swzText + iRead, _T("[/i]"), 4) == 0)) + iRead += 4; + else if (iLen - iRead >= 6 && (_tcsnicmp(swzText + iRead, _T("[color"), 6) == 0)) + { + while(iRead < iLen && swzText[iRead] != ']') iRead++; + iRead++;// skip the ']' + } + else if (iLen - iRead >= 8 && (_tcsnicmp(swzText + iRead, _T("[/color]"), 8) == 0)) + iRead += 8; + else if (iLen - iRead >= 5 && (_tcsnicmp(swzText + iRead, _T("[size"), 5) == 0)) + { + while(iRead < iLen && swzText[iRead] != ']') iRead++; + iRead++;// skip the ']' + } + else if (iLen - iRead >= 7 && (_tcsnicmp(swzText + iRead, _T("[/size]"), 7) == 0)) + iRead += 7; + else + { + if (swzText[iRead] != swzText[iWrite]) swzText[iWrite] = swzText[iRead]; + iRead++; iWrite++; + } + } +} + +DWORD LastMessageTimestamp(HANDLE hContact) +{ + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0); + while (hDbEvent) + { + dbei.cbBlob = 0; + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); + if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) + break; + + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0); + } + + if (hDbEvent) + return dbei.timestamp; + + return 0; +} + +void FormatTimestamp(DWORD ts, char *szFormat, TCHAR *buff, int bufflen) +{ + TCHAR swzForm[16]; + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + a2t(szFormat, swzForm, 16); + dbt.szFormat = swzForm; + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); +} + +bool Uid(HANDLE hContact, char *szProto, TCHAR *buff, int bufflen) +{ + char *tmpProto = NULL; + + if (hContact) tmpProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact, 0); + else tmpProto = szProto; + + if (tmpProto) + { + char *szUid = ( char* )CallProtoService(tmpProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0); + if (szUid && (INT_PTR)szUid != CALLSERVICE_NOTFOUND) + return DBGetContactSettingAsString(hContact, tmpProto, szUid, buff, bufflen); + } + + return false; +} + +bool UidName(char *szProto, TCHAR *buff, int bufflen) +{ + if (szProto) + { + char *szUidName = ( char* )CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0); + if (szUidName && (INT_PTR)szUidName != CALLSERVICE_NOTFOUND) + { + a2t(szUidName, buff, bufflen); + return true; + } + } + return false; +} + +TCHAR *GetLastMessageText(HANDLE hContact) +{ + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + + HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0); + while (hDbEvent) + { + dbei.cbBlob = 0; + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); + if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) + break; + + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0); + } + + if (hDbEvent) + { + dbei.pBlob = (BYTE *)alloca(dbei.cbBlob); + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); + + if (dbei.cbBlob == 0 || dbei.pBlob == 0) + return 0; + + TCHAR *buff = DbGetEventTextT( &dbei, CP_ACP ); + TCHAR *swzMsg = mir_tstrdup(buff); + mir_free(buff); + + StripBBCodesInPlace(swzMsg); + return swzMsg; + } + + return 0; +} + +bool CanRetrieveStatusMsg(HANDLE hContact, char *szProto) +{ + if (opt.bGetNewStatusMsg) + { + int iFlags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0); + WORD wStatus = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE); + if ((CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) && (iFlags & Proto_Status2Flag(wStatus))) + { + iFlags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & (PF1_VISLIST | PF1_INVISLIST); + if (opt.bDisableIfInvisible && iFlags) + { + int iVisMode = DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0); + int wProtoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if ((iVisMode == ID_STATUS_OFFLINE) || (wProtoStatus == ID_STATUS_INVISIBLE && iVisMode != ID_STATUS_ONLINE)) + return false; + else + return true; + } + else + { + return true; + } + } + else + { + return false; + } + } + + return false; +} + +TCHAR *GetStatusMessageText(HANDLE hContact) +{ + TCHAR *swzMsg = 0; + DBVARIANT dbv; + + char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto) + { + if (!strcmp(szProto, szMetaModuleName)) + { + hContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0); + } + else + { + WORD wStatus = (int)CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (wStatus == ID_STATUS_OFFLINE) + return NULL; + + if (!DBGetContactSettingTString(hContact, MODULE, "TempStatusMsg", &dbv)) + { + if (_tcslen(dbv.ptszVal) != 0) + swzMsg = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + + if (!swzMsg) + { + if (CanRetrieveStatusMsg(hContact, szProto)) + { + if (CallContactService(hContact, PSS_GETAWAYMSG, 0, 0)) + return NULL; + } + + if (!DBGetContactSettingTString(hContact, "CList", "StatusMsg", &dbv)) + { + if (dbv.ptszVal && _tcslen(dbv.ptszVal) != 0) + swzMsg = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + } + + if (swzMsg) + StripBBCodesInPlace(swzMsg); + + return swzMsg; +} + +bool GetSysSubstText(HANDLE hContact, TCHAR *swzRawSpec, TCHAR *buff, int bufflen) +{ + if (!_tcscmp(swzRawSpec, _T("uid"))) + { + return Uid(hContact, 0, buff, bufflen); + } + else if (!_tcscmp(swzRawSpec, _T("proto"))) + { + char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto) + { + a2t(szProto, buff, bufflen); + return true; + } + } + else if (!_tcscmp(swzRawSpec, _T("account"))) + { + char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEACCOUNT, (WPARAM)hContact, 0); + if ((INT_PTR)szProto == CALLSERVICE_NOTFOUND) + { + return GetSysSubstText(hContact, _T("proto"), buff, bufflen); + } + else if (szProto) + { + PROTOACCOUNT *pa = ProtoGetAccount(szProto); + if (pa && pa->tszAccountName) + { + _tcsncpy(buff, pa->tszAccountName, bufflen); + return true; + } + else + return GetSysSubstText(hContact, _T("proto"), buff, bufflen); + } + } + else if (!_tcscmp(swzRawSpec, _T("time"))) + { + if (tmi.printDateTime && !tmi.printDateTimeByContact(hContact, _T("t"), buff, bufflen, TZF_KNOWNONLY)) + return true; + } + else if (!_tcscmp(swzRawSpec, _T("uidname"))) + { + char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + return UidName(szProto, buff, bufflen); + } + else if (!_tcscmp(swzRawSpec, _T("status_msg"))) + { + TCHAR *swzMsg = GetStatusMessageText(hContact); + if (swzMsg) + { + _tcsncpy(buff, swzMsg, bufflen); + mir_free(swzMsg); + return true; + } + } + else if (!_tcscmp(swzRawSpec, _T("last_msg"))) + { + TCHAR *swzMsg = GetLastMessageText(hContact); + if (swzMsg) + { + _tcsncpy(buff, swzMsg, bufflen); + mir_free(swzMsg); + return true; + } + } + else if (!_tcscmp(swzRawSpec, _T("meta_subname"))) + { + // get contact list name of active subcontact + HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0); + if (!hSubContact || (INT_PTR)hSubContact == CALLSERVICE_NOTFOUND) return false; + TCHAR *swzNick = (TCHAR *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, GCDNF_TCHAR); + if (swzNick) _tcsncpy(buff, swzNick, bufflen); + return true; + } + else if (!_tcscmp(swzRawSpec, _T("meta_subuid"))) + { + HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0); + if (!hSubContact || (INT_PTR)hSubContact == CALLSERVICE_NOTFOUND) return false; + return Uid(hSubContact, 0, buff, bufflen); + } + else if (!_tcscmp(swzRawSpec, _T("meta_subproto"))) + { + // get protocol of active subcontact + HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0); + if (!hSubContact || (INT_PTR)hSubContact == CALLSERVICE_NOTFOUND) + return false; + return GetSysSubstText(hSubContact, _T("account"), buff, bufflen); + } + else if (!_tcscmp(swzRawSpec, _T("last_msg_time"))) + { + DWORD ts = LastMessageTimestamp(hContact); + if (ts == 0) return false; + FormatTimestamp(ts, "t", buff, bufflen); + return true; + } + else if (!_tcscmp(swzRawSpec, _T("last_msg_date"))) + { + DWORD ts = LastMessageTimestamp(hContact); + if (ts == 0) return false; + FormatTimestamp(ts, "d", buff, bufflen); + return true; + } + else if (!_tcscmp(swzRawSpec, _T("last_msg_reltime"))) + { + DWORD ts = LastMessageTimestamp(hContact); + if (ts == 0) return false; + DWORD t = (DWORD)time(0); + DWORD diff = (t - ts); + int d = (diff / 60 / 60 / 24); + int h = (diff - d * 60 * 60 * 24) / 60 / 60; + int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60; + if (d > 0) mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m); + else if (h > 0) mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m); + else mir_sntprintf(buff, bufflen, TranslateT("%dm"), m); + return true; + } + else if (!_tcscmp(swzRawSpec, _T("msg_count_all")) || !_tcscmp(swzRawSpec, _T("msg_count_out")) || !_tcscmp(swzRawSpec, _T("msg_count_in"))) + { + DWORD dwCountOut, dwCountIn; + DWORD dwMetaCountOut = 0, dwMetaCountIn = 0; + DWORD dwLastTs, dwNewTs, dwRecountTs; + DWORD dwTime, dwDiff; + int iNumber = 1; + HANDLE hTmpContact = hContact; + + char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto && !strcmp(szProto, szMetaModuleName)) + { + iNumber = CallService(MS_MC_GETNUMCONTACTS, (WPARAM)hContact, 0); + hTmpContact = (HANDLE)CallService(MS_MC_GETSUBCONTACT, (WPARAM)hContact, 0); + } + + for (int i = 0; i < iNumber; i++) + { + if (i > 0) hTmpContact = (HANDLE)CallService(MS_MC_GETSUBCONTACT, (WPARAM)hContact, i); + dwRecountTs = DBGetContactSettingDword(hTmpContact, MODULE, "LastCountTS", 0); + dwTime = (DWORD)time(0); + dwDiff = (dwTime - dwRecountTs); + if (dwDiff > (60 * 60 * 24 * 3)) + { + DBWriteContactSettingDword(hTmpContact, MODULE, "LastCountTS", dwTime); + dwCountOut = dwCountIn = dwLastTs = 0; + } + else + { + dwCountOut = DBGetContactSettingDword(hTmpContact, MODULE, "MsgCountOut", 0); + dwCountIn = DBGetContactSettingDword(hTmpContact, MODULE, "MsgCountIn", 0); + dwLastTs = DBGetContactSettingDword(hTmpContact, MODULE, "LastMsgTS", 0); + } + + dwNewTs = dwLastTs; + + HANDLE dbe = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hTmpContact, 0); + while (dbe != NULL) + { + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if (!CallService(MS_DB_EVENT_GET, (WPARAM)dbe, (LPARAM)&dbei)) + { + if (dbei.eventType == EVENTTYPE_MESSAGE) + { + dwNewTs = max(dwNewTs, dbei.timestamp); + if (dbei.timestamp > dwLastTs) + { + if (dbei.flags & DBEF_SENT) dwCountOut++; + else dwCountIn++; + } + else + break; + } + } + dbe = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)dbe, 0); + } + + if (dwNewTs > dwLastTs) + { + DBWriteContactSettingDword(hTmpContact, MODULE, "MsgCountOut", dwCountOut); + DBWriteContactSettingDword(hTmpContact, MODULE, "MsgCountIn", dwCountIn); + DBWriteContactSettingDword(hTmpContact, MODULE, "LastMsgTS", dwNewTs); + } + + dwMetaCountOut += dwCountOut; + dwMetaCountIn += dwCountIn; + } + + if (!_tcscmp(swzRawSpec, _T("msg_count_out"))) + mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountOut); + else if (!_tcscmp(swzRawSpec, _T("msg_count_in"))) + mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountIn); + else + mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountOut + dwMetaCountIn); + return true; + } + + return false; +} + +bool GetSubstText(HANDLE hContact, const DISPLAYSUBST &ds, TCHAR *buff, int bufflen) +{ + TranslateFunc *transFunc = 0; + for (int i = 0; i < iTransFuncsCount; i++) + { + if (translations[i].id == (DWORD)ds.iTranslateFuncId) + { + transFunc = translations[i].transFunc; + break; + } + } + + if (!transFunc) + return false; + + switch (ds.type) + { + case DVT_DB: + return transFunc(hContact, ds.szModuleName, ds.szSettingName, buff, bufflen) != 0; + case DVT_PROTODB: + { + char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto) + { + if (transFunc(hContact, szProto, ds.szSettingName, buff, bufflen) != 0) + return true; + else + return transFunc(hContact, "UserInfo", ds.szSettingName, buff, bufflen) != 0; + } + break; + } + } + return false; +} + +bool GetRawSubstText(HANDLE hContact, char *szRawSpec, TCHAR *buff, int bufflen) +{ + size_t lenght = strlen(szRawSpec); + for (size_t i = 0; i < lenght; i++) + { + if (szRawSpec[i] == '/') + { + szRawSpec[i] = 0; + if (strlen(szRawSpec) == 0) + { + char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (szProto) + { + if (translations[0].transFunc(hContact, szProto, &szRawSpec[i + 1], buff, bufflen) != 0) + return true; + else + return translations[0].transFunc(hContact, "UserInfo", &szRawSpec[i + 1], buff, bufflen) != 0; + } + else + { + return false; + } + } + else + { + return translations[0].transFunc(hContact, szRawSpec, &szRawSpec[i + 1], buff, bufflen) != 0; + } + } + } + return false; +} + +bool ApplySubst(HANDLE hContact, const TCHAR *swzSource, bool parseTipperVarsFirst, TCHAR *swzDest, int iDestLen) +{ + // hack - allow empty strings before passing to variables (note - zero length strings return false after this) + if (swzDest && swzSource && _tcslen(swzSource) == 0) { + swzDest[0] = 0; + return true; + } + + // pass to variables plugin if available + TCHAR *swzVarSrc; + if (parseTipperVarsFirst == false) + swzVarSrc = variables_parsedup((TCHAR *)swzSource, 0, hContact); + else + swzVarSrc = mir_tstrdup(swzSource); + + size_t iSourceLen = _tcslen(swzVarSrc); + size_t si = 0, di = 0, v = 0; + + TCHAR swzVName[LABEL_LEN]; + TCHAR swzRep[VALUE_LEN], swzAlt[VALUE_LEN]; + while (si < iSourceLen && di < (size_t)iDestLen - 1) + { + if (swzVarSrc[si] == _T('%')) + { + si++; + v = 0; + while (si < iSourceLen && v < LABEL_LEN) + { + if (swzVarSrc[si] == _T('%')) + { + // two %'s in a row in variable name disabled: e.g. %a%%b% - this is atbbguous] + //if (si + 1 < iSourceLen && swzVarSrc[si + 1] == _T('%')) { + // si++; // skip first %, allow following code to add the second one to the variable name + //} else + break; + } + swzVName[v] = swzVarSrc[si]; + v++; si++; + } + + if (v == 0) // bSubst len is 0 - just a % symbol + { + swzDest[di] = _T('%'); + } + else if (si < iSourceLen) // we found end % + { + swzVName[v] = 0; + + bool bAltSubst = false; + bool bSubst = false; + + // apply only to specific protocols + TCHAR *p = _tcsrchr(swzVName, _T('^')); // use last '^', so if you want a ^ in swzAlt text, you can just put a '^' on the end + if (p) + { + *p = 0; + p++; + if (*p) + { + char *cp = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (cp != NULL) + { + PROTOACCOUNT *acc = ProtoGetAccount(cp); + if (acc != NULL) + { + cp = acc->szProtoName; + } + } + + if (cp == NULL) + goto empty; + + bool negate = false; + if (*p == _T('!')) + { + p++; + if (*p == 0) goto error; + negate = true; + } + + char sproto[256]; + bool spec = false; + int len; + + TCHAR *last = _tcsrchr(p, _T(',')); + if (!last) last = p; + + while (p <= last + 1) + { + len = (int)_tcscspn(p, _T(",")); + t2a(p, sproto, len); + sproto[len] = 0; + p += len + 1; + + if (_stricmp(cp, sproto) == 0) + { + spec = true; + break; + } + } + + if (negate ? spec : !spec) + goto empty; + } + } + + // get alternate text, if bSubst fails + swzAlt[0] = 0; + p = _tcschr(swzVName, _T('|')); // use first '|' - so you can use the '|' symbol in swzAlt text + if (p) + { + *p = 0; // clip swzAlt from swzVName + p++; + if (_tcslen(p) > 4 && _tcsncmp(p, _T("raw:"), 4) == 0) // raw db substitution + { + char raw_spec[LABEL_LEN]; + p += 4; + t2a(p, raw_spec, LABEL_LEN); + GetRawSubstText(hContact, raw_spec, swzAlt, VALUE_LEN); + } + else if (_tcslen(p) > 4 && _tcsncmp(p, _T("sys:"), 4) == 0) // 'system' substitution + { + p += 4; + GetSysSubstText(hContact, p, swzAlt, VALUE_LEN); + } + else + { + // see if we can find the bSubst + DSListNode *ds_node = opt.dsList; + while(ds_node) + { + if (_tcscmp(ds_node->ds.swzName, p) == 0) + break; + + ds_node = ds_node->next; + } + + if (ds_node) + { + GetSubstText(hContact, ds_node->ds, swzAlt, VALUE_LEN); + } + else + { + _tcsncpy(swzAlt, p, VALUE_LEN); + bAltSubst = true; + } + } + swzAlt[VALUE_LEN - 1] = 0; + if (_tcslen(swzAlt) != 0) + bAltSubst = true; + } + + // get bSubst text + if (v > 4 && _tcsncmp(swzVName, _T("raw:"), 4) == 0) // raw db substitution + { + char raw_spec[LABEL_LEN]; + t2a(&swzVName[4], raw_spec, LABEL_LEN); + bSubst = GetRawSubstText(hContact, raw_spec, swzRep, VALUE_LEN); + } + else if (v > 4 && _tcsncmp(swzVName, _T("sys:"), 4) == 0) // 'system' substitution + { + bSubst = GetSysSubstText(hContact, &swzVName[4], swzRep, VALUE_LEN); + } + else + { + // see if we can find the bSubst + DSListNode *ds_node = opt.dsList; + while(ds_node) + { + if (_tcscmp(ds_node->ds.swzName, swzVName) == 0) + break; + + ds_node = ds_node->next; + } + + if (!ds_node) + goto error; // no such bSubst + + bSubst = GetSubstText(hContact, ds_node->ds, swzRep, VALUE_LEN); + } + + if (bSubst) + { + size_t rep_len = _tcslen(swzRep); + _tcsncpy(&swzDest[di], swzRep, min(rep_len, iDestLen - di)); + di += rep_len - 1; // -1 because we inc at bottom of loop + } + else if (bAltSubst) + { + size_t alt_len = _tcslen(swzAlt); + _tcsncpy(&swzDest[di], swzAlt, min(alt_len, iDestLen - di)); + di += alt_len - 1; // -1 because we inc at bottom of loop + } + else + { + goto empty; // empty value + } + + } + else // no end % - error + { + goto error; + } + } + else + { + swzDest[di] = swzVarSrc[si]; + } + + si++; + di++; + } + + mir_free(swzVarSrc); + swzDest[di] = 0; + + if (parseTipperVarsFirst) + { + swzVarSrc = variables_parsedup((TCHAR *)swzDest, 0, hContact); + _tcscpy(swzDest, swzVarSrc); + mir_free(swzVarSrc); + } + + + // check for a 'blank' string - just spaces etc + for (si = 0; si <= di; si++) + { + if (swzDest[si] != 0 && swzDest[si] != _T(' ') && swzDest[si] != _T('\t') && swzDest[si] != _T('\r') && swzDest[si] != _T('\n')) + return true; + } + + return false; + +empty: + mir_free(swzVarSrc); + return false; + +error: + swzDest[0] = _T('*'); + swzDest[1] = 0; + mir_free(swzVarSrc); + return true; +} + +bool GetLabelText(HANDLE hContact, const DISPLAYITEM &di, TCHAR *buff, int bufflen) +{ + return ApplySubst(hContact, di.swzLabel, false, buff, bufflen); +} + +bool GetValueText(HANDLE hContact, const DISPLAYITEM &di, TCHAR *buff, int bufflen) +{ + return ApplySubst(hContact, di.swzValue, di.bParseTipperVarsFirst, buff, bufflen); +} + +void TruncateString(TCHAR *swzText) +{ + if (swzText && opt.iLimitCharCount > 3) + { + if ((int)_tcslen(swzText) > opt.iLimitCharCount) + { + swzText[opt.iLimitCharCount - 3] = 0; + _tcscat(swzText, _T("...")); + } + } +} + +TCHAR *GetProtoStatusMessage(char *szProto, WORD wStatus) +{ + if (!szProto || wStatus == ID_STATUS_OFFLINE) + return NULL; + + // check if protocol supports status message for status + int flags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0); + if (!(flags & Proto_Status2Flag(wStatus))) + return NULL; + + TCHAR *swzText = (TCHAR *)CallProtoService(szProto, PS_GETMYAWAYMSG, 0, SGMA_TCHAR); + if ((INT_PTR)swzText == CALLSERVICE_NOTFOUND) + { + swzText = (TCHAR*)CallService(MS_AWAYMSG_GETSTATUSMSGT, wStatus, 0); + } + + else if (swzText == NULL) + { + // try to use service without SGMA_TCHAR + char *tmpMsg = (char *)CallProtoService(szProto, PS_GETMYAWAYMSG, 0, 0); + if (tmpMsg && (INT_PTR)tmpMsg != CALLSERVICE_NOTFOUND) + { + swzText = mir_a2t(tmpMsg); + mir_free(tmpMsg); + } + } + + + if (swzText && !swzText[0]) + { + mir_free(swzText); + swzText = NULL; + } + + if (swzText && opt.bLimitMsg) + TruncateString(swzText); + + return swzText; +} + +TCHAR *GetProtoExtraStatusTitle(char *szProto) +{ + DBVARIANT dbv; + TCHAR *swzText = NULL; + + if (!szProto) + return NULL; + + if (!DBGetContactSettingTString(0, szProto, "XStatusName", &dbv)) + { + if (_tcslen(dbv.ptszVal) != 0) + swzText = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } + + if (!swzText) + { + TCHAR buff[256]; + if (EmptyXStatusToDefaultName(0, szProto, 0, buff, 256)) + swzText = mir_tstrdup(buff); + } + + if (opt.bLimitMsg) + TruncateString(swzText); + + return swzText; +} + +TCHAR *GetProtoExtraStatusMessage(char *szProto) +{ + DBVARIANT dbv; + TCHAR *swzText = NULL; + + if (!szProto) + return NULL; + + if (!DBGetContactSettingTString(0, szProto, "XStatusMsg", &dbv)) + { + if (_tcslen(dbv.ptszVal) != 0) + swzText = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + + if (ServiceExists(MS_VARS_FORMATSTRING)) + { + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + char *proto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + while(!proto) + { + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + if (hContact) + { + proto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + } + else + { + hContact = NULL; + break; + } + } + + TCHAR *tszParsed = (TCHAR *)variables_parse(swzText, NULL, hContact); + if (tszParsed) + { + mir_free(swzText); + swzText = mir_tstrdup(tszParsed); + variables_free(tszParsed); + } + } + } + + if (opt.bLimitMsg) + TruncateString(swzText); + + return swzText; +} + +TCHAR *GetListeningTo(char *szProto) +{ + DBVARIANT dbv; + TCHAR *swzText = NULL; + + if (!szProto) + return NULL; + + if (!DBGetContactSettingTString(0, szProto, "ListeningTo", &dbv)) + { + if (_tcslen(dbv.ptszVal) != 0) + swzText = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } + + if (opt.bLimitMsg) + TruncateString(swzText); + + return swzText; +} + +TCHAR *GetJabberAdvStatusText(char *szProto, const char *szSlot, const char *szValue) +{ + DBVARIANT dbv; + TCHAR *swzText = NULL; + char szSetting[128]; + + if (!szProto) + return NULL; + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, szSlot, szValue); + if (!DBGetContactSettingTString(0, "AdvStatus", szSetting, &dbv)) + { + if (_tcslen(dbv.ptszVal) != 0) + swzText = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } + + if (opt.bLimitMsg) + TruncateString(swzText); + + return swzText; +} + +HICON GetJabberActivityIcon(HANDLE hContact, char *szProto) +{ + DBVARIANT dbv; + HICON hIcon = NULL; + char szSetting[128]; + + if (!szProto) + return NULL; + + mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, "activity", "icon"); + if (!DBGetContactSettingString(hContact, "AdvStatus", szSetting, &dbv)) + { + hIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + } + + return hIcon; +} \ No newline at end of file diff --git a/plugins/TipperYM/src/subst.h b/plugins/TipperYM/src/subst.h new file mode 100644 index 0000000000..41f66f871a --- /dev/null +++ b/plugins/TipperYM/src/subst.h @@ -0,0 +1,47 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _SUBST_INC +#define _SUBST_INC + +#include "options.h" +#include "translations.h" + +bool GetLabelText(HANDLE hContact, const DISPLAYITEM &di, TCHAR *buff, int iBufflen); +bool GetValueText(HANDLE hContact, const DISPLAYITEM &di, TCHAR *buff, int iBufflen); + +void StripBBCodesInPlace(TCHAR *text); +int ProtoServiceExists(const char *szModule, const char *szService); + +// can be used with hContact == 0 to get uid for a given proto +bool UidName(char *szProto, TCHAR *buff, int bufflen); +bool Uid(HANDLE hContact, char *szProto, TCHAR *buff, int bufflen); + +// get info for status and tray tooltip +bool DBGetContactSettingAsString(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen); +bool CanRetrieveStatusMsg(HANDLE hContact, char *szProto); +TCHAR *GetProtoStatusMessage(char *szProto, WORD status); +TCHAR *GetProtoExtraStatusTitle(char *szProto); +TCHAR *GetProtoExtraStatusMessage(char *szProto); +TCHAR *GetListeningTo(char *szProto); +TCHAR *GetJabberAdvStatusText(char *szProto, const char *szSlot, const char *szValue); +HICON GetJabberActivityIcon(HANDLE hContact, char *szProto); + +#endif diff --git a/plugins/TipperYM/src/tipper.cpp b/plugins/TipperYM/src/tipper.cpp new file mode 100644 index 0000000000..8c0f5575de --- /dev/null +++ b/plugins/TipperYM/src/tipper.cpp @@ -0,0 +1,362 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "version.h" +#include "message_pump.h" +#include "options.h" +#include "popwin.h" +#include "skin_parser.h" +#include "str_utils.h" + +HMODULE hInst; + +char szMetaModuleName[256] = {0}; + +FontIDT fontTitle, fontLabels, fontValues, fontTrayTitle; +ColourIDT colourBg, colourBorder, colourAvatarBorder, colourDivider, colourSidebar; +HFONT hFontTitle, hFontLabels, hFontValues, hFontTrayTitle; + +// hooked here so it's in the main thread +HANDLE hAvChangeEvent, hShowTipEvent, hHideTipEvent, hAckEvent, hFramesSBShow, hFramesSBHide; +HANDLE hSettingChangedEvent, hEventDeleted; +HANDLE hShowTipService, hShowTipWService, hHideTipService; +HANDLE hReloadFonts = NULL; + +HANDLE hFolderChanged, hSkinFolder; +TCHAR SKIN_FOLDER[256]; + +FI_INTERFACE *fii = NULL; +TIME_API tmi; +int hLangpack; + +PLUGININFOEX pluginInfoEx = +{ + sizeof(PLUGININFOEX), + "Tipper YM", + __VERSION_DWORD, + "Tool Tip notification windows.", + "Scott Ellis, yaho", + "yaho@miranda-easy.net", + "© 2005-2007 Scott Ellis, 2007-2011 Jan Holub", + "http://miranda-easy.net/mods.php", + UNICODE_AWARE, //doesn't replace anything built-in + MIID_TIPPER +}; + +extern "C" bool WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + hInst = hinstDLL; + DisableThreadLibraryCalls(hInst); + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfoEx; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_TOOLTIPS, MIID_LAST}; + +int ReloadFont(WPARAM wParam, LPARAM lParam) +{ + LOGFONT logFont; + if (hFontTitle) DeleteObject(hFontTitle); + opt.colTitle = CallService(MS_FONT_GETT, (WPARAM)&fontTitle, (LPARAM)&logFont); + hFontTitle = CreateFontIndirect(&logFont); + if (hFontLabels) DeleteObject(hFontLabels); + opt.colLabel = CallService(MS_FONT_GETT, (WPARAM)&fontLabels, (LPARAM)&logFont); + hFontLabels = CreateFontIndirect(&logFont); + if (hFontValues) DeleteObject(hFontValues); + opt.colValue = CallService(MS_FONT_GETT, (WPARAM)&fontValues, (LPARAM)&logFont); + hFontValues = CreateFontIndirect(&logFont); + if (hFontTrayTitle) DeleteObject(hFontTrayTitle); + opt.colTrayTitle = CallService(MS_FONT_GETT, (WPARAM)&fontTrayTitle, (LPARAM)&logFont); + hFontTrayTitle = CreateFontIndirect(&logFont); + + opt.colBg = CallService(MS_COLOUR_GETT, (WPARAM)&colourBg, 0); + opt.colBorder = CallService(MS_COLOUR_GETT, (WPARAM)&colourBorder, 0); + opt.colAvatarBorder = CallService(MS_COLOUR_GETT, (WPARAM)&colourAvatarBorder, 0); + opt.colSidebar = CallService(MS_COLOUR_GETT, (WPARAM)&colourSidebar, 0); + opt.colDivider = CallService(MS_COLOUR_GETT, (WPARAM)&colourDivider, 0); + + return 0; +} + + +// hack to hide tip when clist hides from timeout +int SettingChanged(WPARAM wParam, LPARAM lParam) +{ + DBCONTACTWRITESETTING *dcws = (DBCONTACTWRITESETTING *)lParam; + if (strcmp(dcws->szModule, "CList") != 0 || strcmp(dcws->szSetting, "State") != 0) + return 0; + + // clist hiding + if (dcws->value.type == DBVT_BYTE && dcws->value.bVal == 0) + HideTip(0, 0); + + return 0; +} + +// needed for msg_count_xxx substitutions +int EventDeleted(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if (!CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei)) + { + if (dbei.eventType == EVENTTYPE_MESSAGE) + DBDeleteContactSetting((HANDLE)wParam, MODULE, "LastCountTS"); + } + + return 0; +} + +int ReloadSkinFolder(WPARAM wParam, LPARAM lParam) +{ + FoldersGetCustomPathT(hSkinFolder, SKIN_FOLDER, SIZEOF(SKIN_FOLDER), _T(DEFAULT_SKIN_FOLDER)); + return 0; +} + +void InitFonts() +{ + colourBg.cbSize = sizeof(ColourIDT); + _tcscpy(colourBg.group, LPGENT("Tooltips")); + _tcscpy(colourBg.name, LPGENT("Background")); + strcpy(colourBg.dbSettingsGroup, MODULE); + strcpy(colourBg.setting, "ColourBg"); + colourBg.defcolour = RGB(219, 219, 219); + colourBg.order = 0; + ColourRegisterT(&colourBg); + + colourBorder.cbSize = sizeof(ColourIDT); + _tcscpy(colourBorder.group, LPGENT("Tooltips")); + _tcscpy(colourBorder.name, LPGENT("Border")); + strcpy(colourBorder.dbSettingsGroup, MODULE); + strcpy(colourBorder.setting, "BorderCol"); + colourBorder.defcolour = 0; + colourBorder.order = 0; + ColourRegisterT(&colourBorder); + + colourAvatarBorder.cbSize = sizeof(ColourIDT); + _tcscpy(colourAvatarBorder.group, LPGENT("Tooltips")); + _tcscpy(colourAvatarBorder.name, LPGENT("Avatar border")); + strcpy(colourAvatarBorder.dbSettingsGroup, MODULE); + strcpy(colourAvatarBorder.setting, "AvBorderCol"); + colourAvatarBorder.defcolour = 0; + colourAvatarBorder.order = 0; + ColourRegisterT(&colourAvatarBorder); + + colourDivider.cbSize = sizeof(ColourIDT); + _tcscpy(colourDivider.group, LPGENT("Tooltips")); + _tcscpy(colourDivider.name, LPGENT("Dividers")); + strcpy(colourDivider.dbSettingsGroup, MODULE); + strcpy(colourDivider.setting, "DividerCol"); + colourDivider.defcolour = 0; + colourDivider.order = 0; + ColourRegisterT(&colourDivider); + + colourSidebar.cbSize = sizeof(ColourIDT); + _tcscpy(colourSidebar.group, LPGENT("Tooltips")); + _tcscpy(colourSidebar.name, LPGENT("Sidebar")); + strcpy(colourSidebar.dbSettingsGroup, MODULE); + strcpy(colourSidebar.setting, "SidebarCol"); + colourSidebar.defcolour = RGB(192, 192, 192); + colourSidebar.order = 0; + ColourRegisterT(&colourSidebar); + + fontTitle.cbSize = sizeof(FontIDT); + fontTitle.flags = FIDF_ALLOWEFFECTS; + _tcscpy(fontTitle.group, LPGENT("Tooltips")); + _tcscpy(fontTitle.name, LPGENT("Title")); + strcpy(fontTitle.dbSettingsGroup, MODULE); + strcpy(fontTitle.prefix, "FontFirst"); + _tcscpy(fontTitle.backgroundGroup, LPGENT("Tooltips")); + _tcscpy(fontTitle.backgroundName, LPGENT("Background")); + fontTitle.order = 0; + + fontTitle.deffontsettings.charset = DEFAULT_CHARSET; + fontTitle.deffontsettings.size = -14; + fontTitle.deffontsettings.style = DBFONTF_BOLD; + fontTitle.deffontsettings.colour = RGB(255, 0, 0); + fontTitle.flags |= FIDF_DEFAULTVALID; + + fontLabels.cbSize = sizeof(FontIDT); + fontLabels.flags = FIDF_ALLOWEFFECTS; + _tcscpy(fontLabels.group, LPGENT("Tooltips")); + _tcscpy(fontLabels.name, LPGENT("Labels")); + strcpy(fontLabels.dbSettingsGroup, MODULE); + strcpy(fontLabels.prefix, "FontLabels"); + _tcscpy(fontLabels.backgroundGroup, LPGENT("Tooltips")); + _tcscpy(fontLabels.backgroundName, LPGENT("Background")); + fontLabels.order = 1; + + fontLabels.deffontsettings.charset = DEFAULT_CHARSET; + fontLabels.deffontsettings.size = -12; + fontLabels.deffontsettings.style = DBFONTF_ITALIC; + fontLabels.deffontsettings.colour = RGB(128, 128, 128); + fontLabels.flags |= FIDF_DEFAULTVALID; + + fontValues.cbSize = sizeof(FontIDT); + fontValues.flags = FIDF_ALLOWEFFECTS; + _tcscpy(fontValues.group, LPGENT("Tooltips")); + _tcscpy(fontValues.name, LPGENT("Values")); + strcpy(fontValues.dbSettingsGroup, MODULE); + strcpy(fontValues.prefix, "FontValues"); + _tcscpy(fontValues.backgroundGroup, LPGENT("Tooltips")); + _tcscpy(fontValues.backgroundName, LPGENT("Background")); + fontValues.order = 2; + + fontValues.deffontsettings.charset = DEFAULT_CHARSET; + fontValues.deffontsettings.size = -12; + fontValues.deffontsettings.style = 0; + fontValues.deffontsettings.colour = RGB(0, 0, 0); + fontValues.flags |= FIDF_DEFAULTVALID; + + fontTrayTitle.cbSize = sizeof(FontIDT); + fontTrayTitle.flags = FIDF_ALLOWEFFECTS; + _tcscpy(fontTrayTitle.group, LPGENT("Tooltips")); + _tcscpy(fontTrayTitle.name, LPGENT("Tray title")); + strcpy(fontTrayTitle.dbSettingsGroup, MODULE); + strcpy(fontTrayTitle.prefix, "FontTrayTitle"); + _tcscpy(fontTrayTitle.backgroundGroup, LPGENT("Tooltips")); + _tcscpy(fontTrayTitle.backgroundName, LPGENT("Background")); + fontTrayTitle.order = 0; + + fontTrayTitle.deffontsettings.charset = DEFAULT_CHARSET; + fontTrayTitle.deffontsettings.size = -14; + fontTrayTitle.deffontsettings.style = DBFONTF_BOLD; + fontTrayTitle.deffontsettings.colour = RGB(0, 0, 0); + fontTrayTitle.flags |= FIDF_DEFAULTVALID; + + FontRegisterT(&fontTitle); + FontRegisterT(&fontLabels); + FontRegisterT(&fontValues); + FontRegisterT(&fontTrayTitle); + + hReloadFonts = HookEvent(ME_FONT_RELOAD, ReloadFont); +} + +int ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + InitFonts(); + + hAvChangeEvent = HookEvent(ME_AV_AVATARCHANGED, AvatarChanged); + hShowTipEvent = HookEvent(ME_CLC_SHOWINFOTIP, ShowTipHook); + hHideTipEvent = HookEvent(ME_CLC_HIDEINFOTIP, HideTipHook); + hAckEvent = HookEvent(ME_PROTO_ACK, ProtoAck); + + hFramesSBShow = HookEvent(ME_CLIST_FRAMES_SB_SHOW_TOOLTIP, FramesShowSBTip); + hFramesSBHide = HookEvent(ME_CLIST_FRAMES_SB_HIDE_TOOLTIP, FramesHideSBTip); + + hFolderChanged = HookEvent(ME_FOLDERS_PATH_CHANGED, ReloadSkinFolder); + + hSkinFolder = FoldersRegisterCustomPathT(MODULE, "Tipper skins", MIRANDA_PATHT _T("\\") _T(DEFAULT_SKIN_FOLDER)); + FoldersGetCustomPathT(hSkinFolder, SKIN_FOLDER, SIZEOF(SKIN_FOLDER), _T(DEFAULT_SKIN_FOLDER)); + + InitTipperSmileys(); + LoadOptions(); + ReloadFont(0, 0); + ParseSkinFile(opt.szSkinName, true, false); + + // set 'time-in' + CallService(MS_CLC_SETINFOTIPHOVERTIME, opt.iTimeIn, 0); + + // set Miranda start timestamp + DBWriteContactSettingDword(0, MODULE, "MirandaStartTS", (DWORD)time(0)); + + // get MetaContacts module name + if (ServiceExists(MS_MC_GETPROTOCOLNAME)) + strcpy(szMetaModuleName, (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0)); + + return 0; +} + +int Shutdown(WPARAM wParam, LPARAM lParam) +{ + if (hFramesSBShow) UnhookEvent(hFramesSBShow); + if (hFramesSBHide) UnhookEvent(hFramesSBHide); + if (hAvChangeEvent) UnhookEvent(hAvChangeEvent); + if (hShowTipEvent) UnhookEvent(hShowTipEvent); + if (hHideTipEvent) UnhookEvent(hHideTipEvent); + if (hAckEvent) UnhookEvent(hAckEvent); + + if (hShowTipService) DestroyServiceFunction(hShowTipService); + if (hShowTipWService) DestroyServiceFunction(hShowTipWService); + if (hHideTipService) DestroyServiceFunction(hHideTipService); + + if (hFolderChanged) UnhookEvent(hFolderChanged); + + DeinitMessagePump(); + DestroySkinBitmap(); + + return 0; +} + +HANDLE hEventPreShutdown, hEventModulesLoaded; + +extern "C" int __declspec(dllexport) Load(void) +{ + + + CallService(MS_IMG_GETINTERFACE, FI_IF_VERSION, (LPARAM)&fii); + mir_getTMI(&tmi); + mir_getLP(&pluginInfoEx); + + if (ServiceExists(MS_LANGPACK_GETCODEPAGE)) + iCodePage = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); + + InitTranslations(); + InitMessagePump(); + InitOptions(); + + // for compatibility with mToolTip status tooltips + hShowTipService = CreateServiceFunction("mToolTip/ShowTip", ShowTip); + + hShowTipWService = CreateServiceFunction("mToolTip/ShowTipW", ShowTipW); + + hHideTipService = CreateServiceFunction("mToolTip/HideTip", HideTip); + + hEventPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown); + hEventModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); + + hSettingChangedEvent = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, SettingChanged); + hEventDeleted = HookEvent(ME_DB_EVENT_DELETED, EventDeleted); + + return 0; +} + +extern "C" int __declspec(dllexport) Unload() +{ + UnhookEvent(hSettingChangedEvent); + UnhookEvent(hEventDeleted); + UnhookEvent(hEventPreShutdown); + UnhookEvent(hEventModulesLoaded); + UnhookEvent(hReloadFonts); + + DeinitOptions(); + DeleteObject(hFontTitle); + DeleteObject(hFontLabels); + DeleteObject(hFontValues); + DeleteObject(hFontTrayTitle); + + DeinitTranslations(); + return 0; +} diff --git a/plugins/TipperYM/src/translations.cpp b/plugins/TipperYM/src/translations.cpp new file mode 100644 index 0000000000..1fd6e67c39 --- /dev/null +++ b/plugins/TipperYM/src/translations.cpp @@ -0,0 +1,744 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#include "common.h" +#include "translations.h" +#include "subst.h" +#include "str_utils.h" + +int iTransFuncsCount = 0; +DBVTranslation *translations = 0; + +DWORD dwNextFuncId; +HANDLE hServiceAdd; + + +void AddTranslation(DBVTranslation *newTrans) +{ + iTransFuncsCount++; + + translations = (DBVTranslation *)mir_realloc(translations, sizeof(DBVTranslation) * iTransFuncsCount); + translations[iTransFuncsCount - 1] = *newTrans; + + char *szName = mir_t2a(newTrans->swzName); + char szSetting[256] = "Trans_"; + strcat(szSetting, szName); + + if (_tcscmp(newTrans->swzName, _T("[No translation]")) == 0) + { + translations[iTransFuncsCount - 1].id = 0; + } + else + { + DWORD id = DBGetContactSettingDword(0, MODULE_ITEMS, szSetting, 0); + if (id != 0) + { + translations[iTransFuncsCount - 1].id = id; + if (dwNextFuncId <= id) dwNextFuncId = id + 1; + } + else + { + translations[iTransFuncsCount - 1].id = dwNextFuncId++; + DBWriteContactSettingDword(0, MODULE_ITEMS, szSetting, translations[iTransFuncsCount - 1].id); + } + + DBWriteContactSettingDword(0, MODULE_ITEMS, "NextFuncId", dwNextFuncId); + } + + mir_free(szName); +} + +TCHAR *NullTranslation(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + if (DBGetContactSettingAsString(hContact, szModuleName, szSettingName, buff, bufflen)) + return buff; + return NULL; +} + +TCHAR *TimestampToShortDate(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DWORD ts = DBGetContactSettingDword(hContact, szModuleName, szSettingName, 0); + if (ts == 0) return 0; + + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("d"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + return buff; +} + +TCHAR *TimestampToLongDate(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DWORD ts = DBGetContactSettingDword(hContact, szModuleName, szSettingName, 0); + if (ts == 0) return 0; + + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("D"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + return buff; +} + +TCHAR *TimestampToTime(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DWORD ts = DBGetContactSettingDword(hContact, szModuleName, szSettingName, 0); + if (ts == 0) return 0; + + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("s"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + return buff; +} + +TCHAR *TimestampToTimeNoSecs(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DWORD ts = DBGetContactSettingDword(hContact, szModuleName, szSettingName, 0); + if (ts == 0) return 0; + + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("t"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + return buff; +} + +TCHAR *TimestampToTimeDifference(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DWORD ts = DBGetContactSettingDword(hContact, szModuleName, szSettingName, 0); + DWORD t = (DWORD)time(0); + if (ts == 0) return 0; + + DWORD diff = (ts > t) ? 0 : (t - ts); + int d = (diff / 60 / 60 / 24); + int h = (diff - d * 60 * 60 * 24) / 60 / 60; + int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60; + if (d > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m); + else if (h > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m); + else + mir_sntprintf(buff, bufflen, TranslateT("%dm"), m); + + return buff; +} + +TCHAR *SecondsToTimeDifference(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DWORD diff = DBGetContactSettingDword(hContact, szModuleName, szSettingName, 0); + int d = (diff / 60 / 60 / 24); + int h = (diff - d * 60 * 60 * 24) / 60 / 60; + int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60; + if (d > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m); + else if (h > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m); + else + mir_sntprintf(buff, bufflen, TranslateT("%dm"), m); + + return buff; +} + +TCHAR *WordToStatusDesc(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + WORD wStatus = DBGetContactSettingWord(hContact, szModuleName, szSettingName, ID_STATUS_OFFLINE); + TCHAR *szStatus = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)wStatus, GSMDF_TCHAR); + _tcsncpy(buff,szStatus, bufflen); + buff[bufflen - 1] = 0; + return buff; +} + +TCHAR *ByteToYesNo(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (dbv.type == DBVT_BYTE) + { + if (dbv.bVal != 0) + _tcsncpy(buff, _T("Yes"), bufflen); + else + _tcsncpy(buff, _T("No"), bufflen); + buff[bufflen - 1] = 0; + DBFreeVariant(&dbv); + return buff; + } + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *ByteToGender(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + BYTE val = (BYTE)DBGetContactSettingByte(hContact, szModuleName, szSettingName, 0); + if (val == 'F') + _tcsncpy(buff, TranslateT("Female"), bufflen); + else if (val == 'M') + _tcsncpy(buff, TranslateT("Male"), bufflen); + else + return 0; + + buff[bufflen - 1] = 0; + return buff; +} + +TCHAR *WordToCountry(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + char *szCountryName = 0; + WORD cid = (WORD)DBGetContactSettingWord(hContact, szModuleName, szSettingName, (WORD)-1); + if (cid != (WORD)-1 && ServiceExists(MS_UTILS_GETCOUNTRYBYNUMBER) && (szCountryName = (char *)CallService(MS_UTILS_GETCOUNTRYBYNUMBER, cid, 0)) != 0) + { + if (strcmp(szCountryName, "Unknown") == 0) + return 0; + a2t(szCountryName, buff, bufflen); + buff[bufflen - 1] = 0; + return buff; + } + return 0; +} + +TCHAR *DwordToIp(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + DWORD ip = DBGetContactSettingDword(hContact, szModuleName, szSettingName, 0); + if (ip) { + unsigned char *ipc = (unsigned char*)&ip; + mir_sntprintf(buff, bufflen, _T("%u.%u.%u.%u"), ipc[3], ipc[2], ipc[1], ipc[0]); + return buff; + } + return 0; +} + +bool GetInt(const DBVARIANT &dbv, int *iVal) +{ + if (!iVal) return false; + + switch(dbv.type) + { + case DBVT_BYTE: + if (iVal) *iVal = (int)dbv.bVal; + return true; + case DBVT_WORD: + if (iVal) *iVal = (int)dbv.wVal; + return true; + case DBVT_DWORD: + if (iVal) *iVal = (int)dbv.dVal; + return true; + } + return false; +} + +TCHAR *DayMonthYearToDate(HANDLE hContact, const char *szModuleName, const char *prefix, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + char szSettingName[256]; + mir_snprintf(szSettingName, 256, "%sDay", prefix); + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + int day = 0; + if (GetInt(dbv, &day)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sMonth", prefix); + int month = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &month)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sYear", prefix); + int year = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &year)) + { + DBFreeVariant(&dbv); + + SYSTEMTIME st = {0}; + st.wDay = day; + st.wMonth = month; + st.wYear = year; + + GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, 0, buff, bufflen); + return buff; + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *DayMonthYearToAge(HANDLE hContact, const char *szModuleName, const char *szPrefix, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + char szSettingName[256]; + mir_snprintf(szSettingName, 256, "%sDay", szPrefix); + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + int day = 0; + if (GetInt(dbv, &day)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sMonth", szPrefix); + int month = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &month)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sYear", szPrefix); + int year = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &year)) + { + DBFreeVariant(&dbv); + + SYSTEMTIME now; + GetLocalTime(&now); + + int age = now.wYear - year; + if (now.wMonth < month || (now.wMonth == month && now.wDay < day)) + age--; + mir_sntprintf(buff, bufflen, _T("%d"), age); + return buff; + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *HoursMinutesSecondsToTime(HANDLE hContact, const char *szModuleName, const char *szPrefix, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + char szSettingName[256]; + mir_snprintf(szSettingName, 256, "%sHours", szPrefix); + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + int hours = 0; + if (GetInt(dbv, &hours)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sMinutes", szPrefix); + int minutes = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &minutes)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sSeconds", szPrefix); + int seconds = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + GetInt(dbv, &seconds); + DBFreeVariant(&dbv); + } + + SYSTEMTIME st = {0}; + st.wHour = hours; + st.wMinute = minutes; + st.wSecond = seconds; + + GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, 0, buff, bufflen); + return buff; + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *HoursMinutesToTime(HANDLE hContact, const char *szModuleName, const char *szPrefix, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + char szSettingName[256]; + mir_snprintf(szSettingName, 256, "%sHours", szPrefix); + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + int hours = 0; + if (GetInt(dbv, &hours)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sMinutes", szPrefix); + int minutes = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &minutes)) + { + DBFreeVariant(&dbv); + + SYSTEMTIME st = {0}; + st.wHour = hours; + st.wMinute = minutes; + + GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, 0, buff, bufflen); + return buff; + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *DmyToTimeDifference(HANDLE hContact, const char *szModuleName, const char *szPrefix, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + char szSettingName[256]; + mir_snprintf(szSettingName, 256, "%sDay", szPrefix); + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + int day = 0; + if (GetInt(dbv, &day)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sMonth", szPrefix); + int month = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &month)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sYear", szPrefix); + int year = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &year)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sHours", szPrefix); + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + int hours = 0; + if (GetInt(dbv, &hours)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sMinutes", szPrefix); + int minutes = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &minutes)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sSeconds", szPrefix); + int seconds = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + GetInt(dbv, &seconds); + DBFreeVariant(&dbv); + } + + SYSTEMTIME st = {0}, st_now; + st.wDay = day; + st.wMonth = month; + st.wYear = year; + st.wHour = hours; + st.wMinute = minutes; + st.wSecond = seconds; + GetLocalTime(&st_now); + + FILETIME ft, ft_now; + SystemTimeToFileTime(&st, &ft); + SystemTimeToFileTime(&st_now, &ft_now); + + LARGE_INTEGER li, li_now; + li.HighPart = ft.dwHighDateTime; li.LowPart = ft.dwLowDateTime; + li_now.HighPart = ft_now.dwHighDateTime; li_now.LowPart = ft_now.dwLowDateTime; + + long diff = (long)((li_now.QuadPart - li.QuadPart) / (LONGLONG)10000000L); + int y = diff / 60 / 60 / 24 / 365; + int d = (diff - y * 60 * 60 * 24 * 365) / 60 / 60 / 24; + int h = (diff - y * 60 * 60 * 24 * 365 - d * 60 * 60 * 24) / 60 / 60; + int m = (diff - y * 60 * 60 * 24 * 365 - d * 60 * 60 * 24 - h * 60 * 60) / 60; + if (y != 0) + mir_sntprintf(buff, bufflen, TranslateT("%dy %dd %dh %dm"), y, d, h, m); + else if (d != 0) + mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m); + else if (h != 0) + mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m); + else + mir_sntprintf(buff, bufflen, TranslateT("%dm"), m); + + return buff; + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + } + else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *DayMonthToDaysToNextBirthday(HANDLE hContact, const char *szModuleName, const char *szPrefix, TCHAR *buff, int bufflen) +{ + DBVARIANT dbv; + char szSettingName[256]; + mir_snprintf(szSettingName, 256, "%sDay", szPrefix); + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + int day = 0; + if (GetInt(dbv, &day)) + { + DBFreeVariant(&dbv); + mir_snprintf(szSettingName, 256, "%sMonth", szPrefix); + int month = 0; + if (!DBGetContactSetting(hContact, szModuleName, szSettingName, &dbv)) + { + if (GetInt(dbv, &month)) + { + DBFreeVariant(&dbv); + time_t now = time(NULL); + struct tm *ti = localtime(&now); + int yday_now = ti->tm_yday; + + ti->tm_mday = day; + ti->tm_mon = month - 1; + mktime(ti); + + int yday_birth = ti->tm_yday; + if (yday_birth < yday_now) + { + yday_now -= 365; + yday_now -= (ti->tm_year % 4) ? 0 : 1; + } + + int diff = yday_birth - yday_now; + mir_sntprintf(buff, bufflen, TranslateT("%dd"), diff); + + return buff; + } + else + { + DBFreeVariant(&dbv); + } + } + } + else + { + DBFreeVariant(&dbv); + } + } + return 0; +} + + +TCHAR *EmptyXStatusToDefaultName(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + TCHAR szDefaultName[1024]; + ICQ_CUSTOM_STATUS xstatus = {0}; + DBVARIANT dbv; + + // translate jabber mood + if (ProtoServiceExists(szModuleName, "/SendXML")) // jabber protocol? + { + if (!DBGetContactSettingTString(hContact, szModuleName, szSettingName, &dbv)) + { + _tcsncpy(buff, TranslateTS(dbv.ptszVal), bufflen); + buff[bufflen - 1] = 0; + return buff; + } + } + + if (NullTranslation(hContact, szModuleName, szSettingName, buff, bufflen)) + return buff; + + int status = DBGetContactSettingByte(hContact, szModuleName, "XStatusId", 0); + if (!status) return 0; + + if (ProtoServiceExists(szModuleName, PS_ICQ_GETCUSTOMSTATUSEX)) + { + xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS); + xstatus.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR; + xstatus.ptszName = szDefaultName; + xstatus.wParam = (WPARAM *)&status; + if (CallProtoService(szModuleName, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus)) + return 0; + + _tcsncpy(buff, TranslateTS(szDefaultName), bufflen); + buff[bufflen - 1] = 0; + return buff; + } + + return 0; +} + +TCHAR *TimezoneToTime(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + int timezone = DBGetContactSettingByte(hContact,szModuleName,szSettingName,256); + if (timezone==256 || (char)timezone==-100) + return 0; + + TIME_ZONE_INFORMATION tzi; + FILETIME ft; + LARGE_INTEGER lift; + SYSTEMTIME st; + + timezone=(char)timezone; + GetSystemTimeAsFileTime(&ft); + if (GetTimeZoneInformation(&tzi) == TIME_ZONE_ID_DAYLIGHT) + timezone += tzi.DaylightBias / 30; + + lift.QuadPart = *(__int64*)&ft; + lift.QuadPart -= (__int64)timezone * BIGI(30) * BIGI(60) * BIGI(10000000); + *(__int64*)&ft = lift.QuadPart; + FileTimeToSystemTime(&ft, &st); + GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff, bufflen); + + return buff; +} + +TCHAR *ByteToDay(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + int iDay = DBGetContactSettingWord(hContact, szModuleName, szSettingName, -1); + if (iDay > -1 && iDay < 7) + { + a2t(Translate(days[iDay]), buff, bufflen); + buff[bufflen - 1] = 0; + return buff; + } + + return 0; +} + +TCHAR *ByteToMonth(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + int iMonth = DBGetContactSettingWord(hContact, szModuleName, szSettingName, 0); + if (iMonth > 0 && iMonth < 13) + { + a2t(Translate(months[iMonth - 1]), buff, bufflen); + buff[bufflen - 1] = 0; + return buff; + } + + return 0; +} + +TCHAR *ByteToLanguage(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen) +{ + int iLang = DBGetContactSettingByte(hContact, szModuleName, szSettingName, 0); + if (iLang) + { + for (int i = 0; i < SIZEOF(languages); i++) + { + if (iLang == languages[i].id) + { + a2t(Translate(languages[i].szValue), buff, bufflen); + buff[bufflen - 1] = 0; + return buff; + } + } + } + + return 0; +} + +INT_PTR ServiceAddTranslation(WPARAM wParam, LPARAM lParam) +{ + if (!lParam) return 1; + + DBVTranslation *trans = (DBVTranslation *)lParam; + AddTranslation(trans); + + return 0; +} + +static DBVTranslation internalTranslations[] = +{ + { NullTranslation, _T("[No translation]") }, + { WordToStatusDesc, _T("WORD to status description") }, + { TimestampToTime, _T("DWORD timestamp to time") }, + { TimestampToTimeDifference, _T("DWORD timestamp to time difference") }, + { ByteToYesNo, _T("BYTE to Yes/No") }, + { ByteToGender, _T("BYTE to Male/Female (ICQ)") }, + { WordToCountry, _T("WORD to country name") }, + { DwordToIp, _T("DWORD to ip address") }, + { DayMonthYearToDate, _T("Day|Month|Year to date") }, + { DayMonthYearToAge, _T("Day|Month|Year to age") }, + { HoursMinutesSecondsToTime, _T("Hours|Minutes|Seconds to time") }, + { DmyToTimeDifference, _T("Day|Month|Year|Hours|Minutes|Seconds to time difference") }, + { DayMonthToDaysToNextBirthday, _T("Day|Month to days to next birthday") }, + { TimestampToTimeNoSecs, _T("DWORD timestamp to time (no seconds)") }, + { HoursMinutesToTime, _T("Hours|Minutes to time") }, + { TimestampToShortDate, _T("DWORD timestamp to date (short)") }, + { TimestampToLongDate, _T("DWORD timestamp to date (long)") }, + { EmptyXStatusToDefaultName, _T("xStatus: empty xStatus name to default name") }, + { SecondsToTimeDifference, _T("DWORD seconds to time difference") }, + { TimezoneToTime, _T("BYTE timezone to time") }, + { ByteToDay, _T("WORD to name of a day (0..6, 0 is Sunday)") }, + { ByteToMonth, _T("WORD to name of a month (1..12, 1 is January)") }, + { ByteToLanguage, _T("BYTE to language (ICQ)") }, +}; + +void InitTranslations() +{ + dwNextFuncId = DBGetContactSettingDword(0, MODULE_ITEMS, "NextFuncId", 1); + for (int i = 0; i < SIZEOF(internalTranslations); i++) + AddTranslation( &internalTranslations[i] ); + + hServiceAdd = CreateServiceFunction(MS_TIPPER_ADDTRANSLATION, ServiceAddTranslation); +} + +void DeinitTranslations() +{ + DestroyServiceFunction(hServiceAdd); + mir_free(translations); +} + diff --git a/plugins/TipperYM/src/translations.h b/plugins/TipperYM/src/translations.h new file mode 100644 index 0000000000..985920054e --- /dev/null +++ b/plugins/TipperYM/src/translations.h @@ -0,0 +1,125 @@ +/* +Copyright (C) 2006-2007 Scott Ellis +Copyright (C) 2007-2011 Jan Holub + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + +#ifndef _TRANSLATIONS_INC +#define _TRANSLATIONS_INC + +extern int iTransFuncsCount; +extern DBVTranslation *translations; + +typedef struct { + int id; + char *szValue; +} LISTTYPEDATAITEM; + +static LISTTYPEDATAITEM languages[] = { + {0, LPGEN("None")}, + {55,LPGEN("Afrikaans")}, + {58,LPGEN("Albanian")}, + {1, LPGEN("Arabic")}, + {59,LPGEN("Armenian")}, + {68,LPGEN("Azerbaijani")}, + {72,LPGEN("Belorussian")}, + {2, LPGEN("Bhojpuri")}, + {56,LPGEN("Bosnian")}, + {3, LPGEN("Bulgarian")}, + {4, LPGEN("Burmese")}, + {5, LPGEN("Cantonese")}, + {6, LPGEN("Catalan")}, + {61,LPGEN("Chamorro")}, + {7, LPGEN("Chinese")}, + {8, LPGEN("Croatian")}, + {9, LPGEN("Czech")}, + {10,LPGEN("Danish")}, + {11,LPGEN("Dutch")}, + {12,LPGEN("English")}, + {13,LPGEN("Esperanto")}, + {14,LPGEN("Estonian")}, + {15,LPGEN("Farsi")}, + {16,LPGEN("Finnish")}, + {17,LPGEN("French")}, + {18,LPGEN("Gaelic")}, + {19,LPGEN("German")}, + {20,LPGEN("Greek")}, + {70,LPGEN("Gujarati")}, + {21,LPGEN("Hebrew")}, + {22,LPGEN("Hindi")}, + {23,LPGEN("Hungarian")}, + {24,LPGEN("Icelandic")}, + {25,LPGEN("Indonesian")}, + {26,LPGEN("Italian")}, + {27,LPGEN("Japanese")}, + {28,LPGEN("Khmer")}, + {29,LPGEN("Korean")}, + {69,LPGEN("Kurdish")}, + {30,LPGEN("Lao")}, + {31,LPGEN("Latvian")}, + {32,LPGEN("Lithuanian")}, + {65,LPGEN("Macedonian")}, + {33,LPGEN("Malay")}, + {63,LPGEN("Mandarin")}, + {62,LPGEN("Mongolian")}, + {34,LPGEN("Norwegian")}, + {57,LPGEN("Persian")}, + {35,LPGEN("Polish")}, + {36,LPGEN("Portuguese")}, + {60,LPGEN("Punjabi")}, + {37,LPGEN("Romanian")}, + {38,LPGEN("Russian")}, + {39,LPGEN("Serbo-Croatian")}, + {66,LPGEN("Sindhi")}, + {40,LPGEN("Slovak")}, + {41,LPGEN("Slovenian")}, + {42,LPGEN("Somali")}, + {43,LPGEN("Spanish")}, + {44,LPGEN("Swahili")}, + {45,LPGEN("Swedish")}, + {46,LPGEN("Tagalog")}, + {64,LPGEN("Taiwanese")}, + {71,LPGEN("Tamil")}, + {47,LPGEN("Tatar")}, + {48,LPGEN("Thai")}, + {49,LPGEN("Turkish")}, + {50,LPGEN("Ukrainian")}, + {51,LPGEN("Urdu")}, + {52,LPGEN("Vietnamese")}, + {67,LPGEN("Welsh")}, + {53,LPGEN("Yiddish")}, + {54,LPGEN("Yoruba")}, +}; + +static char *days[7] = { + LPGEN("Sunday"), LPGEN("Monday"), LPGEN("Tuesday"), LPGEN("Wednesday"), LPGEN("Thursday"), LPGEN("Friday"), LPGEN("Saturday") +}; + +static char *months[12] = { + LPGEN("January"), LPGEN("February"), LPGEN("March"), LPGEN("April"), LPGEN("May"), LPGEN("June"), + LPGEN("July"), LPGEN("August"), LPGEN("September"), LPGEN("October"), LPGEN("November"), LPGEN("December") +}; + +void InitTranslations(); +void DeinitTranslations(); + +TCHAR *TimestampToTimeDifference(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen); +TCHAR *EmptyXStatusToDefaultName(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen); +TCHAR *WordToStatusDesc(HANDLE hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen); + + +#endif diff --git a/plugins/TipperYM/src/version.h b/plugins/TipperYM/src/version.h new file mode 100644 index 0000000000..c71b187bc0 --- /dev/null +++ b/plugins/TipperYM/src/version.h @@ -0,0 +1,4 @@ +#define __FILEVERSION_STRING 2,1,0,4 +#define __VERSION_STRING "2.1.0.4" +#define __VERSION_DWORD PLUGIN_MAKE_VERSION(2, 1, 0, 4) + -- cgit v1.2.3