summaryrefslogtreecommitdiff
path: root/plugins/TipperYM/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/TipperYM/src')
-rw-r--r--plugins/TipperYM/src/bitmap_func.cpp776
-rw-r--r--plugins/TipperYM/src/bitmap_func.h71
-rw-r--r--plugins/TipperYM/src/common.h105
-rw-r--r--plugins/TipperYM/src/message_pump.cpp413
-rw-r--r--plugins/TipperYM/src/message_pump.h71
-rw-r--r--plugins/TipperYM/src/mir_smileys.cpp514
-rw-r--r--plugins/TipperYM/src/mir_smileys.h70
-rw-r--r--plugins/TipperYM/src/options.cpp2495
-rw-r--r--plugins/TipperYM/src/options.h196
-rw-r--r--plugins/TipperYM/src/popwin.cpp2016
-rw-r--r--plugins/TipperYM/src/popwin.h140
-rw-r--r--plugins/TipperYM/src/preset_items.cpp131
-rw-r--r--plugins/TipperYM/src/preset_items.h57
-rw-r--r--plugins/TipperYM/src/resource.h137
-rw-r--r--plugins/TipperYM/src/skin_parser.cpp417
-rw-r--r--plugins/TipperYM/src/skin_parser.h30
-rw-r--r--plugins/TipperYM/src/str_utils.cpp231
-rw-r--r--plugins/TipperYM/src/str_utils.h66
-rw-r--r--plugins/TipperYM/src/subst.cpp1011
-rw-r--r--plugins/TipperYM/src/subst.h47
-rw-r--r--plugins/TipperYM/src/tipper.cpp362
-rw-r--r--plugins/TipperYM/src/translations.cpp744
-rw-r--r--plugins/TipperYM/src/translations.h125
-rw-r--r--plugins/TipperYM/src/version.h4
24 files changed, 10229 insertions, 0 deletions
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 <m_stdhdr.h>
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+#include <commctrl.h>
+#include <stddef.h>
+#include <time.h>
+#include <windowsx.h>
+
+#include <win2k.h>
+#include <newpluginapi.h>
+#include <statusmodes.h>
+#include <m_avatars.h>
+#include <m_awaymsg.h>
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include <m_cluiframes.h>
+#include <m_contacts.h>
+#include <m_database.h>
+#include <m_fontservice.h>
+#include <m_icolib.h>
+#include <m_idle.h>
+#include <m_imgsrvc.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_skin.h>
+#include <m_system.h>
+#include <m_timezones.h>
+#include <m_utils.h>
+#include <m_icq.h>
+
+#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("<No Label>");
+ }
+ 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("<No Label>: "));
+ }
+
+ if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0])
+ _tcscat(pchData, pwd->rows[i].swzValue);
+ else
+ _tcscat(pchData, TranslateT("<No Value>"));
+
+ _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 = (h<v) ? h : v;
+ }
+ else
+ {
+ h = 0;
+ }
+
+ hRgn = CreateRoundRectRgn(r.left,r.top,r.right + 1,r.bottom + 1, h, h);
+ SetWindowRgn(hwnd, hRgn, FALSE);
+
+ if (opt.showEffect == PSE_ANIMATE && pwd->iAnimStep == 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("<b>"));
+
+ 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("<prefix>Day|Month|Year to date") },
+ { DayMonthYearToAge, _T("<prefix>Day|Month|Year to age") },
+ { HoursMinutesSecondsToTime, _T("<prefix>Hours|Minutes|Seconds to time") },
+ { DmyToTimeDifference, _T("<prefix>Day|Month|Year|Hours|Minutes|Seconds to time difference") },
+ { DayMonthToDaysToNextBirthday, _T("<prefix>Day|Month to days to next birthday") },
+ { TimestampToTimeNoSecs, _T("DWORD timestamp to time (no seconds)") },
+ { HoursMinutesToTime, _T("<prefix>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)
+