diff options
| author | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-07-18 07:52:13 +0000 | 
|---|---|---|
| committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-07-18 07:52:13 +0000 | 
| commit | 70d04c9b21955c34070ee466693403e2b00870e1 (patch) | |
| tree | a891633004c655fbc3448803cffa0d62855409d0 /plugins/FloatingContacts/src | |
| parent | 2b556a0908dfa1c12400ec9ac22a00b39bc17136 (diff) | |
FirstRun, FlashAvatars, FloatingContacts: changed folder structure 
git-svn-id: http://svn.miranda-ng.org/main/trunk@1008 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/FloatingContacts/src')
| -rw-r--r-- | plugins/FloatingContacts/src/bitmap_funcs.cpp | 1234 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/bitmap_funcs.h | 127 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/filedrop.cpp | 368 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/filedrop.h | 26 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/fltcont.h | 191 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/main.cpp | 1268 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/options.cpp | 1171 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/resource.h | 75 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/stdhdr.h | 64 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/thumbs.cpp | 1013 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/thumbs.h | 74 | ||||
| -rw-r--r-- | plugins/FloatingContacts/src/version.h | 23 | 
12 files changed, 5634 insertions, 0 deletions
| diff --git a/plugins/FloatingContacts/src/bitmap_funcs.cpp b/plugins/FloatingContacts/src/bitmap_funcs.cpp new file mode 100644 index 0000000000..334bf98abe --- /dev/null +++ b/plugins/FloatingContacts/src/bitmap_funcs.cpp @@ -0,0 +1,1234 @@ +/*
 +Popup Plus plugin for Miranda IM
 +
 +Copyright	© 2002 Luca Santarelli,
 +			© 2004-2007 Victor Pavlychko
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program; if not, write to the Free Software
 +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 +*/
 +
 +#include "stdhdr.h"
 +#include "bitmap_funcs.h"
 +
 +#include <m_png.h>
 +#include <math.h>
 +
 +#define PU_FONT_THRESHOLD				96
 +#define PU_BMP_ACCURATE_ARITHMETICS
 +
 +#ifdef PU_BMP_ACCURATE_ARITHMETICS
 +	#define	PU_DIV255(x)	((x)/255)
 +	#define	PU_DIV128(x)	((x)/128)
 +	typedef float pu_koef;
 +#else
 +	#define	PU_DIV255(x)	((x)>>8)
 +	#define	PU_DIV128(x)	((x)>>7)
 +	typedef long pu_koef;
 +#endif
 +
 +MyBitmap::MyBitmap()
 +{
 +	dcBmp = 0;
 +	hBmp = 0;
 +	bits = 0;
 +	width = height = 0;
 +	bitsSave = 0;
 +}
 +
 +MyBitmap::MyBitmap(int w, int h)
 +{
 +	dcBmp = 0;
 +	hBmp = 0;
 +	bits = 0;
 +	width = height = 0;
 +	bitsSave = 0;
 +	allocate(w,h);
 +}
 +
 +MyBitmap::MyBitmap(const char *fn, const char *fnAlpha)
 +{
 +	dcBmp = 0;
 +	hBmp = 0;
 +	bits = 0;
 +	width = height = 0;
 +	bitsSave = 0;
 +	loadFromFile(fn, fnAlpha);
 +}
 +
 +MyBitmap::~MyBitmap()
 +{
 +	if (bitsSave)
 +		delete [] bitsSave;
 +	free();
 +}
 +
 +void MyBitmap::setAlpha(BYTE level)
 +{
 +	if (!bits) return;
 +
 +	GdiFlush();
 +	for (int i = 0; i < width*height; i++)
 +	{
 +		if (bits[i] & 0xff000000)
 +		{
 +			bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, geta(bits[i])*level/255);
 +		} else
 +		{
 +			bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, level);
 +		}
 +	}
 +}
 +
 +void MyBitmap::setAlphaRect(int x1, int y1, int x2, int y2, BYTE level)
 +{
 +	if (!bits) return;
 +
 +	GdiFlush();
 +	for (int i = y1; i < y2; i++)
 +		for (int j = x1; j < x2; j++) {
 +			int idx = i * width + j;
 +			if (bits[idx] & 0xff000000)
 +				bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, geta(bits[idx])*level/255);
 +			else
 +				bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, level);
 +		}
 +}
 +
 +void MyBitmap::makeOpaque()
 +{
 +	if (!bits) return;
 +
 +	GdiFlush();
 +	for (int i = 0; i < width*height; i++)
 +		bits[i] |= 0xff000000;
 +}
 +
 +void MyBitmap::makeOpaqueRect(int x1, int y1, int x2, int y2)
 +{
 +	if (!bits) return;
 +
 +	GdiFlush();
 +	for (int i = y1; i < y2; i++)
 +		for (int j = x1; j < x2; j++) {
 +			int idx = i * width + j;
 +			bits[idx] |= 0xff000000;
 +		}
 +}
 +
 +void MyBitmap::saveAlpha(int x, int y, int w, int h)
 +{
 +	if (bitsSave)
 +		delete [] bitsSave;
 +
 +	GdiFlush();
 +
 +	if (!w) w = width;
 +	if (!h) h = height;
 +
 +	bitsSave = new COLOR32[w*h];
 +	COLOR32 *p1 = bitsSave;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		COLOR32 *p2 = bits + (y+i)*width + x;
 +		p1 = bitsSave + i*w;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			*p1++=*p2++;
 +		}
 +	}
 +}
 +
 +void MyBitmap::restoreAlpha(int x, int y, int w, int h)
 +{
 +	if (!bitsSave)
 +		return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = width;
 +	if (!h) h = height;
 +
 +	COLOR32 *p1 = bitsSave;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		COLOR32 *p2 = bits + (y+i)*width + x;
 +		p1 = bitsSave + i*w;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			if ((*p1&0x00ffffff) != (*p2&0x00ffffff))
 +			{
 +				*p2 |= 0xff000000;
 +			} else
 +			{
 +				*p2 = (*p2&0x00ffffff) | (*p1&0xff000000);
 +			}
 +			++p1;
 +			++p2;
 +		}
 +	}
 +
 +	delete [] bitsSave;
 +	bitsSave = 0;
 +}
 +
 +void MyBitmap::DrawBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h)
 +{
 +	if (!(bits && inbits)) return;
 +
 +	GdiFlush();
 +
 +	float kx = (float)inw / w;
 +	float ky = (float)inh / h;
 +
 +	if (x+w >= this->getWidth())
 +		w = this->getWidth() - x;
 +	if (y+h >= this->getHeight())
 +		h = this->getHeight() - y;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			bits[(i+y)*width + (j+x)] = inbits[int(i*ky)*inw + int(j*kx)];
 +		}
 +	}
 +}
 +
 +void MyBitmap::BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h)
 +{
 +	if (!(bits && inbits)) return;
 +
 +	GdiFlush();
 +
 +	float kx = (float)inw / w;
 +	float ky = (float)inh / h;
 +
 +	if (x+w >= this->getWidth())
 +		w = this->getWidth() - x;
 +	if (y+h >= this->getHeight())
 +		h = this->getHeight() - y;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			COLOR32 src = inbits[int(i*ky)*inw + int(j*kx)];
 +			COLOR32 dst = bits[(i+y)*width + (j+x)];
 +			long alpha = geta(src);
 +			bits[(i+y)*width + (j+x)] = rgba(
 +					getr(src)+PU_DIV255((255-alpha)*getr(dst)),
 +					getg(src)+PU_DIV255((255-alpha)*getg(dst)),
 +					getb(src)+PU_DIV255((255-alpha)*getb(dst)),
 +					geta(src)+PU_DIV255((255-alpha)*geta(dst))
 +				);
 +		}
 +	}
 +}
 +
 +void MyBitmap::Blend(MyBitmap *bmp, int x, int y, int w, int h)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = bmp->width;
 +	if (!h) h = bmp->height;
 +	float kx = (float)bmp->width / w;
 +	float ky = (float)bmp->height / h;
 +
 +	if (x+w >= this->getWidth())
 +		w = this->getWidth() - x;
 +	if (y+h >= this->getHeight())
 +		h = this->getHeight() - y;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			COLOR32 src = bmp->bits[int(i*ky)*bmp->width + int(j*kx)];
 +			COLOR32 dst = bits[(i+y)*width + (j+x)];
 +			long alpha = geta(src);
 +			bits[(i+y)*width + (j+x)] = rgba(
 +					getr(src)+PU_DIV255((255-alpha)*getr(dst)),
 +					getg(src)+PU_DIV255((255-alpha)*getg(dst)),
 +					getb(src)+PU_DIV255((255-alpha)*getb(dst)),
 +					geta(src)+PU_DIV255((255-alpha)*geta(dst))
 +				);
 +		}
 +	}
 +}
 +
 +void MyBitmap::Draw(MyBitmap *bmp, int x, int y, int w, int h)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = bmp->width;
 +	if (!h) h = bmp->height;
 +
 +	if (!x && !y && (w == width) && (h == height) && (w == bmp->width) && (h == bmp->height))
 +	{
 +		// fast bitmap copy is possible good for animated avatars
 +		CopyMemory(bits, bmp->bits, width*height*sizeof(COLOR32));
 +		return;
 +	}
 +
 +	float kx = (float)bmp->width / w;
 +	float ky = (float)bmp->height / h;
 +
 +	if (x+w >= this->getWidth())
 +		w = this->getWidth() - x;
 +	if (y+h >= this->getHeight())
 +		h = this->getHeight() - y;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			bits[(i+y)*width + (j+x)] = bmp->bits[int(i*ky)*bmp->width + int(j*kx)];
 +		}
 +	}
 +}
 +
 +void MyBitmap::BlendColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = bmp->width;
 +	if (!h) h = bmp->height;
 +	float kx = (float)bmp->width / w;
 +	float ky = (float)bmp->height / h;
 +
 +	// we should swap B and R channels when working with win32 COLORREF
 +	float koef1r = (255 - getb(color)) / 128.0f;
 +	float koef1g = (255 - getg(color)) / 128.0f;
 +	float koef1b = (255 - getr(color)) / 128.0f;
 +
 +	int br = - 255 + 2 * getb(color);
 +	int bg = - 255 + 2 * getg(color);
 +	int bb = - 255 + 2 * getr(color);
 +
 +	float koef2r = (getb(color)) / 128.0f;
 +	float koef2g = (getg(color)) / 128.0f;
 +	float koef2b = (getr(color)) / 128.0f;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +
 +//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +//			bits[(i+y)*width + (j+x)] = (cl > 128) ?
 +//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])):
 +//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]));
 +
 +			long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +			COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0;
 +#pragma warning(push)
 +#pragma warning(disable: 4244)
 +			COLOR32 src = (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);
 +#pragma warning(pop) 
 +//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +//			COLOR32 src = (cl > 128) ?
 +//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha):
 +//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha);
 +			COLOR32 dst = bits[(i+y)*width + (j+x)];
 +//			long alpha = geta(src);
 +			bits[(i+y)*width + (j+x)] = rgba(
 +					getr(src)+PU_DIV255((255-alpha)*getr(dst)),
 +					getg(src)+PU_DIV255((255-alpha)*getg(dst)),
 +					getb(src)+PU_DIV255((255-alpha)*getb(dst)),
 +					geta(src)+PU_DIV255((255-alpha)*geta(dst))
 +				);
 +
 +		}
 +	}
 +}
 +
 +void MyBitmap::DrawColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = bmp->width;
 +	if (!h) h = bmp->height;
 +	float kx = (float)bmp->width / w;
 +	float ky = (float)bmp->height / h;
 +
 +	// we should swap B and R channels when working with win32 COLORREF
 +	float koef1r = (255 - getb(color)) / 128.0f;
 +	float koef1g = (255 - getg(color)) / 128.0f;
 +	float koef1b = (255 - getr(color)) / 128.0f;
 +
 +	int br = - 255 + 2 * getb(color);
 +	int bg = - 255 + 2 * getg(color);
 +	int bb = - 255 + 2 * getr(color);
 +
 +	float koef2r = (getb(color)) / 128.0f;
 +	float koef2g = (getg(color)) / 128.0f;
 +	float koef2b = (getr(color)) / 128.0f;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +
 +			long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +			COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0;
 +#pragma warning(push)
 +#pragma warning(disable: 4244)
 +			bits[(i+y)*width + (j+x)] = (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);
 +#pragma warning(pop) 
 +//			bits[(i+y)*width + (j+x)] = (cl > 128) ?
 +//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])):
 +//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]));
 +		}
 +	}
 +}
 +
 +void MyBitmap::BlendPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +	if (!win || !hin) return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = win;
 +	if (!h) h = hin;
 +	float kx = (float)win / w;
 +	float ky = (float)hin / h;
 +
 +	if (x+w >= this->getWidth())
 +		w = this->getWidth() - x;
 +	if (y+h >= this->getHeight())
 +		h = this->getHeight() - y;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
 +			COLOR32 dst = bits[(i+y)*width + (j+x)];
 +			long alpha = geta(src);
 +			bits[(i+y)*width + (j+x)] = rgba(
 +					getr(src)+PU_DIV255((255-alpha)*getr(dst)),
 +					getg(src)+PU_DIV255((255-alpha)*getg(dst)),
 +					getb(src)+PU_DIV255((255-alpha)*getb(dst)),
 +					geta(src)+PU_DIV255((255-alpha)*geta(dst))
 +				);
 +//			bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
 +		}
 +	}
 +}
 +
 +void MyBitmap::BlendPartColorized(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +	if (!win || !hin) return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = win;
 +	if (!h) h = hin;
 +	float kx = (float)win / w;
 +	float ky = (float)hin / h;
 +
 +	if (x+w >= this->getWidth())
 +		w = this->getWidth() - x;
 +	if (y+h >= this->getHeight())
 +		h = this->getHeight() - y;
 +
 +	// we should swap B and R channels when working with win32 COLORREF
 +	float koef1r = (255 - getb(color)) / 128.0f;
 +	float koef1g = (255 - getg(color)) / 128.0f;
 +	float koef1b = (255 - getr(color)) / 128.0f;
 +
 +	int br = - 255 + 2 * getb(color);
 +	int bg = - 255 + 2 * getg(color);
 +	int bb = - 255 + 2 * getr(color);
 +
 +	float koef2r = (getb(color)) / 128.0f;
 +	float koef2g = (getg(color)) / 128.0f;
 +	float koef2b = (getr(color)) / 128.0f;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +
 +			long alpha = geta(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]);
 +//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +			COLOR32 cl = alpha ? getr(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)])*255/alpha : 0;
 +#pragma warning(push)
 +#pragma warning(disable: 4244)
 +			COLOR32 src = (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);
 +#pragma warning(pop) 
 +//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
 +//			COLOR32 src = (cl > 128) ?
 +//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha):
 +//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha);
 +			COLOR32 dst = bits[(i+y)*width + (j+x)];
 +//			long alpha = geta(src);
 +			bits[(i+y)*width + (j+x)] = rgba(
 +					getr(src)+PU_DIV255((255-alpha)*getr(dst)),
 +					getg(src)+PU_DIV255((255-alpha)*getg(dst)),
 +					getb(src)+PU_DIV255((255-alpha)*getb(dst)),
 +					geta(src)+PU_DIV255((255-alpha)*geta(dst))
 +				);
 +
 +/*			COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
 +			COLOR32 dst = bits[(i+y)*width + (j+x)];
 +			long alpha = geta(src);
 +			bits[(i+y)*width + (j+x)] = rgba(
 +					getr(src)+(255-alpha)*getr(dst)/255,
 +					getg(src)+(255-alpha)*getg(dst)/255,
 +					getb(src)+(255-alpha)*getb(dst)/255,
 +					geta(src)+(255-alpha)*geta(dst)/255
 +				);*/
 +//			bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
 +		}
 +	}
 +}
 +
 +void MyBitmap::DrawPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +	if (!win || !hin) return;
 +
 +	GdiFlush();
 +
 +	if (!w) w = win;
 +	if (!h) h = hin;
 +	float kx = (float)win / w;
 +	float ky = (float)hin / h;
 +
 +	if (x+w >= this->getWidth())
 +		w = this->getWidth() - x;
 +	if (y+h >= this->getHeight())
 +		h = this->getHeight() - y;
 +
 +	for (int i = 0; i < h; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < w; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
 +		}
 +	}
 +}
 +
 +void MyBitmap::DrawNoAlpha(MyBitmap *bmp, int x, int y, int w, int h)
 +{
 +	if (!(bits && bmp && bmp->bits)) return;
 +
 +	GdiFlush();
 +
 +	for (int i = 0; i < bmp->height; i++)
 +	{
 +		if (i+y < 0) continue;
 +		if (i+y >= height) break;
 +		for (int j = 0; j < bmp->width; j++)
 +		{
 +			if (j+x < 0) continue;
 +			if (j+x >= width) break;
 +			bits[(i+y)*width + (j+x)] = bmp->bits[i*bmp->width + j];
 +		}
 +	}
 +}
 +
 +static __forceinline int ReadP(long *p, int w, int h, int x, int y, int k)
 +{
 +	if (x<0) x = 0; else if (x>=w) x = w-1;
 +	if (y<0) y = 0; else if (y>=h) y = h-1;
 +	return p[(x+y*w)*4+k];
 +}
 +
 +void MyBitmap::Blur(int w, int h)
 +{
 +	if ((w <= 0) || (h <= 0)) return;
 +
 +	BYTE *buf_src = new BYTE[width*height*4];
 +	long *buf_tmp = new long[width*height*4];
 +	BYTE *buf_dst = (BYTE *)bits;
 +	memcpy(buf_src, buf_dst, width*height*4);
 +
 +	BYTE *src, *dst;
 +	long *tmp;
 +
 +	src = buf_src;
 +	tmp = buf_tmp;
 +	dst = buf_dst;
 +
 +	int y;
 +
 +	for (y = 0; y < height; ++y)
 +	{
 +		for (int x = 0; x < width; ++x)
 +		{
 +			for (int k = 0; k < 4; ++k)
 +			{
 +				int tot = src[0];
 +				if (x > 0) tot += tmp[-4];
 +				if (y > 0) tot += tmp[-width*4];
 +				if (x > 0 && y > 0) tot -= tmp[-(width+1)*4];
 +				*tmp = tot;
 +
 +				++src;
 +				++tmp;
 +			}
 +		}
 +	}
 +
 +	src = buf_src;
 +	tmp = buf_tmp;
 +	dst = buf_dst;
 +
 +	float mul = 1.f/((w*2+1)*(h*2+1));
 +	for (y = 0;y<height;y++)
 +	{
 +		for (int x = 0;x<width;x++)
 +		{
 +			for (int k = 0; k < 4; ++k)
 +			{
 +				int tot = ReadP(tmp,width,height,x+w,y+h,k) +
 +				          ReadP(tmp,width,height,x-w,y-h,k) -
 +				          ReadP(tmp,width,height,x-w,y+h,k) -
 +				          ReadP(tmp,width,height,x+w,y-h,k);
 +
 +				*dst = BYTE(tot*mul);
 +
 +				++dst;
 +				++src;
 +			}
 +		}
 +	}
 +
 +	delete [] buf_src;
 +	delete [] buf_tmp;
 +}
 +
 +void MyBitmap::IncreaseAlpha(float q)
 +{
 +	BYTE *p = (BYTE *)bits;
 +
 +	for (int i = 0; i < height; ++i)
 +	{
 +		for (int j = 0; j < width; ++j)
 +		{
 +			if (!p[3])
 +			{
 +				p += 4;
 +				continue;
 +			}
 +
 +			float q1 = min(q, 255.f/p[3]);
 +
 +			for (int k = 0; k < 4; ++k)
 +			{
 +				*p = (BYTE)min(255, *p * q1);
 +				++p;
 +			}
 +		}
 +	}
 +}
 +
 +void MyBitmap::DrawIcon(HICON hic, int x, int y, int w, int h)
 +{
 +	GdiFlush();
 +
 +	ICONINFO info;
 +	GetIconInfo(hic, &info);
 +
 +	BITMAP bmpColor, bmpMask;
 +	GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
 +	GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);
 +
 +	if (!w) w = abs(bmpMask.bmWidth);
 +	if (!h) h = abs(bmpMask.bmHeight);
 +
 +	if (bmpColor.bmBitsPixel == 32)
 +	{
 +		if ((w != abs(bmpMask.bmWidth)) || (h != abs(bmpMask.bmHeight)))
 +		{
 +			DeleteObject(info.hbmColor);
 +			DeleteObject(info.hbmMask);
 +			HICON hicTmp = (HICON)CopyImage(hic,IMAGE_ICON,w,h,LR_COPYFROMRESOURCE);
 +			GetIconInfo(hicTmp, &info);
 +			GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
 +			GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);
 +			DestroyIcon(hicTmp);
 +		}
 +
 +		BYTE *cbit = new BYTE[bmpColor.bmWidthBytes*bmpColor.bmHeight];
 +		BYTE *mbit = new BYTE[bmpMask.bmWidthBytes*bmpMask.bmHeight];
 +		GetBitmapBits(info.hbmColor, bmpColor.bmWidthBytes*bmpColor.bmHeight, cbit);
 +		GetBitmapBits(info.hbmMask, bmpMask.bmWidthBytes*bmpMask.bmHeight, mbit);
 +
 +		for (int i = 0; i < bmpColor.bmHeight; i++)
 +		{
 +			for (int j = 0; j < bmpColor.bmWidth; j++)
 +			{
 +				BYTE *pixel = cbit + i*bmpColor.bmWidthBytes + j*4;
 +				if (!pixel[3])
 +				{
 +					pixel[3] = (*(mbit + i*bmpMask.bmWidthBytes + j*bmpMask.bmBitsPixel/8) & (1<<(7-j%8))) ? 0 : 255;
 +				}
 +
 +				if (pixel[3] != 255)
 +				{
 +					pixel[0] = PU_DIV255(pixel[0] * pixel[3]);
 +					pixel[1] = PU_DIV255(pixel[1] * pixel[3]);
 +					pixel[2] = PU_DIV255(pixel[2] * pixel[3]);
 +				}
 +			}
 +		}
 +
 +		this->BlendBits((COLOR32 *)cbit, bmpColor.bmWidth, bmpColor.bmHeight, x, y, w, h);
 +
 +		delete [] mbit;
 +		delete [] cbit;
 +	} else
 +	{
 +		this->saveAlpha(x,y,w,h);
 +		DrawIconEx(this->getDC(), x, y, hic, w, h, 0, NULL, DI_NORMAL);
 +		this->restoreAlpha(x,y,w,h);
 +	}
 +
 +	DeleteObject(info.hbmColor);
 +	DeleteObject(info.hbmMask);
 +}
 +
 +//Base on code by Artem Shpynov
 +//from clist_modern plugin
 +//slightly modified and integrated to MyBitmap class 
 +void MyBitmap::DrawText(TCHAR *str, int x, int y, int blur, int strength)
 +{
 +	SIZE sz; GetTextExtentPoint32(this->getDC(), str, lstrlen(str), &sz);
 +	sz.cx += (blur+2)*2; sz.cy += (blur+2)*2;
 +	x -= blur+2; y -= blur+2;
 +
 +	static BYTE             pbGammaWeight[256] = {0};
 +	static BOOL             bGammaWeightFilled = FALSE;
 +
 +	if (!bGammaWeightFilled)
 +	{
 +		int i;
 +		for(i = 0;i<256;i++)
 +		{
 +			double f;
 +			double gamma = (double)700/1000;
 +
 +			f = (double)i/255;
 +			f = pow(f,(1/gamma));
 +
 +			pbGammaWeight[i] = (BYTE)(255*f);
 +		}
 +		bGammaWeightFilled = 1;
 +	}
 +
 +	MyBitmap tmp(sz.cx, sz.cy);
 +	HFONT hfnTmp = (HFONT)SelectObject(tmp.getDC(), GetCurrentObject(this->getDC(), OBJ_FONT));
 +
 +	RECT rc; SetRect(&rc, 0, 0, sz.cx, sz.cy);
 +	SetTextColor(tmp.getDC(), RGB(255,255,255));
 +	SetBkColor(tmp.getDC(), RGB(0,0,0));
 +	ExtTextOutA(tmp.getDC(), 0, 0, ETO_OPAQUE, &rc, "", 0, NULL);
 +	::DrawText(tmp.getDC(), str, lstrlen(str), &rc, DT_CENTER|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER);
 +	SelectObject(tmp.getDC(), hfnTmp);
 +
 +	GdiFlush();
 +
 +	if (blur)
 +	{
 +		for (int i = 0; i < sz.cy; i++)
 +		{
 +			COLOR32 *row_src = tmp.bits + i * tmp.width;
 +
 +			for (int j = 0; j < sz.cx; j++)
 +			{
 +				COLOR32 cl = row_src[j];
 +				if (!cl) continue;
 +
 +				int a1 = (getr(cl) + getg(cl) + getb(cl)) / 3;
 +				row_src[j] = rgba(a1, a1, a1, a1);
 +			}
 +		}
 +		tmp.Blur(blur, blur);
 +		tmp.IncreaseAlpha((float)(strength ? strength : blur));
 +	}
 +
 +	// use Get*Value for COLORREF and get* for COLOR32
 +	COLOR32 textColor = GetTextColor(this->getDC());
 +	COLOR32 r = GetRValue(textColor);
 +	COLOR32 g = GetGValue(textColor);
 +	COLOR32 b = GetBValue(textColor);
 +
 +	int minx = max(0,-x);
 +	int miny = max(0,-y);
 +	int maxx = min(sz.cx, width-x);
 +	int maxy = min(sz.cy, height-y);
 +
 +	for (int i = miny; i < maxy; i++)
 +	{
 +		COLOR32 *row_dst = bits + (i+y) * width + x;
 +		COLOR32 *row_src = tmp.bits + i * tmp.width;
 +
 +		for (int j = minx; j < maxx; j++)
 +		{
 +			COLOR32 bx,rx,gx,mx;
 +			{
 +				bx = pbGammaWeight[getb(row_src[j])];
 +				gx = pbGammaWeight[getg(row_src[j])];
 +				rx = pbGammaWeight[getr(row_src[j])];
 +			}
 +
 +			bx = (pbGammaWeight[bx]*(255-b)+bx*(b))/255;
 +			gx = (pbGammaWeight[gx]*(255-g)+gx*(g))/255;
 +			rx = (pbGammaWeight[rx]*(255-r)+rx*(r))/255;
 +
 +			mx = (BYTE)(max(max(bx,rx),gx));
 +
 +			if (1) 
 +			{
 +				bx = (bx<mx)?(BYTE)(((WORD)bx*7+(WORD)mx)>>3):bx;
 +				rx = (rx<mx)?(BYTE)(((WORD)rx*7+(WORD)mx)>>3):rx;
 +				gx = (gx<mx)?(BYTE)(((WORD)gx*7+(WORD)mx)>>3):gx;
 +				// reduce boldeness at white fonts
 +			}
 +			COLOR32 cl = row_dst[j];
 +			if (mx)                                      
 +			{
 +				COLOR32 rrx,grx,brx;
 +				COLOR32 rlx,glx,blx;
 +				COLOR32 axx = geta(cl);
 +				COLOR32 mmx = (bx+gx+rx)/3;
 +				COLOR32 nx = mmx;;//pbGammaWeight[mx];//
 +				{
 +					//Normalize components	to alpha level
 +					bx = (nx*(255-axx)+bx*axx)/255;
 +					gx = (nx*(255-axx)+gx*axx)/255;
 +					rx = (nx*(255-axx)+rx*axx)/255;
 +					mx = (nx*(255-axx)+mmx*axx)/255;
 +				}
 +				{
 +					blx = getb(cl);
 +					glx = getg(cl);
 +					rlx = getr(cl);
 +
 +					brx = (b-blx)*bx/255;
 +					grx = (g-glx)*gx/255;
 +					rrx = (r-rlx)*rx/255;
 +					row_dst[j] = rgba(rlx+rrx, glx+grx, blx+brx, mx+(255-mx)*axx/255);
 +				}
 +			}
 +		}
 +	}
 +}
 +
 +// based on code by Yuriy Zaporozhets from:
 +// http://www.codeproject.com/gdi/coolrgn.asp?df = 100&forumid = 739&exp = 0&select = 6341
 +// slightly modified to integrate with MyBitmap class.
 +HRGN MyBitmap::buildOpaqueRgn(int level, bool opaque)
 +{
 +	GdiFlush();
 +
 +	const int addRectsCount = 64;
 +	int rectsCount = addRectsCount;
 +	PRGNDATA pRgnData = (PRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]);
 +	LPRECT pRects = (LPRECT)(&pRgnData->Buffer);
 +
 +	memset(pRgnData, 0, sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT));
 +	pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
 +	pRgnData->rdh.iType = RDH_RECTANGLES;
 +
 +	int first = 0;
 +	bool wasfirst = false;
 +	bool ismask = false;
 +	for (int i = 0; i < height; i++)
 +	{
 +		int j; // we will need j after the loop!
 +		for (j = 0; j < width; j++)
 +		{
 +			ismask = opaque ? (int)geta(this->getRow(i)[j]) > level : (int)geta(this->getRow(i)[j]) < level;
 +			if (wasfirst)
 +			{
 +				if (!ismask)
 +				{
 +					SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1);
 +					if ((int)(pRgnData->rdh.nCount) >= rectsCount)
 +					{
 +						rectsCount += addRectsCount;
 +						LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]);
 +						memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT));
 +						delete pRgnData;
 +						pRgnData = pRgnDataNew;
 +						pRects = (LPRECT)(&pRgnData->Buffer);
 +					}
 +					wasfirst = false;
 +				}
 +			} else
 +			if (ismask) // set wasfirst when mask is found
 +			{
 +				first = j;
 +				wasfirst = true;
 +			}
 +		}
 +
 +		if (wasfirst && ismask)
 +		{
 +			SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1);
 +			if ((int)(pRgnData->rdh.nCount) >= rectsCount)
 +			{
 +				rectsCount += addRectsCount;
 +				LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]);
 +				memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT));
 +				delete pRgnData;
 +				pRgnData = pRgnDataNew;
 +				pRects = (LPRECT)(&pRgnData->Buffer);
 +			}
 +			wasfirst = false;
 +		}
 +
 +	}
 +
 +	HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData);
 +	delete pRgnData;
 +	return hRgn;
 +}
 +
 +static int hex2dec(char hex)
 +{
 +	if ((hex >= '0') && (hex <= '9'))
 +		return hex - '0';
 +	if ((hex >= 'a') && (hex <= 'f'))
 +		return hex - 'a' + 0xa;
 +	if ((hex >= 'A') && (hex <= 'F'))
 +		return hex - 'A' + 0xa;
 +	return 0;
 +}
 +
 +bool MyBitmap::loadFromFile_pixel(const char *fn, const char *fnAlpha)
 +{
 +	allocate(1,1);
 +	int r, g, b, a = 255;
 +	const char *p = fn + lstrlenA("pixel:");
 +	r = (hex2dec(p[0]) << 4) + hex2dec(p[1]);
 +	g = (hex2dec(p[2]) << 4) + hex2dec(p[3]);
 +	b = (hex2dec(p[4]) << 4) + hex2dec(p[5]);
 +	*bits = rgba(r,g,b,a);
 +	return true;
 +}
 +
 +bool MyBitmap::loadFromFile_gradient(const char *fn, const char *fnAlpha)
 +{
 +	const char *p = fn + lstrlenA("gradient:");
 +
 +	if (*p == 'h') allocate(256,1);
 +	else allocate(1,256);
 +
 +	int r, g, b, a = 255;
 +
 +	p += 2;
 +	r = (hex2dec(p[0]) << 4) + hex2dec(p[1]);
 +	g = (hex2dec(p[2]) << 4) + hex2dec(p[3]);
 +	b = (hex2dec(p[4]) << 4) + hex2dec(p[5]);
 +	COLOR32 from = rgba(r,g,b,a);
 +
 +	p += 7;
 +	r = (hex2dec(p[0]) << 4) + hex2dec(p[1]);
 +	g = (hex2dec(p[2]) << 4) + hex2dec(p[3]);
 +	b = (hex2dec(p[4]) << 4) + hex2dec(p[5]);
 +	COLOR32 to = rgba(r,g,b,a);
 +
 +	for (int i = 0; i < 256; ++i)
 +	{
 +		bits[i] = rgba(
 +				((255-i) * getr(from) + i * getr(to)) / 255,
 +				((255-i) * getg(from) + i * getg(to)) / 255,
 +				((255-i) * getb(from) + i * getb(to)) / 255,
 +				255
 +			);
 +	}
 +
 +	return true;
 +}
 +
 +bool MyBitmap::loadFromFile_png(const char *fn, const char *fnAlpha)
 +{
 +	if (ServiceExists(MS_PNG2DIB))
 +	{
 +		HANDLE hFile, hMap = 0;
 +		BYTE *ppMap = 0;
 +		long cbFileSize = 0;
 +		BITMAPINFOHEADER *pDib;
 +		BYTE *pDibBits;
 +		if ((hFile = CreateFileA(fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
 +			if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
 +					if ((ppMap = (BYTE*)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL)
 +						cbFileSize = GetFileSize(hFile, NULL);
 +		if (cbFileSize)
 +		{
 +			PNG2DIB param;
 +			param.pSource = ppMap;
 +			param.cbSourceSize = cbFileSize;
 +			param.pResult = &pDib;
 +			if (CallService(MS_PNG2DIB, 0, (LPARAM)¶m))
 +				pDibBits = (BYTE*)(pDib+1);
 +			else
 +				cbFileSize = 0;
 +		}
 +
 +		if (ppMap) UnmapViewOfFile(ppMap);
 +		if (hMap) CloseHandle(hMap);
 +		if (hFile) CloseHandle(hFile);
 +
 +		if (!cbFileSize) return false;
 +
 +		BITMAPINFO *bi = (BITMAPINFO*)pDib;
 +		BYTE *pt = (BYTE*)bi;
 +		pt+=bi->bmiHeader.biSize;
 +
 +		if (bi->bmiHeader.biBitCount != 32)
 +		{
 +			allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight));
 +			HDC hdcTmp = CreateCompatibleDC(getDC());
 +			HBITMAP hBitmap = CreateDIBitmap(getDC(), pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS);
 +			SelectObject(hdcTmp, hBitmap);
 +			BitBlt(this->getDC(), 0, 0, abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight), hdcTmp, 0, 0, SRCCOPY);
 +			this->makeOpaque();
 +			DeleteDC(hdcTmp);
 +			DeleteObject(hBitmap);
 +		} else
 +		{
 +			allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight));
 +			BYTE *p2 = (BYTE *)pt;
 +			for (int y = 0; y<bi->bmiHeader.biHeight; ++y)
 +			{
 +				BYTE *p1 = (BYTE *)bits + (bi->bmiHeader.biHeight-y-1)*bi->bmiHeader.biWidth*4;
 +				for (int x = 0; x<bi->bmiHeader.biWidth; ++x)
 +				{
 +					p1[0] =  p2[0];
 +					p1[1] =  p2[1];
 +					p1[2] =  p2[2];
 +					p1[3] =  p2[3];
 +					p1 += 4;
 +					p2 += 4;
 +				}
 +			}
 +//				memcpy(bits, pt, bi->bmiHeader.biSizeImage);
 +			premultipleChannels();
 +		}
 +
 +		GlobalFree(pDib);
 +		return true;
 +	} else
 +	{
 +//			MessageBox(NULL, Translate("You need the png2dib plugin v. 0.1.3.x or later to process PNG images"), Translate("Error"), MB_OK);
 +		return false;
 +	}
 +}
 +
 +bool MyBitmap::loadFromFile_default(const char *fn, const char *fnAlpha)
 +{
 +	SIZE sz;
 +	HBITMAP hBmpLoaded = (HBITMAP)LoadImageA(NULL, fn, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
 +	if (!hBmpLoaded)
 +		return false;
 +
 +	BITMAP bm; GetObject(hBmpLoaded, sizeof(bm), &bm);
 +	SetBitmapDimensionEx(hBmpLoaded, bm.bmWidth, bm.bmHeight, NULL);
 +
 +	HDC dcTmp = CreateCompatibleDC(0);
 +	GetBitmapDimensionEx(hBmpLoaded, &sz);
 +	HBITMAP hBmpDcSave = (HBITMAP)SelectObject(dcTmp, hBmpLoaded);
 +
 +	allocate(sz.cx, sz.cy);
 +	BitBlt(dcBmp, 0, 0, width, height, dcTmp, 0, 0, SRCCOPY);
 +
 +	DeleteObject(SelectObject(dcTmp, hBmpDcSave));
 +	DeleteDC(dcTmp);
 +
 +	MyBitmap alpha;
 +	if (fnAlpha && alpha.loadFromFile(fnAlpha) &&
 +		(alpha.getWidth() == width) &&
 +		(alpha.getHeight() == height))
 +	{
 +		for (int i = 0; i < width*height; i++)
 +			bits[i] = (bits[i] & 0x00ffffff) | ( (alpha.bits[i] & 0x000000ff) << 24 );
 +		premultipleChannels();
 +	} else
 +	{
 +		makeOpaque();
 +	}
 +	return true;
 +}
 +
 +bool MyBitmap::loadFromFile(const char *fn, const char *fnAlpha)
 +{
 +	if (bits) free();
 +
 +	if (!strncmp(fn, "pixel:", lstrlenA("pixel:")))
 +	{
 +		return loadFromFile_pixel(fn, fnAlpha);
 +	} else
 +	if (!strncmp(fn, "gradient:", lstrlenA("gradient:")))
 +	{
 +		return loadFromFile_gradient(fn, fnAlpha);
 +	} else
 +	{
 +		char ext[5];
 +		memcpy(ext,fn+(strlen(fn)-4),5);   
 +		if (!lstrcmpiA(ext,".png"))
 +		{
 +			return loadFromFile_png(fn, fnAlpha);
 +		} else
 +		{
 +			return loadFromFile_default(fn, fnAlpha);
 +		}
 +	}
 +	// unreachable place
 +	return false;
 +}
 +
 +void MyBitmap::allocate(int w, int h)
 +{
 +	if (dcBmp && (width == w) && (height == h)) return;
 +	
 +	width = w;
 +	height = h;
 +
 +	BITMAPINFO bi;
 +
 +    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
 +    bi.bmiHeader.biWidth = w;
 +    bi.bmiHeader.biHeight = -h;
 +    bi.bmiHeader.biPlanes = 1;
 +    bi.bmiHeader.biBitCount = 32;
 +    bi.bmiHeader.biCompression = BI_RGB;
 +
 +	if (dcBmp)
 +	{
 +		DeleteObject(SelectObject(dcBmp, hBmpSave));
 +		DeleteDC(dcBmp);
 +	}
 +
 +    hBmp = (HBITMAP)CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void **)&bits, 0, 0);
 +    dcBmp = CreateCompatibleDC(0);
 +    hBmpSave = (HBITMAP)SelectObject(dcBmp, hBmp);
 +
 +	GdiFlush();
 +}
 +
 +void MyBitmap::free()
 +{
 +	GdiFlush();
 +
 +	DeleteObject(SelectObject(dcBmp, hBmpSave));
 +	DeleteDC(dcBmp);
 +
 +	dcBmp = 0;
 +	hBmp = 0;
 +	bits = 0;
 +	width = height = 0;
 +}
 +
 +void MyBitmap::premultipleChannels()
 +{
 +	GdiFlush();
 +
 +	for (int i = 0; i < width*height; i++)
 +		bits[i] = rgba(getr(bits[i])*geta(bits[i])/255, getg(bits[i])*geta(bits[i])/255, getb(bits[i])*geta(bits[i])/255, geta(bits[i]));
 +}
 diff --git a/plugins/FloatingContacts/src/bitmap_funcs.h b/plugins/FloatingContacts/src/bitmap_funcs.h new file mode 100644 index 0000000000..85bbee2004 --- /dev/null +++ b/plugins/FloatingContacts/src/bitmap_funcs.h @@ -0,0 +1,127 @@ +/*
 +Popup Plus plugin for Miranda IM
 +
 +Copyright	© 2002 Luca Santarelli,
 +			© 2004-2007 Victor Pavlychko
 +
 +This program is free software; you can redistribute it and/or
 +modify it under the terms of the GNU General Public License
 +as published by the Free Software Foundation; either version 2
 +of the License, or (at your option) any later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License
 +along with this program; if not, write to the Free Software
 +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 +*/
 +
 +#ifndef __bitmap_funcs_h__
 +#define __bitmap_funcs_h__
 +
 +// This should make bitmap manipulations much easier...
 +class MyBitmap
 +{
 +public:
 +	typedef unsigned long COLOR32;
 +	static inline COLOR32 RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0xff)
 +	{
 +		return (a << 24) | (r << 16) | (g << 8) | b;
 +	};
 +
 +private:
 +	HBITMAP hBmpSave, hBmp;
 +	HDC dcBmp;
 +	COLOR32 *bits;
 +	COLOR32 *bitsSave;
 +	int width, height;
 +
 +	void free();
 +
 +	bool loadFromFile_pixel(const char *fn, const char *fnAlpha = 0);
 +	bool loadFromFile_gradient(const char *fn, const char *fnAlpha = 0);
 +	bool loadFromFile_png(const char *fn, const char *fnAlpha = 0);
 +	bool loadFromFile_default(const char *fn, const char *fnAlpha = 0);
 +	void premultipleChannels();
 +
 +public:
 +	MyBitmap();
 +	MyBitmap(int w, int h);
 +	MyBitmap(const char *fn, const char *fnAlpha = 0);
 +	~MyBitmap();
 +	void allocate(int w, int h);
 +
 +	bool loadFromFile(const char *fn, const char *fnAlpha = 0);
 +
 +	int getWidth() { return width; }
 +	int getHeight() { return height; }
 +
 +	HDC getDC() { return dcBmp; }
 +	HBITMAP getBitmap() { return hBmp; }
 +
 +	void setAlpha(BYTE level);
 +	void setAlphaRect(int x1, int y1, int x2, int y2, BYTE level);
 +	void setAlphaRect(RECT rc, BYTE level) { setAlphaRect(rc.left, rc.top, rc.right, rc.bottom, level);  }
 +
 +	void makeOpaque();
 +	void makeOpaqueRect(int x1, int y1, int x2, int y2);
 +	void makeOpaqueRect(RECT rc) { makeOpaqueRect(rc.left, rc.top, rc.right, rc.bottom);  }
 +
 +	void saveAlpha(int x = 0, int y = 0, int w = 0, int h = 0);
 +	void restoreAlpha(int x = 0, int y = 0, int w = 0, int h = 0);
 +
 +	void DrawBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h);
 +	void BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h);
 +
 +	void DrawNoAlpha(MyBitmap *bmp, int x, int y, int w, int h);
 +
 +	void Blend(MyBitmap *bmp, int x, int y, int w, int h);
 +	void Draw(MyBitmap *bmp, int x, int y, int w, int h);
 +
 +	void BlendColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color);
 +	void DrawColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color);
 +
 +	void BlendPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h);
 +	void BlendPartColorized(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color);
 +	void DrawPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h);
 +//	void DrawPartNoAlpha(MyBitmap *bmp, int x, int y, int w, int h);
 +//	void DrawPartColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color);
 +
 +	void Blur(int w, int h);
 +	void IncreaseAlpha(float q);
 +
 +	void DrawIcon(HICON hic, int x, int y, int w = 0, int h = 0);
 +	void DrawText(TCHAR *str, int x, int y, int blur = 0, int strength = 0);
 +
 +	__forceinline COLOR32 *getBits() { return bits; }
 +	__forceinline COLOR32 *getRow(int row) { return bits + row * width; }
 +	__forceinline COLOR32 *operator[] (int row) { return bits + row * width; }
 +
 +	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;
 +	}
 +
 +	HRGN buildOpaqueRgn(int level = 64, bool opaque = true);
 +};
 +
 +#endif // __bitmap_funcs_h__
 diff --git a/plugins/FloatingContacts/src/filedrop.cpp b/plugins/FloatingContacts/src/filedrop.cpp new file mode 100644 index 0000000000..473c7a6814 --- /dev/null +++ b/plugins/FloatingContacts/src/filedrop.cpp @@ -0,0 +1,368 @@ +#include "stdhdr.h"
 +
 +static	void	ProcessDroppedItems	( char **ppDroppedItems, int nCount, char **ppFiles );
 +static	int		CountDroppedFiles	( char **ppDroppedItems, int nCount  );
 +static	BOOL	OnDropFiles			( HDROP hDrop, ThumbInfo *pThumb );
 +
 +HRESULT STDMETHODCALLTYPE CDropTarget::QueryInterface(REFIID riid,LPVOID *ppvObj)
 +{
 +	if ( IsEqualIID( riid, IID_IDropTarget )) 
 +	{
 +		*ppvObj = this;
 +		this->AddRef();
 +		return S_OK;
 +	}
 +	
 +	*ppvObj = NULL;
 +
 +	return ( E_NOINTERFACE );
 +}
 +
 +ULONG STDMETHODCALLTYPE CDropTarget::AddRef( )
 +{
 +	return ++this->refCount;
 +}
 +
 +ULONG STDMETHODCALLTYPE CDropTarget::Release( )
 +{
 +	int res = --this->refCount;
 +	if (!res) delete this;
 +	return res;
 +}
 +
 +
 +HRESULT STDMETHODCALLTYPE CDropTarget::DragOver( DWORD fKeyState, POINTL pt, DWORD *pdwEffect )
 +{
 +	*pdwEffect = 0;
 +	
 +	if ( hwndCurDrag == NULL ) 
 +	{
 +		*pdwEffect = DROPEFFECT_NONE;
 +	}
 +	else
 +	{
 +		*pdwEffect |= DROPEFFECT_COPY;
 +	}
 +	return S_OK;
 +}
 +
 +
 +HRESULT STDMETHODCALLTYPE CDropTarget::DragEnter( IDataObject *pData, DWORD fKeyState, POINTL pt, DWORD *pdwEffect)
 +{
 +	HWND		hwnd	 =  NULL;
 +	POINT		shortPt;
 +	FORMATETC	feFile	 =  { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 +	FORMATETC	feText	 =  { CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 +	ThumbInfo *pThumb;
 +
 +	if ( S_OK == pData->QueryGetData( &feFile ) ||
 +		 S_OK == pData->QueryGetData( &feText ))
 +	{
 +		shortPt.x	 =  pt.x; 
 +		shortPt.y	 =  pt.y;
 +		
 +		hwnd = WindowFromPoint( shortPt );
 +		
 +		if ( pThumb = thumbList.FindThumb( hwnd ))
 +		{
 +			hwndCurDrag = hwnd;
 +			pThumb->ThumbSelect( TRUE );
 +		}
 +	}
 +
 +	return DragOver( fKeyState, pt, pdwEffect);
 +}
 +
 +
 +HRESULT STDMETHODCALLTYPE CDropTarget::DragLeave( )
 +{
 +	ThumbInfo *pThumb = thumbList.FindThumb( hwndCurDrag );
 +
 +	if ( NULL != pThumb )
 +	{
 +		pThumb->ThumbDeselect( TRUE );
 +	}
 +
 +	hwndCurDrag = NULL;
 +	
 +	return S_OK;
 +}
 +
 +
 +HRESULT STDMETHODCALLTYPE CDropTarget::Drop( IDataObject *pData,DWORD fKeyState,POINTL pt,DWORD *pdwEffect)
 +{
 +	FORMATETC	fe		 =  { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 +	STGMEDIUM	stg;
 +	HDROP		hDrop		 =  NULL;
 +	ThumbInfo	*pThumb		 =  NULL;
 +	char		*pText		 =  NULL;
 +	BOOL		bFormatText = FALSE;
 +
 +	*pdwEffect = DROPEFFECT_NONE;
 +	
 +
 +	if ( hwndCurDrag == NULL ) return( S_OK );
 +
 +	pThumb	 =  (ThumbInfo*)GetWindowLongPtr( hwndCurDrag, GWLP_USERDATA );
 +	if ( pThumb == NULL ) return( S_OK );
 +
 +	if ( S_OK != pData->GetData( &fe,&stg ))
 +	{
 +		fe.cfFormat = CF_TEXT;
 +
 +		if ( S_OK != pData->GetData( &fe,&stg ))
 +		{
 +			return( S_OK );
 +		}
 +		else
 +		{
 +			bFormatText = TRUE;
 +		}
 +	}
 +		
 +	
 +
 +	if ( !bFormatText )
 +	{
 +		hDrop	 =  (HDROP)stg.hGlobal;
 +		
 +		if ( hDrop != NULL )
 +		{
 +			OnDropFiles( hDrop, pThumb );
 +		}
 +	}
 +	else
 +	{
 +		pText = (char*)GlobalLock( stg.hGlobal );
 +
 +		if ( pText != NULL  )
 +		{
 +			SendMsgDialog( hwndCurDrag, pText );
 +			GlobalUnlock( stg.hGlobal );
 +		}
 +	}
 +
 +	if ( stg.pUnkForRelease != NULL )
 +	{
 +		stg.pUnkForRelease->Release( );
 +	}
 +	else 
 +	{
 +		GlobalFree( stg.hGlobal );
 +	}
 +
 +	DragLeave( );
 +	
 +	return S_OK;
 +}
 +
 +///////////////////////////////////////////////////////
 +// Send files processing
 +
 +BOOL OnDropFiles( HDROP hDrop, ThumbInfo *pThumb )
 +{
 +	BOOL	bSuccess			 =  FALSE;
 +	UINT	nFilesCount			 =  0;
 +	UINT	iItem				 =  0;
 +	char	**ppFiles			 =  NULL;	
 +	char	**ppDroppedItems	 =  NULL;
 +	UINT	nDroppedItemsCount	 =  0;
 +	char	szFilename[ MAX_PATH ];
 +	
 +
 +	nDroppedItemsCount = DragQueryFile( hDrop, 0xFFFFFFFF, NULL, 0 );
 +
 +	ppDroppedItems = ( char** )malloc( sizeof(char*)*( nDroppedItemsCount + 1 ));
 +	
 +	if ( ppDroppedItems == NULL )
 +	{
 +		return( FALSE );
 +	}
 +
 +	ppDroppedItems[ nDroppedItemsCount ] = NULL;
 +	
 +	for ( iItem = 0; iItem < nDroppedItemsCount; ++iItem ) 
 +	{
 +		DragQueryFileA( hDrop, iItem, szFilename, sizeof( szFilename ));
 +		ppDroppedItems[ iItem ] = _strdup( szFilename );
 +	}
 +	
 +	nFilesCount = CountDroppedFiles( ppDroppedItems, nDroppedItemsCount );
 +	
 +	ppFiles = ( char** )malloc( sizeof( char *)* ( nFilesCount+1 ));
 +	
 +	if ( ppFiles == NULL )
 +	{
 +		return( FALSE );
 +	}
 +	
 +	ppFiles[ nFilesCount] = NULL;
 +
 +	ProcessDroppedItems( ppDroppedItems, nDroppedItemsCount, ppFiles );
 +
 +	bSuccess = (BOOL)CallService( MS_CLIST_CONTACTFILESDROPPED, (WPARAM)pThumb->hContact, (LPARAM)ppFiles ); 
 +
 +	// Cleanup
 +	for ( iItem = 0; ppDroppedItems[ iItem ]; ++iItem ) 
 +	{
 +		free( ppDroppedItems[ iItem ] );
 +	}
 +
 +	free( ppDroppedItems );
 +
 +	for ( iItem = 0; iItem < nFilesCount ; ++iItem ) 
 +	{
 +		free( ppFiles[ iItem ] );
 +	}
 +
 +	free( ppFiles );
 +
 +	return( bSuccess );
 +}
 +
 +
 +static int CountFiles( char *szItem )
 +{
 +	int nCount = 0;
 +	WIN32_FIND_DATAA	fd;
 +	
 +	HANDLE hFind = FindFirstFileA( szItem, &fd );
 +
 +	if ( hFind != INVALID_HANDLE_VALUE )
 +	{
 +		do
 +		{
 +			if ( fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY )
 +			{
 +				// Skip parent directories
 +				if ( ( 0 != strcmp( fd.cFileName, "." )) &&
 +					 ( 0 != strcmp( fd.cFileName, ".." )) )
 +				{
 +					char szDirName[ MAX_PATH ];
 +					strncpy( szDirName, szItem, MAX_PATH - 1 );
 +
 +					if ( NULL != strstr( szItem, "*.*" ))
 +					{
 +						sprintf( szDirName + strlen( szDirName ) - 3, "%s\0", fd.cFileName );
 +					}
 +					
 +					++nCount;
 +					strcat( szDirName, "\\*.*" );
 +					nCount += CountFiles( szDirName );
 +				}
 +			}
 +			else
 +			{
 +				++nCount;
 +			}
 +		}
 +		while( FALSE != FindNextFileA( hFind, &fd ));
 +	}
 +
 +	return( nCount );
 +}
 +
 +
 +
 +static void SaveFiles( char *szItem, char **ppFiles, int *pnCount )
 +{
 +	
 +	WIN32_FIND_DATAA	fd;
 +
 +	HANDLE hFind = FindFirstFileA( szItem, &fd );
 +
 +	if ( hFind != INVALID_HANDLE_VALUE )
 +	{
 +		do
 +		{
 +			if ( fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY )
 +			{
 +				// Skip parent directories
 +				if ( ( 0 != strcmp( fd.cFileName, "." )) &&
 +					 ( 0 != strcmp( fd.cFileName, ".." )) )
 +				{
 +					char szDirName[ MAX_PATH ];
 +					strncpy( szDirName, szItem, MAX_PATH - 1 );
 +
 +					if ( NULL != strstr( szItem, "*.*" ))
 +					{
 +						sprintf( szDirName + strlen( szDirName ) - 3, "%s\0", fd.cFileName );
 +					}
 +					
 +					ppFiles[ *pnCount ] = _strdup( szDirName );
 +					++( *pnCount );
 +
 +					strcat( szDirName, "\\*.*" );
 +					SaveFiles( szDirName, ppFiles, pnCount );
 +					
 +				}
 +			}
 +			else
 +			{
 +				int	 nSize = sizeof(char) * ( strlen( szItem ) + strlen( fd.cFileName ) + sizeof( char ));
 +				char *szFile = (char*) malloc( nSize ) ;
 +				
 +				strncpy( szFile, szItem, nSize - 1 ); 
 +				
 +				if ( NULL != strstr( szFile, "*.*" ))
 +				{
 +					szFile[ strlen( szFile ) - 3 ] = '\0';
 +					strncat( szFile, fd.cFileName, MAX_PATH - 1 );
 +				}
 +								
 +				ppFiles[ *pnCount ] = szFile;
 +				++( *pnCount );
 +			}
 +		}
 +		while( FALSE != FindNextFileA( hFind, &fd ));
 +	}
 +}
 +
 +
 +static void ProcessDroppedItems( char **ppDroppedItems, int nCount, char **ppFiles  )
 +{
 +	int i;
 +	int fileCount = 0;
 +
 +	for ( i = 0; i < nCount; ++i )
 +	{
 +		SaveFiles( ppDroppedItems[ i ], ppFiles, &fileCount );
 +	}
 +}
 +
 +
 +static int CountDroppedFiles( char **ppDroppedItems, int nCount  )
 +{
 +	int fileCount = 0;
 +	int i;
 +	
 +	for ( i = 0; i < nCount; ++i )
 +	{
 +		fileCount += CountFiles( ppDroppedItems[ i ] );
 +	}
 +
 +	return( fileCount );
 +}
 +
 +
 +///////////////////////////////////////////////////////////////////////////////
 +// Init/destroy
 +void InitFileDropping()
 +{
 +	OleInitialize( NULL );
 +}
 +
 +void FreeFileDropping(void)
 +{
 +	OleUninitialize();
 +}
 +
 +void RegisterFileDropping( HWND hwnd, CDropTarget* pdropTarget )
 +{
 +	RegisterDragDrop( hwnd, (IDropTarget*)pdropTarget );
 +}
 +
 +void UnregisterFileDropping( HWND hwnd )
 +{
 +	RevokeDragDrop( hwnd );
 +}
 diff --git a/plugins/FloatingContacts/src/filedrop.h b/plugins/FloatingContacts/src/filedrop.h new file mode 100644 index 0000000000..b5c7f803aa --- /dev/null +++ b/plugins/FloatingContacts/src/filedrop.h @@ -0,0 +1,26 @@ +/* This file is a modification of clcfiledrop.h originally 
 + written by Richard Hughes*/
 +
 +static HWND	hwndCurDrag	 =  NULL;
 +
 +class CDropTarget: public IDropTarget
 +{
 +private:
 +	unsigned long refCount;
 +
 +public:
 +	CDropTarget(): refCount(0) {}
 +
 +	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,LPVOID *ppvObj);
 +	ULONG STDMETHODCALLTYPE AddRef();
 +	ULONG STDMETHODCALLTYPE Release();
 +	HRESULT STDMETHODCALLTYPE DragOver(DWORD fKeyState, POINTL pt, DWORD *pdwEffect);
 +	HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pData, DWORD fKeyState, POINTL pt, DWORD *pdwEffect);
 +	HRESULT STDMETHODCALLTYPE DragLeave();
 +	HRESULT STDMETHODCALLTYPE Drop(IDataObject *pData,DWORD fKeyState,POINTL pt,DWORD *pdwEffect);
 +};
 +
 +void InitFileDropping();
 +void FreeFileDropping(void);
 +void RegisterFileDropping( HWND hwnd, CDropTarget* pdropTarget );
 +void UnregisterFileDropping( HWND hwnd );
 diff --git a/plugins/FloatingContacts/src/fltcont.h b/plugins/FloatingContacts/src/fltcont.h new file mode 100644 index 0000000000..3d725d71bc --- /dev/null +++ b/plugins/FloatingContacts/src/fltcont.h @@ -0,0 +1,191 @@ +
 +#ifndef __FLTCONT_H__
 +#define __FLTCONT_H__
 +
 +#if _MSC_VER >= 1000
 +#pragma once
 +#endif // _MSC_VER >= 1000
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +#define WND_CLASS					_T("MirandaThumbsWnd")
 +#define	WM_REFRESH_CONTACT			WM_USER + 0x100
 +
 +#ifndef WS_EX_LAYERED
 +	#define WS_EX_LAYERED           0x00080000
 +#endif
 +
 +#ifndef LWA_ALPHA
 +	#define LWA_ALPHA               0x00000002
 +#endif
 +
 +#ifndef ULW_ALPHA
 +	#define ULW_ALPHA				0x00000002
 +#endif
 +
 +#define TIMERID_SELECT_T			1
 +#define TIMERID_HOVER_T				2
 +#define TIMERID_TOTOP_T				3
 +#define TIMERID_LEAVE_T				4
 +
 +
 +#if WINVER < 0x0500
 +	#define SM_XVIRTUALSCREEN       76
 +	#define SM_YVIRTUALSCREEN       77
 +	#define SM_CXVIRTUALSCREEN      78
 +	#define SM_CYVIRTUALSCREEN      79
 +#endif
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +enum
 +{
 +	FLT_FONTID_CONTACTS,
 +	FLT_FONTID_INVIS,
 +	FLT_FONTID_OFFLINE,
 +	FLT_FONTID_OFFINVIS,
 +	FLT_FONTID_NOTONLIST,
 +	FLT_FONTIDS,
 +};
 +
 +#define DBFONTF_BOLD       1
 +#define DBFONTF_ITALIC     2
 +#define DBFONTF_UNDERLINE  4
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +#define FLT_DEFAULT_DRAWBORDER			TRUE
 +#define FLT_DEFAULT_LTEDGESCOLOR		GetSysColor(COLOR_3DHILIGHT)
 +#define FLT_DEFAULT_RBEDGESCOLOR		GetSysColor(COLOR_3DDKSHADOW)
 +#define FLT_DEFAULT_BKGNDCOLOR			GetSysColor(COLOR_3DFACE)
 +#define FLT_DEFAULT_BKGNDUSEBITMAP		FALSE
 +#define FLT_DEFAULT_BKGNDBITMAPOPT		CLB_STRETCH
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +#define sModule "FloatingContacts"
 +
 +#define TOTOPTIME_P	1000
 +#define TOTOPTIME_MAX	(15*(60000/TOTOPTIME_P))
 +#define TOTOPTIME_DEF	(3*(60000/TOTOPTIME_P))
 +
 +#define MAXRCOOR 32767.0
 +#define DB_POS_GETX(pos) (short)(((float)(short)(LOWORD(pos))*(float)GetSystemMetrics(SM_CXSCREEN))/MAXRCOOR+0.5)
 +#define DB_POS_GETY(pos) (short)(((float)(short)(HIWORD(pos))*(float)GetSystemMetrics(SM_CYSCREEN))/MAXRCOOR+0.5)
 +#define DB_POS_MAKE_XY(x, y) MAKELONG((short)(((float)x*MAXRCOOR)/(float)GetSystemMetrics(SM_CXSCREEN)+0.5), (short)(((float)y*MAXRCOOR)/(float)GetSystemMetrics(SM_CYSCREEN)+0.5))
 +
 +extern HINSTANCE	hInst;
 +extern BOOL			bNT;
 +//extern BOOL			bHideOffline;
 +//extern BOOL			bHideAll;
 +//extern BOOL			bHideWhenFullscreen;
 +//extern BOOL			bMoveTogether;
 +//extern BOOL			bFixedWidth;
 +//extern int			nThumbWidth;
 +//extern BYTE			thumbAlpha;
 +//extern BOOL			bShowTip;
 +extern BOOL			bEnableTip;
 +//extern WORD			TimeIn;
 +//extern BOOL			bToTop;
 +//extern WORD			ToTopTime;
 +//extern BOOL			bHideWhenCListShow;
 +
 +extern BOOL			bIsCListShow;
 +extern HWND			hwndMiranda;
 +extern HIMAGELIST	himl;
 +extern RECT			rcScreen;
 +
 +extern HFONT		hFont[FLT_FONTIDS];
 +extern COLORREF		tColor[FLT_FONTIDS];
 +
 +extern HPEN			hLTEdgesPen;
 +extern HPEN			hRBEdgesPen;
 +extern HBRUSH		hBkBrush;
 +extern DWORD		bkColor;
 +extern HBITMAP		hBmpBackground;
 +extern WORD			nBackgroundBmpUse;
 +
 +
 +
 +typedef struct _FCOptions
 +{
 +	BYTE	thumbAlpha;
 +	BOOL	bHideOffline;
 +	BOOL	bHideAll;
 +	BOOL	bHideWhenFullscreen;
 +	BOOL	bMoveTogether;
 +	BOOL	bFixedWidth;
 +	int		nThumbWidth;
 +	BOOL	bShowTip;
 +	WORD	TimeIn;
 +	BOOL	bToTop;
 +	WORD	ToTopTime;
 +	BOOL	bHideWhenCListShow;
 +	BOOL	bUseSingleClick;
 +	BOOL	bShowIdle;
 +} 
 +FCOptions;
 +
 +extern FCOptions fcOpt;
 +
 +extern BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD);
 +extern BOOL (WINAPI *pUpdateLayeredWindow)
 +	(HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc,
 +	 COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags);
 +
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +static __forceinline BOOL ImageList_GetIconSize_my(HIMAGELIST himl, SIZE &sz)
 +{
 +	int cx, cy;
 +	BOOL res = ImageList_GetIconSize(himl, &cx, &cy);
 +	sz.cx = cx; sz.cy = cy;
 +	return res;
 +}
 +
 +void RegHotkey				( HANDLE hContact, HWND hwnd );
 +BOOL IsStatusVisible		( int status );
 +BOOL HideOnFullScreen		();
 +void SendMsgDialog			( HWND hwnd, char *pText );
 +void SaveContactsPos		( void );
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +void
 +GetFontSetting
 +	( IN BOOL bFltContacts
 +	, IN int nFontId
 +	, IN LOGFONTA* lf
 +	, IN COLORREF* colour
 +	);
 +
 +void
 +ApplyOptionsChanges();
 +
 +void
 +OnStatusChanged();
 +
 +void
 +SetThumbsOpacity
 +	( IN BYTE btAlpha
 +	);
 +
 +int
 +OnOptionsInitialize
 +	( IN WPARAM wParam
 +	, IN LPARAM lParam
 +	);
 +
 +/////////////////////////////////////////////////////////////////////////////
 +
 +#endif	// #ifndef __FLTCONT_H__
 +
 +/////////////////////////////////////////////////////////////////////////////
 +// End Of File fltcont.h
 diff --git a/plugins/FloatingContacts/src/main.cpp b/plugins/FloatingContacts/src/main.cpp new file mode 100644 index 0000000000..f51e1f6d34 --- /dev/null +++ b/plugins/FloatingContacts/src/main.cpp @@ -0,0 +1,1268 @@ +/*
 +Miranda Floating Contacts plugin, created by Iavor Vajarov ( ivajarov@code.bg )
 +http://miranda-icq.sourceforge.net/
 +
 +Miranda fonts and colors settings by Ranger.
 +Extended bonts and backgrounds settings by Oleksiy Shurubura
 +
 +
 +This file is placed in the public domain. Anybody is free to use or
 +modify it as they wish with no restriction.
 +
 +This plugin has been tested to work under Windows ME, 2000 and XP.
 +
 +No warranty for any misbehaviour.
 +*/
 +
 +#include "stdhdr.h"
 +#include "shlwapi.h"
 +
 +#include "version.h"
 +
 +#pragma comment ( lib, "comctl32.lib" )
 +#pragma comment ( lib, "shlwapi.lib" )
 +
 +#pragma warning ( default : 4201 )
 +
 +//#define DB_POS_GETX(pos) LOWORD(pos)
 +//#define DB_POS_GETY(pos) HIWORD(pos)
 +//#define DB_POS_MAKE_XY(x, y) MAKELONG(x, y)
 +
 +BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD);
 +BOOL (WINAPI *pUpdateLayeredWindow)
 +	(HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc,
 +	 COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags);
 +
 +// Globals
 +
 +// TODO: move to some more approriate place, probably part of Thumbs manager
 +static void	LoadContacts			( void );
 +static void LoadContact				( HANDLE hContact );
 +
 +// Internal funcs
 +static void	RepaintWindow			( HWND hwnd, HDC hdc );
 +static void	LoadMenus				();
 +static void	CreateThumbWnd			( TCHAR *ptszName, HANDLE hContact, int nX, int nY );
 +static void	RegisterWindowClass		( void );
 +static void	UnregisterWindowClass	( void );
 +static void	CleanUp					( void );
 +static BOOL GetOSPlatform			( void );
 +static void LoadDBSettings			( void );
 +static void CreateThumbsFont		( void );
 +static void CreateBackgroundBrush	( void );
 +static int	GetContactStatus		( HANDLE hContact );
 +static void	GetScreenRect			( void );
 +extern void SetThumbsOpacity		( BYTE btAlpha );
 +static int	ClcStatusToPf2			( int status );
 +
 +static LRESULT __stdcall CommWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
 +static LRESULT __stdcall newMirandaWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
 +
 +static int OnContactDeleted			( WPARAM wParam, LPARAM lParam );
 +static int OnContactIconChanged		( WPARAM wParam, LPARAM lParam );
 +static int OnContactDrag			( WPARAM wParam, LPARAM lParam );
 +static int OnContactDrop			( WPARAM wParam, LPARAM lParam );
 +static int OnContactDragStop		( WPARAM wParam, LPARAM lParam );
 +static int OnSkinIconsChanged		( WPARAM wParam, LPARAM lParam );
 +static int OnContactSettingChanged	( WPARAM wParam, LPARAM lParam );
 +static int OnStatusModeChange		( WPARAM wParam, LPARAM lParam );
 +static int OnModulesLoded			( WPARAM wParam, LPARAM lParam );
 +static int OnPrebuildContactMenu	( WPARAM wParam, LPARAM lParam );
 +
 +static INT_PTR OnContactMenu_Remove		( WPARAM wParam, LPARAM lParam );
 +static INT_PTR OnMainMenu_HideAll		( WPARAM wParam, LPARAM lParam );
 +static INT_PTR OnHotKey_HideWhenCListShow( WPARAM wParam, LPARAM lParam );
 +static VOID CALLBACK ToTopTimerProc ( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
 +
 +WNDPROC oldMirandaWndProc;
 +
 +
 +HINSTANCE	hInst				 =  NULL;
 +HMODULE		hUserDll			 =  NULL;
 +HFONT		hFont[FLT_FONTIDS]	 =  {NULL};
 +COLORREF	tColor[FLT_FONTIDS]	 =  {0};
 +HIMAGELIST	himl				 =  NULL;
 +HANDLE		hevContactIcon		 =  NULL;
 +HANDLE		hevContactDrop		 =  NULL;
 +HANDLE		hevContactDragStop	 =  NULL;
 +HANDLE		hevSkinIcons		 =  NULL;
 +HANDLE		hevContactDrag		 =  NULL;
 +HANDLE		hevContactSetting	 =  NULL;
 +HANDLE		hevContactDeleted	 =  NULL;
 +HANDLE		hevOptionsInit		 =  NULL;
 +HANDLE		hevStatusMode		 =  NULL;
 +HANDLE		hevModules			 =  NULL;
 +HANDLE		hevPrebuildMenu		 =  NULL;
 +HANDLE		hNewContact			 =  NULL;
 +
 +HPEN		hLTEdgesPen			 =  NULL;
 +HPEN		hRBEdgesPen			 =  NULL;
 +HBRUSH		hBkBrush			 =  NULL;
 +DWORD		bkColor				 =  0;
 +HBITMAP		hBmpBackground		 =  NULL;
 +WORD		nBackgroundBmpUse	 =  CLB_STRETCH;
 +
 +HWND		hwndMiranda			 =  NULL;
 +BOOL		bVersionOK			 =  FALSE;
 +BOOL		bNT					 =  FALSE;
 +BOOL		bDockHorz			 =  TRUE;
 +//UINT		nStatus				 =  0;
 +HMENU		hContactMenu		 =  NULL;
 +HANDLE		hMenuItemRemove		 =  NULL;
 +HANDLE		hMenuItemHideAll	 =  NULL;
 +HANDLE		hMainMenuItemHideAll	 =  NULL;
 +RECT		rcScreen;
 +DWORD		dwOfflineModes		 =  0;
 +BOOL		bEnableTip			 =  FALSE;
 +UINT_PTR	ToTopTimerID		 =  0;
 +BOOL		bIsCListShow		 =  TRUE;
 +
 +HANDLE		hRemoveThumb		 =  NULL;
 +HANDLE		hMainHideAllThumbs	 =  NULL;
 +HANDLE		hHideWhenCListShow	 =  NULL;
 +int hLangpack;
 +
 +//Options
 +
 +FCOptions fcOpt = {0};
 +
 +static void InitOptions() {
 +	fcOpt.thumbAlpha			 =  255;
 +	fcOpt.bHideOffline			 =  FALSE;
 +	fcOpt.bHideAll				 =  FALSE;
 +	fcOpt.bHideWhenFullscreen	 =  FALSE;
 +	fcOpt.bMoveTogether			 =  FALSE;
 +	fcOpt.bFixedWidth			 =  FALSE;
 +	fcOpt.nThumbWidth			 =  0;
 +	fcOpt.bShowTip				 =  TRUE;
 +	fcOpt.TimeIn				 =  0;
 +	fcOpt.bToTop				 =  TRUE;
 +	fcOpt.ToTopTime				 =  TOTOPTIME_DEF;
 +	fcOpt.bHideWhenCListShow	 =  FALSE;
 +	fcOpt.bUseSingleClick		 =  FALSE;
 +	fcOpt.bShowIdle				 =  TRUE;
 +}
 +
 +// {53C715A8-EB01-4136-A73C-441868610074}
 +#define MIID_FLTCONT  { 0x53c715a8, 0xeb01, 0x4136, { 0xa7, 0x3c, 0x44, 0x18, 0x68, 0x61, 0x0, 0x74 } }
 +
 +PLUGININFOEX pluginInfoEx  = {
 +	sizeof(PLUGININFOEX),
 +		__PLUGIN_NAME,
 +		0,
 +		__DESC,
 +		__AUTHOR,
 +		__AUTHOREMAIL,
 +		__COPYRIGHT,
 +		__AUTHORWEB,
 +		UNICODE_AWARE,
 +		MIID_FLTCONT
 +};
 +
 +_inline unsigned int MakeVer(int a, int b, int c, int d)
 +{
 +    return PLUGIN_MAKE_VERSION(a, b, c, d);
 +}
 +
 +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
 +{
 +	return &pluginInfoEx;
 +}
 +
 +
 +///////////////////////////////////////////////////////
 +// Load / unload
 +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
 +{
 +	hInst = hinstDLL;
 +
 +	switch ( fdwReason )
 +	{
 +		case DLL_PROCESS_ATTACH:
 +			break;
 +
 +		case DLL_PROCESS_DETACH:
 +			break;
 +	}
 +
 +	return( TRUE );
 +}
 +
 +extern "C" int __declspec(dllexport) Load(  )
 +{
 +	SetLastError( 0 );
 +	InitOptions();
 +
 +	mir_getLP(&pluginInfoEx);
 +
 +	hevModules = HookEvent( ME_SYSTEM_MODULESLOADED,  OnModulesLoded );
 +	bNT = GetOSPlatform();
 +
 +	if (hUserDll = LoadLibrary(_T("user32.dll"))) {
 +		pSetLayeredWindowAttributes  =
 +			(BOOL (WINAPI *)(HWND, COLORREF, BYTE, DWORD))
 +			GetProcAddress(hUserDll, "SetLayeredWindowAttributes");
 +		pUpdateLayeredWindow  =
 +			(BOOL (WINAPI *)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD))
 +			GetProcAddress(hUserDll, "UpdateLayeredWindow");
 +	}
 +	else {
 +		pSetLayeredWindowAttributes = NULL;
 +		pUpdateLayeredWindow = NULL;
 +	}
 +
 +	return 0;
 +}
 +
 +
 +
 +extern "C" int __declspec(dllexport) Unload()
 +{
 +	CleanUp();
 +	return 0;
 +}
 +
 +
 +
 +static void CleanUp()
 +{
 +	int nFontId;
 +
 +	UnhookEvent( hevContactIcon );
 +	UnhookEvent( hevContactDrag );
 +	UnhookEvent( hevContactDrop );
 +	UnhookEvent( hevContactDragStop );
 +	UnhookEvent( hevSkinIcons );
 +	UnhookEvent( hevContactDeleted );
 +	UnhookEvent( hevContactSetting );
 +	UnhookEvent( hevOptionsInit );
 +	UnhookEvent( hevStatusMode );
 +	UnhookEvent( hevModules );
 +	UnhookEvent( hevPrebuildMenu );
 +
 +	if (hRemoveThumb)
 +		DestroyServiceFunction(hRemoveThumb);
 +	if (hMainHideAllThumbs)
 +		DestroyServiceFunction(hMainHideAllThumbs);
 +	if (hHideWhenCListShow)
 +		DestroyServiceFunction(hHideWhenCListShow);
 +
 +	if (ServiceExists(MS_HOTKEY_UNREGISTER)) {
 +		CallService(MS_HOTKEY_UNREGISTER, 0, (LPARAM)(sModule "/MainHideAllThumbs"));
 +		CallService(MS_HOTKEY_UNREGISTER, 0, (LPARAM)(sModule "/HideWhenCListShow"));
 +	}
 +
 +	if (NULL != hLTEdgesPen)
 +		DeleteObject(hLTEdgesPen);
 +	if (NULL != hRBEdgesPen)
 +		DeleteObject(hRBEdgesPen);
 +	if (NULL != hBmpBackground)
 +		DeleteObject(hBmpBackground);
 +	if (NULL != hBkBrush) {
 +		SetClassLong((HWND)WND_CLASS, GCLP_HBRBACKGROUND, (LONG)NULL);
 +		DeleteObject(hBkBrush);
 +		hBkBrush = NULL;
 +	}
 +
 +	for (nFontId = 0; nFontId < FLT_FONTIDS; nFontId++)
 +		if (NULL != hFont[nFontId])
 +			DeleteObject(hFont[nFontId]);
 +
 +	UnregisterWindowClass();
 +
 +	FreeFileDropping();
 +
 +	if ( hUserDll != NULL )
 +		FreeLibrary( hUserDll );
 +}
 +
 +
 +
 +///////////////////////////////////////////////////////
 +// Hooked events
 +static int OnModulesLoded( WPARAM wParam, LPARAM lParam )
 +{
 +	hevContactIcon		 =  HookEvent( ME_CLIST_CONTACTICONCHANGED,  OnContactIconChanged );
 +	hevSkinIcons		 =  HookEvent( ME_SKIN_ICONSCHANGED,  OnSkinIconsChanged );
 +	hevContactDrag		 =  HookEvent( ME_CLUI_CONTACTDRAGGING,  OnContactDrag );
 +	hevContactDrop		 =  HookEvent( ME_CLUI_CONTACTDROPPED,  OnContactDrop );
 +	hevContactDragStop	 =  HookEvent( ME_CLUI_CONTACTDRAGSTOP,  OnContactDragStop );
 +	hevContactSetting	 =  HookEvent( ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged );
 +	hevContactDeleted	 =  HookEvent( ME_DB_CONTACT_DELETED, OnContactDeleted );
 +	hevOptionsInit		 =  HookEvent( ME_OPT_INITIALISE, OnOptionsInitialize );
 +	hevStatusMode		 =  HookEvent( ME_CLIST_STATUSMODECHANGE, OnStatusModeChange );
 +	hevPrebuildMenu		 =  HookEvent( ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildContactMenu );
 +	hwndMiranda			 =  (HWND)CallService( MS_CLUI_GETHWND, 0, 0 );
 +
 +	oldMirandaWndProc	 =  (WNDPROC)SetWindowLongPtr( hwndMiranda, GWLP_WNDPROC, (LONG)newMirandaWndProc);
 +
 +
 +
 +	// No thumbs yet
 +//	pThumbsList	 =  NULL;
 +	bEnableTip = ServiceExists("mToolTip/ShowTip");
 +
 +	RegisterWindowClass();
 +	InitFileDropping();
 +	GetScreenRect();
 +	LoadDBSettings();
 +	CreateBackgroundBrush();
 +	CreateThumbsFont();
 +	LoadContacts();
 +	LoadMenus();
 +
 +	if (fcOpt.bToTop){
 +		fcOpt.ToTopTime = (fcOpt.ToTopTime<1)?1:fcOpt.ToTopTime;
 +		fcOpt.ToTopTime = (fcOpt.ToTopTime>TOTOPTIME_MAX)?TOTOPTIME_MAX:fcOpt.ToTopTime;
 +		ToTopTimerID = SetTimer(NULL, 0, fcOpt.ToTopTime*TOTOPTIME_P, ToTopTimerProc);
 +	}
 +	return( 0 );
 +}
 +
 +
 +static int OnContactDeleted( WPARAM wParam, LPARAM lParam )
 +{
 +	HANDLE		hContact	 =  ( HANDLE )wParam;
 +	ThumbInfo	*pThumb		 =  thumbList.FindThumbByContact( hContact );
 +	if (!pThumb) return 0;
 +
 +	pThumb->DeleteContactPos();
 +	thumbList.RemoveThumb(pThumb);
 +
 +	return 0;
 +}
 +
 +
 +static int OnContactIconChanged( WPARAM wParam, LPARAM lParam )
 +{
 +	HANDLE		hContact	 =  ( HANDLE )wParam;
 +	ThumbInfo	*pThumb		 =  thumbList.FindThumbByContact( hContact );
 +
 +	if ( pThumb )
 +	{
 +		pThumb->RefreshContactIcon( ( int )lParam );
 +		//pThumb->ThumbSelect( FALSE );
 +		//SetTimer( pThumb->hwnd, TIMERID_SELECT_T, 1000, NULL );
 +	}
 +
 +	return 0;
 +}
 +
 +
 +static int OnContactDrag( WPARAM wParam, LPARAM lParam )
 +{
 +	ThumbInfo	*pNewThumb	 =  NULL;
 +	HANDLE		hContact	 =  ( HANDLE )wParam;
 +	ThumbInfo	*pThumb		 =  thumbList.FindThumbByContact( hContact );
 +	TCHAR		*ptName		 =  (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME, wParam, (LPARAM)GCDNF_TCHAR );
 +	int			idStatus	 =  ID_STATUS_OFFLINE;
 +	POINT pt;
 +	GetCursorPos(&pt);
 +
 +	if ( pThumb == NULL ) {
 +		idStatus = GetContactStatus( hContact );
 +
 +		if ( !fcOpt.bHideAll && !HideOnFullScreen() && ( !fcOpt.bHideOffline || IsStatusVisible( idStatus ))  && (!fcOpt.bHideWhenCListShow || !bIsCListShow)) {
 +			CreateThumbWnd( ptName, hContact, pt.x, pt.y );
 +			pNewThumb = thumbList.FindThumbByContact( hContact );
 +			ShowWindow( pNewThumb->hwnd, SW_SHOWNA );
 +			hNewContact = hContact;
 +
 +			OnStatusChanged();
 +		}
 +	}
 +	else if ( hContact == hNewContact )
 +		pThumb->PositionThumb( (short)( pt.x - 5 ), (short)( pt.y - 5 ));
 +
 +	return( hNewContact != NULL ? 1 : 0 );
 +}
 +
 +
 +
 +static int OnContactDrop( WPARAM wParam, LPARAM lParam )
 +{
 +	RECT	rcMiranda;
 +	RECT	rcThumb;
 +//	RECT	rcOverlap;
 +
 +	HANDLE	hContact	 =  ( HANDLE )wParam;
 +	ThumbInfo *pThumb	 =  thumbList.FindThumbByContact( hContact );
 +
 +	if ( ( hNewContact == hContact ) && ( pThumb != NULL ))
 +	{
 +		hNewContact = NULL;
 +
 +		GetWindowRect( hwndMiranda, &rcMiranda );
 +		pThumb->GetThumbRect( &rcThumb );
 +
 +		//if ( IntersectRect( &rcOverlap, &rcThumb, &rcMiranda ))
 +		//{
 +		//	pThumb->OnLButtonDown( (short)(rcThumb.left + 5), (short)(rcThumb.top + 5));
 +		//}
 +	}
 +
 +	SaveContactsPos();
 +
 +	return( 1 );
 +}
 +
 +
 +static int OnContactDragStop( WPARAM wParam, LPARAM lParam )
 +{
 +	HANDLE	hContact = ( HANDLE )wParam;
 +	ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact );
 +
 +	if ( ( pThumb != NULL ) && ( hNewContact == hContact ))
 +	{
 +		thumbList.RemoveThumb( pThumb );
 +		hNewContact = NULL;
 +	}
 +
 +	return( 0 );
 +}
 +
 +
 +static int OnSkinIconsChanged( WPARAM wParam, LPARAM lParam )
 +{
 +	// Get handle to the image list
 +	himl = ( HIMAGELIST )CallService( MS_CLIST_GETICONSIMAGELIST, 0, 0 );
 +
 +	// Update thumbs
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +		thumbList[i]->UpdateContent();
 +
 +	return( 0 );
 +}
 +
 +
 +
 +static int OnContactSettingChanged( WPARAM wParam, LPARAM lParam )
 +{
 +	HANDLE		hContact	 =  ( HANDLE )wParam;
 +	ThumbInfo	*pThumb		 =  thumbList.FindThumbByContact( hContact );
 +	int			idStatus	 =  ID_STATUS_OFFLINE;
 +	BOOL		bRefresh	 =  TRUE;
 +	DBCONTACTWRITESETTING* pdbcws = ( DBCONTACTWRITESETTING* )lParam;
 +
 +
 +	if ( hContact == NULL )
 +	{
 +		if (( 0 == stricmp( pdbcws->szModule, "CLC" )) || ( 0 == stricmp( pdbcws->szModule, sModule )) ) {
 +			LoadDBSettings();
 +			ApplyOptionsChanges();
 +		}
 +
 +		return( 0 );
 +	}
 +
 +	if ( pThumb == NULL ) return( 0 );
 +
 +	// Only on these 2 events we need to refresh
 +	if ( 0 == stricmp( pdbcws->szSetting, "Status" ))
 +	{
 +		idStatus = pdbcws->value.wVal;
 +	}
 +	else if ( 0 == stricmp( pdbcws->szSetting, "Nick" ))
 +	{
 +		idStatus = GetContactStatus( hContact );
 +	}
 +	else if ( 0 == stricmp( pdbcws->szSetting, "MyHandle" ))
 +	{
 +		idStatus = GetContactStatus( hContact );
 +	}
 +	else if ( fcOpt.bShowIdle && 0 == stricmp( pdbcws->szSetting, "IdleTS" ))
 +	{
 +		idStatus = GetContactStatus( hContact );
 +	}
 +	else
 +	{
 +		bRefresh = FALSE;
 +	}
 +
 +	if ( bRefresh )
 +	{
 +		// Detach call
 +		PostMessage( pThumb->hwnd, WM_REFRESH_CONTACT, 0, idStatus );
 +	}
 +
 +	return( 0 );
 +}
 +
 +
 +static int OnStatusModeChange( WPARAM wParam, LPARAM lParam )
 +{
 +	int			idStatus;
 +
 +	//nStatus = (int)wParam;
 +
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +	{
 +		idStatus = GetContactStatus( thumbList[i]->hContact );
 +		thumbList[i]->RefreshContactStatus( idStatus );
 +	}
 +	if ( wParam == ID_STATUS_OFFLINE )
 +	{
 +		// Floating status window will use this
 +	}
 +
 +	return( 0 );
 +}
 +
 +
 +
 +static int OnPrebuildContactMenu( WPARAM wParam, LPARAM lParam )
 +{
 +	ThumbInfo *pThumb = thumbList.FindThumbByContact( (HANDLE) wParam );
 +	CLISTMENUITEM clmi;
 +
 +	ZeroMemory( &clmi, sizeof( clmi ));
 +	clmi.cbSize = sizeof( clmi );
 +
 +	clmi.flags = ( pThumb == NULL ) ? CMIM_FLAGS | CMIF_HIDDEN : CMIM_FLAGS &~CMIF_HIDDEN;
 +	CallService( MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemRemove, (LPARAM)&clmi );
 +
 +	clmi.flags = fcOpt.bHideAll ? CMIM_FLAGS | CMIF_HIDDEN : CMIM_FLAGS &~CMIF_HIDDEN;
 +	CallService( MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemHideAll, (LPARAM)&clmi );
 +
 +	return( 0 );
 +}
 +
 +
 +
 +
 +///////////////////////////////////////////////////////
 +// General functions
 +
 +static void LoadDBSettings()
 +{
 +	fcOpt.thumbAlpha			 =  (BYTE)((double)DBGetContactSettingByte( NULL, sModule, "Opacity", 100 ) * 2.55 );
 +	fcOpt.bHideOffline			 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "HideOffline", 0 );
 +	fcOpt.bHideAll				 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "HideAll", 0 );
 +	fcOpt.bHideWhenFullscreen	 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "HideWhenFullscreen", 0 );
 +	fcOpt.bMoveTogether			 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "MoveTogether", 0 );
 +	fcOpt.bFixedWidth			 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "FixedWidth", 0 );
 +	fcOpt.nThumbWidth			 =  (DWORD)DBGetContactSettingDword( NULL, sModule, "Width", 0 );
 +	dwOfflineModes				 =  DBGetContactSettingDword( NULL, "CLC", "OfflineModes", CLCDEFAULT_OFFLINEMODES );
 +	fcOpt.bShowTip				 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "ShowTip", 1 );
 +	fcOpt.TimeIn				 =  (WORD)DBGetContactSettingWord( NULL, sModule, "TimeIn", 0 );
 +	fcOpt.bToTop				 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "ToTop", 0 );
 +	fcOpt.ToTopTime				 =  (WORD)DBGetContactSettingWord( NULL, sModule, "ToTopTime", TOTOPTIME_DEF );
 +	fcOpt.bHideWhenCListShow	 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "HideWhenCListShow", 0 );
 +	fcOpt.bUseSingleClick		 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "UseSingleClick", 0 );
 +	fcOpt.bShowIdle				 =  (BOOL)DBGetContactSettingByte( NULL, sModule, "ShowIdle", 0 );
 +
 +	if (DBGetContactSettingByte(NULL, "ModernData", "HideBehind", 0))
 +		bIsCListShow = (DBGetContactSettingByte(NULL, "ModernData", "BehindEdge", 0) == 0);
 +	else
 +		bIsCListShow = (DBGetContactSettingByte(NULL, "CList", "State", 0) == 2);
 +}
 +
 +void SendMsgDialog( HWND hwnd, char *pText )
 +{
 +	ThumbInfo *pThumb = thumbList.FindThumb( hwnd );
 +
 +	if ( pThumb != NULL )
 +		CallService( MS_MSG_SENDMESSAGE, (WPARAM)pThumb->hContact, (LPARAM)pText );
 +}
 +
 +
 +static void ShowContactMenu( HWND hwnd, POINT pt )
 +{
 +	ThumbInfo	*pThumb		 =  thumbList.FindThumb( hwnd );
 +	int			idCommand	 =  0;
 +
 +	if ( pThumb != NULL )
 +	{
 +		hContactMenu = (HMENU)CallService( MS_CLIST_MENUBUILDCONTACT, (WPARAM)pThumb->hContact, (LPARAM)0 );
 +
 +		if ( hContactMenu == NULL ) return;
 +
 +		idCommand = TrackPopupMenu( hContactMenu, TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, 0 , hwnd, NULL );
 +		CallService( MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM( idCommand , MPCF_CONTACTMENU), (LPARAM)pThumb->hContact );
 +	}
 +}
 +
 +static LRESULT __stdcall CommWndProc(	HWND	hwnd,
 +										UINT	uMsg,
 +										WPARAM	wParam,
 +										LPARAM  lParam	)
 +{
 +	LRESULT		lResult		 =  0;
 +	ThumbInfo	*pThumb		 =  thumbList.FindThumb( hwnd );
 +
 +	switch( uMsg )
 +	{
 +	case WM_RBUTTONUP:
 +		{
 +			POINT pt;
 +			pt.x = LOWORD( lParam );
 +			pt.y = HIWORD( lParam );
 +
 +			if (pThumb) pThumb->ThumbDeselect( TRUE );
 +
 +			ClientToScreen(hwnd, &pt);
 +			ShowContactMenu( hwnd, pt );
 +		}
 +
 +		break;
 +
 +//#if 0
 +	case WM_NCPAINT:
 +		if (pThumb){
 +			HDC hdc = GetWindowDC( hwnd );
 +			BitBlt(hdc, 0, 0, pThumb->bmpContent.getWidth(), pThumb->bmpContent.getHeight(), pThumb->bmpContent.getDC(), 0, 0, SRCCOPY);
 +			//RepaintWindow( hwnd, hdc );
 +			ReleaseDC( hwnd, hdc );
 +			ValidateRect( hwnd, NULL );
 +			return 0;
 +		}
 +
 +	case WM_PAINT:
 +		if (pThumb){
 +			PAINTSTRUCT ps;
 +			HDC hdc = BeginPaint(hwnd, &ps);
 +			BitBlt(hdc, 0, 0, pThumb->bmpContent.getWidth(), pThumb->bmpContent.getHeight(), pThumb->bmpContent.getDC(), 0, 0, SRCCOPY);
 +			//RepaintWindow( hwnd, hdc );
 +			EndPaint(hwnd, &ps);
 +			break;
 +		}
 +
 +	case WM_PRINT:
 +	case WM_PRINTCLIENT:
 +		if (pThumb){
 +			BitBlt((HDC)wParam, 0, 0, pThumb->bmpContent.getWidth(), pThumb->bmpContent.getHeight(), pThumb->bmpContent.getDC(), 0, 0, SRCCOPY);
 +			//RepaintWindow(hwnd, (HDC)wParam);
 +			break;
 +		}
 +//#endif
 +
 +	case WM_MEASUREITEM:
 +		lResult = CallService( MS_CLIST_MENUMEASUREITEM, wParam, lParam );
 +		break;
 +
 +	case WM_DRAWITEM:
 +		lResult = CallService( MS_CLIST_MENUDRAWITEM, wParam, lParam );
 +		break;
 +
 +	case WM_LBUTTONDOWN:
 +		if (pThumb) pThumb->OnLButtonDown( (short)LOWORD( lParam ), (short)HIWORD( lParam ));
 +		break;
 +
 +	case WM_MOUSEMOVE:
 +		if (pThumb) pThumb->OnMouseMove( (short)LOWORD( lParam ), (short)HIWORD( lParam ), wParam);
 +		break;
 +
 +	case WM_LBUTTONUP:
 +		if (pThumb) pThumb->OnLButtonUp();
 +		//if (bMouseMoved || !DBGetContactSettingByte(NULL, "CList", "Tray1Click", SETTING_TRAY1CLICK_DEFAULT))
 +		break;
 +		// FALL THRU
 +
 +	case WM_LBUTTONDBLCLK:
 +		// Popup message dialog
 +		//if (pThumb) pThumb->ThumbDeselect( TRUE );
 +		if (!fcOpt.bUseSingleClick && pThumb)
 +			pThumb->PopUpMessageDialog();
 +		break;
 +
 +	case WM_RBUTTONDOWN:
 +		if (bEnableTip && fcOpt.bShowTip && pThumb) pThumb->KillTip();
 +		break;
 +	case WM_REFRESH_CONTACT:
 +		if (pThumb)
 +		{
 +			_tcsncpy( pThumb->ptszName, (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pThumb->hContact, (LPARAM)GCDNF_TCHAR ), USERNAME_LEN - 1 );
 +			pThumb->RefreshContactStatus( (int)lParam );
 +			pThumb->ResizeThumb();
 +		}
 +		break;
 +
 +	case WM_TIMER:
 +		if (pThumb)pThumb->OnTimer(wParam);
 +		break;
 +
 +	case WM_HOTKEY:
 +		{
 +			ThumbInfo *pThumb = thumbList.FindThumb( ( HWND )wParam );
 +
 +			if (pThumb)	pThumb->PopUpMessageDialog();
 +		}
 +
 +	default:
 +		break;
 +	}
 +
 +	lResult = DefWindowProc( hwnd, uMsg, wParam, lParam );
 +
 +	return( lResult );
 +}
 +
 +
 +
 +extern void SetThumbsOpacity( BYTE btAlpha )
 +{
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +		thumbList[i]->SetThumbOpacity( btAlpha );
 +}
 +
 +
 +
 +static void GetScreenRect()
 +{
 +	rcScreen.left	 =  GetSystemMetrics( SM_XVIRTUALSCREEN );
 +	rcScreen.top	 =  GetSystemMetrics( SM_YVIRTUALSCREEN );
 +	rcScreen.right	 =  GetSystemMetrics( SM_CXVIRTUALSCREEN ) + rcScreen.left;
 +	rcScreen.bottom	 =  GetSystemMetrics( SM_CYVIRTUALSCREEN ) + rcScreen.top;
 +}
 +
 +
 +
 +void OnStatusChanged()
 +{
 +	int			idStatus	 =  ID_STATUS_OFFLINE;
 +
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +	{
 +		idStatus = GetContactStatus( thumbList[i]->hContact );
 +		thumbList[i]->RefreshContactStatus( idStatus );
 +	}
 +}
 +
 +
 +
 +void ApplyOptionsChanges()
 +{
 +	CreateThumbsFont();
 +	CreateBackgroundBrush();
 +
 +//	dwOfflineModes	 =  DBGetContactSettingDword( NULL, "CLC", "OfflineModes", CLCDEFAULT_OFFLINEMODES );
 +	if (!fcOpt.bToTop && ToTopTimerID){
 +		KillTimer(NULL, ToTopTimerID);
 +		ToTopTimerID = 0;
 +	}
 +	if (fcOpt.bToTop){
 +		if (ToTopTimerID) KillTimer(NULL, ToTopTimerID);
 +		fcOpt.ToTopTime = (fcOpt.ToTopTime<1)?1:fcOpt.ToTopTime;
 +		fcOpt.ToTopTime = (fcOpt.ToTopTime>TOTOPTIME_MAX)?TOTOPTIME_MAX:fcOpt.ToTopTime;
 +		ToTopTimerID = SetTimer(NULL, 0, fcOpt.ToTopTime*TOTOPTIME_P, ToTopTimerProc);
 +	}
 +
 +	OnStatusChanged();
 +
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +		thumbList[i]->ResizeThumb();
 +}
 +
 +
 +
 +///////////////////////////////////////////////////////
 +// Window creation
 +static void RegisterWindowClass()
 +{
 +	WNDCLASSEX	wcx;
 +	ZeroMemory( &wcx, sizeof( wcx ));
 +
 +	wcx.cbSize			 = 	sizeof( WNDCLASSEX );
 +	wcx.style			 = 	CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
 +	wcx.lpfnWndProc		 = 	CommWndProc;
 +	wcx.cbClsExtra		 = 	0;
 +	wcx.cbWndExtra		 = 	0;
 +	wcx.hInstance		 = 	hInst;
 +	wcx.hIcon			 = 	NULL;
 +	wcx.hCursor			 = 	NULL;
 +	wcx.hbrBackground	 = 	GetSysColorBrush(COLOR_3DFACE);
 +	wcx.lpszMenuName	 = 	NULL;
 +	wcx.lpszClassName	 = 	WND_CLASS;
 +	wcx.hIconSm			 = 	NULL;
 +
 +	SetLastError( 0 );
 +
 +	RegisterClassEx( &wcx );
 +}
 +
 +
 +
 +static void UnregisterWindowClass()
 +{
 +	UnregisterClass( WND_CLASS, hInst );
 +}
 +
 +
 +
 +static void CreateThumbWnd( TCHAR *ptszName, HANDLE hContact, int nX, int nY )
 +{
 +	HWND		hwnd		 =  NULL;
 +	ThumbInfo	*pThumb		 =  thumbList.FindThumbByContact( hContact );
 +
 +	// Prepare for window creation
 +	if ( pThumb == NULL )
 +	{
 +		hwnd = CreateWindowEx(	WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
 +								WND_CLASS,
 +								ptszName,
 +								WS_POPUP,
 +								nX,
 +								nY,
 +								50,
 +								20,
 +								NULL /*hwndMiranda*/,
 +								NULL,
 +								hInst,
 +								NULL
 +								 );
 +
 +		if ( hwnd != NULL )
 +		{
 +			pThumb = thumbList.AddThumb( hwnd, ptszName, hContact );
 +			SetWindowLongPtr( hwnd, GWLP_USERDATA, (long)pThumb );
 +			pThumb->ResizeThumb();
 +
 +			pThumb->SetThumbOpacity( fcOpt.thumbAlpha );
 +			ShowWindow( hwnd, ( fcOpt.bHideAll || HideOnFullScreen() || fcOpt.bHideOffline  || (fcOpt.bHideWhenCListShow && bIsCListShow))? SW_HIDE : SW_SHOWNA );
 +			pThumb->PositionThumb( (short)nX, (short)nY );
 +
 +			// force repaint
 +			pThumb->UpdateContent();
 +		}
 +	}
 +}
 +
 +
 +
 +static BOOL GetOSPlatform()
 +{
 +	OSVERSIONINFO	VersionInfo;
 +
 +	// Get OS platform
 +	ZeroMemory( &VersionInfo, sizeof( VersionInfo ));
 +	VersionInfo.dwOSVersionInfoSize = sizeof( VersionInfo );
 +
 +	GetVersionEx( &VersionInfo );
 +	return( VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT );
 +}
 +
 +
 +
 +static void CreateThumbsFont()
 +{
 +	int nFontId;
 +	LOGFONTA lf;
 +
 +	for (nFontId = 0; nFontId < FLT_FONTIDS; nFontId++)
 +	{
 +		if (NULL != hFont[nFontId])
 +		{
 +			DeleteObject(hFont[nFontId]);
 +			hFont[nFontId] = NULL;
 +		}
 +		GetFontSetting(TRUE, nFontId, &lf, &tColor[nFontId]);
 +		{
 +			LONG height;
 +			HDC hdc = GetDC(NULL);
 +			height = lf.lfHeight;
 +			lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
 +			ReleaseDC(NULL, hdc);
 +
 +			hFont[nFontId] = CreateFontIndirectA(&lf);
 +
 +			lf.lfHeight = height;
 +		}
 +	}
 +}
 +
 +
 +
 +static void CreateBackgroundBrush()
 +{
 +//	LOGBRUSH	lb;
 +	bkColor = DBGetContactSettingDword(NULL, sModule, "BkColor", FLT_DEFAULT_BKGNDCOLOR);
 +
 +
 +	if (NULL != hLTEdgesPen)
 +	{
 +		DeleteObject(hLTEdgesPen);
 +		hLTEdgesPen = NULL;
 +	}
 +	if (NULL != hRBEdgesPen)
 +	{
 +		DeleteObject(hRBEdgesPen);
 +		hRBEdgesPen = NULL;
 +	}
 +	if (NULL != hBmpBackground)
 +	{
 +		DeleteObject(hBmpBackground);
 +		hBmpBackground = NULL;
 +	}
 +	if (NULL != hBkBrush)
 +	{
 +		SetClassLong((HWND)WND_CLASS, GCLP_HBRBACKGROUND, (LONG)NULL);
 +		DeleteObject( hBkBrush );
 +		hBkBrush = NULL;
 +	}
 +
 +	if (DBGetContactSettingByte(NULL, sModule, "DrawBorder", FLT_DEFAULT_DRAWBORDER))
 +	{
 +		COLORREF cr;
 +
 +		cr = (COLORREF)DBGetContactSettingDword(NULL, sModule, "LTEdgesColor", FLT_DEFAULT_LTEDGESCOLOR);
 +		hLTEdgesPen = CreatePen(PS_SOLID, 1, cr);
 +		cr = (COLORREF)DBGetContactSettingDword(NULL, sModule, "RBEdgesColor", FLT_DEFAULT_RBEDGESCOLOR);
 +		hRBEdgesPen = CreatePen(PS_SOLID, 1, cr);
 +	}
 +	if (DBGetContactSettingByte(NULL, sModule, "BkUseBitmap", FLT_DEFAULT_BKGNDUSEBITMAP))
 +	{
 +		DBVARIANT dbv;
 +
 +		if (!DBGetContactSetting(NULL, sModule, "BkBitmap", &dbv))
 +		{
 +			hBmpBackground = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (LPARAM)dbv.pszVal);
 +			DBFreeVariant(&dbv);
 +		}
 +	}
 +	nBackgroundBmpUse = (WORD)DBGetContactSettingWord(NULL, sModule, "BkBitmapOpt", FLT_DEFAULT_BKGNDBITMAPOPT);
 +
 +	// Create brush
 +	hBkBrush	 =  CreateSolidBrush(bkColor);
 +
 +	// Attach brush to the window
 +	SetClassLong((HWND)WND_CLASS, GCLP_HBRBACKGROUND, (LONG)hBkBrush);
 +}
 +
 +
 +static int GetContactStatus( HANDLE hContact )
 +{
 +	char	*szProto	 =  NULL;
 +	int		idStatus	 =  ID_STATUS_OFFLINE;
 +
 +	if ( hContact == NULL )
 +	{
 +		assert( !"Contact is NULL" );
 +		return( 0 );
 +	}
 +
 +	szProto	 =  ( char* )CallService( "Proto/GetContactBaseProto", (WPARAM)hContact, 0 );
 +
 +	if ( NULL != szProto )
 +	{
 +		idStatus	 =  DBGetContactSettingWord( hContact, szProto, "Status", ID_STATUS_OFFLINE );
 +	}
 +
 +
 +	return( idStatus );
 +}
 +
 +
 +static int ClcStatusToPf2( int status )
 +{
 +	switch(status) {
 +		case ID_STATUS_ONLINE: return PF2_ONLINE;
 +		case ID_STATUS_AWAY: return PF2_SHORTAWAY;
 +		case ID_STATUS_DND: return PF2_HEAVYDND;
 +		case ID_STATUS_NA: return PF2_LONGAWAY;
 +		case ID_STATUS_OCCUPIED: return PF2_LIGHTDND;
 +		case ID_STATUS_FREECHAT: return PF2_FREECHAT;
 +		case ID_STATUS_INVISIBLE: return PF2_INVISIBLE;
 +		case ID_STATUS_ONTHEPHONE: return PF2_ONTHEPHONE;
 +		case ID_STATUS_OUTTOLUNCH: return PF2_OUTTOLUNCH;
 +		case ID_STATUS_OFFLINE: return MODEF_OFFLINE;
 +	}
 +	return 0;
 +}
 +
 +BOOL IsStatusVisible( int status )
 +{
 +	return ( 0 == ( dwOfflineModes & ClcStatusToPf2( status )) );
 +}
 +
 +
 +
 +void RegHotkey( HANDLE hContact, HWND hwnd )
 +{
 +	char szBuf[ MAX_PATH ] =  {0};
 +/*	char szPath[ MAX_PATH ] =  {0};
 +
 +	GetModuleFileName( NULL, szPath, MAX_PATH );
 +	PathRemoveFileSpec( szPath );
 +	strcat( szPath, "\\Thumbs.ini" );
 +	GetPrivateProfileString( "Hotkeys", szName, "", szBuf, MAX_PATH - 1, szPath );*/
 +	DBVARIANT dbv;
 +	if (DBGetContactSettingString ( hContact, sModule, "Hotkey", &dbv)) return;
 +	strncpy(szBuf, dbv.pszVal, MAX_PATH - 1);
 +	DBFreeVariant( &dbv );
 +
 +	if ( 0 != strlen( szBuf ))
 +	{
 +		UINT nModifiers			 =  0;
 +		char chKey				 =  0;
 +		char szMod[ 2 ][ 20 ]	 =  {0};
 +		char szKey[ 20 ]		 =  {0};
 +		int i = 0;
 +
 +		sscanf( szBuf, "%[^'+']+%[^'+']+%[^'+']", szMod[ 0 ], szMod[ 1 ], szKey );
 +
 +		for (  i = 0; i < 2; ++i )
 +		{
 +			if ( 0 == strncmp( szMod[ i ], "ALT", 19 ))
 +			{
 +				nModifiers = nModifiers | MOD_ALT;
 +			}
 +			else if ( 0 == strncmp( szMod[ i ], "CTRL", 19 ))
 +			{
 +				nModifiers = nModifiers | MOD_CONTROL;
 +			}
 +			else if ( 0 == strncmp( szMod[ i ], "SHIFT", 19 ))
 +			{
 +				nModifiers = nModifiers | MOD_SHIFT;
 +			}
 +		}
 +
 +		chKey = szKey[ 0 ];
 +
 +		RegisterHotKey( hwnd, (int)hwnd, nModifiers, VkKeyScan( chKey ));
 +	}
 +}
 +
 +
 +
 +///////////////////////////////////////////////////////
 +// Contact sttings
 +
 +void SaveContactsPos()
 +{
 +	RECT					rc;
 +
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +	{
 +		SetLastError( 0 );
 +
 +		thumbList[i]->GetThumbRect( &rc );
 +
 +		if ( 0 == GetLastError())
 +			DBWriteContactSettingDword( thumbList[i]->hContact, sModule, "ThumbsPos", DB_POS_MAKE_XY(rc.left, rc.top));
 +	}
 +}
 +
 +
 +static void LoadContacts()
 +{
 +	HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0) ;
 +	while( hContact != NULL ) {
 +		LoadContact( hContact );
 +		hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
 +	}
 +}
 +
 +
 +
 +
 +static void LoadMenus()
 +{
 +	// Remove thumb menu item
 +	hRemoveThumb = CreateServiceFunction( sModule "/RemoveThumb", OnContactMenu_Remove );
 +
 +	CLISTMENUITEM mi = { 0 };
 +	mi.cbSize = sizeof( mi );
 +	mi.position = 0xFFFFF;
 +	mi.flags = CMIF_TCHAR;
 +	mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_HIDE ));
 +	mi.ptszName = _T("Remove thumb");
 +	mi.pszService = sModule "/RemoveThumb";
 +	hMenuItemRemove = Menu_AddContactMenuItem(&mi);
 +
 +	// Hide all thumbs main menu item
 +	hMainHideAllThumbs = CreateServiceFunction( sModule "/MainHideAllThumbs", OnMainMenu_HideAll );
 +	ZeroMemory( &mi, sizeof( mi ));
 +
 +	mi.cbSize = sizeof( mi );
 +	mi.position = 0xFFFFF;
 +	mi.flags = CMIF_TCHAR;
 +	mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( fcOpt.bHideAll ? IDI_SHOW : IDI_HIDE ));
 +	mi.ptszName = fcOpt.bHideAll ? _T("Show all thumbs") : _T("Hide all thumbs");
 +	mi.pszService = sModule "/MainHideAllThumbs";
 +	Menu_AddMainMenuItem(&mi);
 +
 +	// Register hotkeys
 +	HOTKEYDESC hkd = {0};
 +	hkd.cbSize = sizeof(hkd);
 +	hkd.pszSection = "Floating Contacts";
 +
 +	hkd.pszName = sModule "/MainHideAllThumbs";
 +	hkd.pszDescription = LPGEN("Show/Hide all thumbs");
 +	hkd.pszService = sModule "/MainHideAllThumbs";
 +	Hotkey_Register(&hkd);
 +
 +	hHideWhenCListShow = CreateServiceFunction( sModule "/HideWhenCListShow", OnHotKey_HideWhenCListShow );
 +	hkd.pszName = sModule "/HideWhenCListShow";
 +	hkd.pszDescription = LPGEN("Hide when contact list is shown");
 +	hkd.pszService = sModule "/HideWhenCListShow";
 +	Hotkey_Register(&hkd);
 +}
 +
 +
 +static void LoadContact( HANDLE hContact )
 +{
 +	DWORD	dwPos		 =  (DWORD)-1;
 +	TCHAR	*ptName		 =  NULL;
 +	ThumbInfo	*pThumb	 =  thumbList.FindThumbByContact( hContact );
 +	int		nX, nY;
 +
 +
 +	if ( hContact == NULL ) return;
 +
 +	dwPos = DBGetContactSettingDword( hContact, sModule, "ThumbsPos", (DWORD)-1 );
 +
 +	if ( dwPos != -1 )
 +	{
 +		ptName = (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME, ( WPARAM )hContact, (LPARAM)GCDNF_TCHAR );
 +
 +		if ( ptName != NULL )
 +		{
 +			nX = DB_POS_GETX( dwPos );
 +			nY = DB_POS_GETY( dwPos );
 +
 +			CreateThumbWnd( ptName, hContact, nX, nY );
 +			pThumb->PositionThumb( (short)nX, (short)nY );
 +		}
 +	}
 +}
 +
 +
 +BOOL HideOnFullScreen()
 +{
 +	BOOL bFullscreen = FALSE;
 +	HWND hWnd = 0;
 +
 +	if ( fcOpt.bHideWhenFullscreen )
 +	{
 +		int w = GetSystemMetrics(SM_CXSCREEN);
 +		int h = GetSystemMetrics(SM_CYSCREEN);
 +
 +		hWnd = GetForegroundWindow();
 +
 +		while (GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
 +		{
 +			RECT WindowRect;
 +			GetWindowRect(hWnd, &WindowRect);
 +
 +			if ( (w == (WindowRect.right - WindowRect.left)) &&
 +				(h == (WindowRect.bottom - WindowRect.top)))
 +			{
 +				bFullscreen = TRUE;
 +				break;
 +			}
 +
 +			hWnd = GetNextWindow( hWnd, GW_HWNDNEXT );
 +		}
 +	}
 +
 +	return bFullscreen && fcOpt.bHideWhenFullscreen;
 +}
 +
 +
 +static INT_PTR OnContactMenu_Remove( WPARAM wParam, LPARAM lParam )
 +{
 +	HANDLE hContact = ( HANDLE )wParam;
 +	ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact );
 +
 +	if (pThumb) {
 +		pThumb->DeleteContactPos();
 +		thumbList.RemoveThumb(pThumb);
 +	}
 +
 +	DestroyMenu( hContactMenu );
 +	return 0;
 +}
 +
 +static INT_PTR OnHotKey_HideWhenCListShow( WPARAM wParam, LPARAM lParam )
 +{
 +	fcOpt.bHideWhenCListShow = !fcOpt.bHideWhenCListShow;
 +	DBWriteContactSettingByte(NULL, sModule, "HideWhenCListShow", (BYTE)fcOpt.bHideWhenCListShow);
 +	OnStatusChanged();
 +	return 0;
 +}
 +
 +
 +static INT_PTR OnMainMenu_HideAll( WPARAM wParam, LPARAM lParam )
 +{
 +	CLISTMENUITEM clmi = {0};
 +	int b;
 +
 +	fcOpt.bHideAll = !fcOpt.bHideAll;
 +	DBWriteContactSettingByte(NULL, sModule, "HideAll", (BYTE)fcOpt.bHideAll);
 +	OnStatusChanged();
 +
 +	clmi.cbSize		 =  sizeof( clmi );
 +	clmi.flags		 =  CMIM_NAME | CMIM_ICON|CMIF_TCHAR;
 +	clmi.hIcon		 =  LoadIcon( hInst, MAKEINTRESOURCE( fcOpt.bHideAll ? IDI_SHOW : IDI_HIDE ));
 +	clmi.ptszName	 =  fcOpt.bHideAll ? _T("Show all thumbs") : _T("Hide all thumbs");
 +	b = CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMainMenuItemHideAll, ( LPARAM )&clmi );
 +	return 0;
 +}
 +
 +static VOID CALLBACK ToTopTimerProc ( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
 +{
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +	{
 +		SetWindowPos(thumbList[i]->hwnd,
 +					HWND_TOPMOST,
 +					0,
 +					0,
 +					0,
 +					0,
 +					SWP_NOSIZE | SWP_NOMOVE | /*SWP_NOZORDER |*/ SWP_NOACTIVATE);
 +	}
 +}
 +
 +void ShowThumbsOnHideCList()
 +{
 +	if (!fcOpt.bHideWhenCListShow || fcOpt.bHideAll || HideOnFullScreen())
 +		return;
 +
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +		if ( !fcOpt.bHideOffline || IsStatusVisible( GetContactStatus(thumbList[i]->hContact)))
 +			ShowWindow( thumbList[i]->hwnd, SW_SHOWNA );
 +}
 +
 +
 +void HideThumbsOnShowCList()
 +{
 +	if (!fcOpt.bHideWhenCListShow || fcOpt.bHideAll || HideOnFullScreen())return;
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +		ShowWindow( thumbList[i]->hwnd, SW_HIDE );
 +}
 +
 +static LRESULT __stdcall newMirandaWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
 +{
 +	if ( uMsg == WM_WINDOWPOSCHANGED) {
 +		WINDOWPOS *wp = (WINDOWPOS *)lParam;
 +		if (wp->flags&SWP_HIDEWINDOW) {
 +			bIsCListShow = FALSE;
 +			ShowThumbsOnHideCList();
 +		}
 +		else if (wp->flags&SWP_SHOWWINDOW){
 +			bIsCListShow = TRUE;
 +			HideThumbsOnShowCList();
 +		}
 +		else if (!(wp->flags&SWP_NOMOVE)) {
 +			BYTE method = DBGetContactSettingByte(NULL, "ModernData", "HideBehind", 0);
 +			if (method) {
 +				WORD wBehindEdgeBorderSize = DBGetContactSettingWord(NULL, "ModernData", "HideBehindBorderSize", 0);
 +				RECT rc = {wp->x, wp->y, wp->x+wp->cx, wp->y+wp->cy};
 +				RECT rcScreen = {wBehindEdgeBorderSize*(2-method), 0, GetSystemMetrics(SM_CXSCREEN)-wBehindEdgeBorderSize*(method-1), GetSystemMetrics(SM_CYSCREEN)};
 +				RECT rcOverlap;
 +				BOOL isIntersect;
 +
 +				isIntersect = IntersectRect( &rcOverlap, &rc, &rcScreen );
 +				if ( !isIntersect && bIsCListShow ) {
 +					bIsCListShow = FALSE;
 +					ShowThumbsOnHideCList();
 +				}
 +				else if ( isIntersect && !bIsCListShow ) {
 +					bIsCListShow = TRUE;
 +					HideThumbsOnShowCList();
 +				}
 +			}
 +		}
 +	}
 +	return( CallWindowProc(oldMirandaWndProc, hwnd, uMsg, wParam, lParam));
 +}
 diff --git a/plugins/FloatingContacts/src/options.cpp b/plugins/FloatingContacts/src/options.cpp new file mode 100644 index 0000000000..cee946a438 --- /dev/null +++ b/plugins/FloatingContacts/src/options.cpp @@ -0,0 +1,1171 @@ +
 +#include "stdhdr.h"
 +
 +#include "resource.h"
 +#include "fltcont.h"
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +#define SAMEASF_FACE   1
 +#define SAMEASF_SIZE   2
 +#define SAMEASF_STYLE  4
 +#define SAMEASF_COLOUR 8
 +
 +typedef struct _SFontSettings
 +{
 +	BYTE sameAsFlags,sameAs;
 +	COLORREF colour;
 +	char size;
 +	BYTE style;
 +	BYTE charset;
 +	char szFace[LF_FACESIZE];
 +} SFontSettings;
 +
 +static SFontSettings s_rgFontSettings[FLT_FONTIDS];
 +static SFontSettings s_rgFontSettingsMiranda[FLT_FONTIDS];
 +
 +#define FLT_SAME_AS_NONE	((BYTE)0xFF)
 +#define FLT_SAME_AS_MIRANDA	((BYTE)0xFE)
 +
 +static char* s_rgszFontSizes[] = {"8","10","14","16","18","20","24","28"};
 +
 +static const TCHAR* s_rgszFontIdDescr[FLT_FONTIDS]  = 
 +{
 +	_T("Standard contacts"),
 +	_T("Online contacts to whom you have a different visibility"),
 +	_T("Offline contacts"),
 +	_T("Offline contacts to whom you have a different visibility"),
 +	_T("Contacts which are 'not on list'"),
 +};
 +
 +static WORD s_rgwFontSameAsDefault[FLT_FONTIDS]  = 
 +{
 +	MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F),
 +	MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F),
 +	MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F),
 +	MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F),
 +	MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F),
 +};
 +
 +static int s_rgnMirandaFontId[FLT_FONTIDS]  = 
 +{
 +	FONTID_CONTACTS,
 +	FONTID_INVIS,
 +	FONTID_OFFLINE,
 +	FONTID_OFFINVIS,
 +	FONTID_NOTONLIST
 +};
 +
 +#define M_REBUILDFONTGROUP		(WM_USER + 10)
 +#define M_REMAKESAMPLE			(WM_USER + 11)
 +#define M_RECALCONEFONT			(WM_USER + 12)
 +#define M_RECALCOTHERFONTS		(WM_USER + 13)
 +#define M_SAVEFONT				(WM_USER + 14)
 +#define M_REFRESHSAMEASBOXES	(WM_USER + 15)
 +#define M_FILLSCRIPTCOMBO		(WM_USER + 16)
 +#define M_LOADFONT				(WM_USER + 17)
 +#define M_GUESSSAMEASBOXES		(WM_USER + 18)
 +#define M_SETSAMEASBOXES		(WM_USER + 19)
 +
 +#define M_REFRESHBKGBOXES		(WM_USER + 20)
 +#define M_REFRESHBORDERPICKERS	(WM_USER + 21)
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +static
 +LRESULT
 +APIENTRY
 +OptWndProc
 +	( IN HWND hwndDlg
 +	, IN UINT uMsg
 +	, IN WPARAM wParam
 +	, IN LPARAM lParam
 +	);
 +
 +static
 +LRESULT
 +APIENTRY
 +OptSknWndProc
 +	( IN HWND hwndDlg
 +	, IN UINT uMsg
 +	, IN WPARAM wParam
 +	, IN LPARAM lParam
 +	);
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +int
 +OnOptionsInitialize
 +	( IN WPARAM wParam
 +	, IN LPARAM lParam
 +	)
 +{
 +	OPTIONSDIALOGPAGE odp = { 0 };
 +	odp.cbSize      =  sizeof(odp);
 +	odp.hInstance   =  hInst;
 +	odp.pszTemplate =  MAKEINTRESOURCEA(IDD_OPT_FLTCONT);
 +	odp.pszTitle    =  LPGEN("Floating Contacts");
 +	odp.pszGroup    =  LPGEN("Plugins");
 +	odp.pszTab      =  LPGEN("Main Features");
 +	odp.flags       =  ODPF_BOLDGROUPS;
 +	odp.pfnDlgProc  =  (DLGPROC)OptWndProc;
 +	Options_AddPage(wParam, &odp);
 +
 +	odp.pszTemplate =  MAKEINTRESOURCEA(IDD_OPT_SKIN);
 +	odp.pszTab      =  LPGEN("Appearance");
 +	odp.pfnDlgProc  =  (DLGPROC)OptSknWndProc;
 +	Options_AddPage(wParam, &odp);
 +
 +	return 0;
 +}
 +
 +static
 +int
 +CALLBACK
 +EnumFontsProc
 +	( IN ENUMLOGFONTEXA* lpelfe
 +	, IN NEWTEXTMETRICEXA* lpntme
 +	, IN int FontType
 +	, IN LPARAM lParam
 +	)
 +{
 +	if (IsWindow((HWND)lParam))
 +	{
 +		if (CB_ERR == SendMessageA((HWND)lParam, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)lpelfe->elfLogFont.lfFaceName))
 +			SendMessageA((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)lpelfe->elfLogFont.lfFaceName);
 +		return TRUE;
 +	}
 +	return FALSE;
 +}
 +
 +void
 +FillFontListThread
 +	( IN HWND hwndDlg
 +	)
 +{
 +	LOGFONTA lf = {0};
 +	HDC hdc = GetDC(hwndDlg);
 +
 +	lf.lfCharSet		 =  DEFAULT_CHARSET;
 +	lf.lfFaceName[0]	 =  0;
 +	lf.lfPitchAndFamily	 =  0;
 +	EnumFontFamiliesExA(hdc, &lf, (FONTENUMPROCA)EnumFontsProc, (LPARAM)GetDlgItem(hwndDlg,IDC_TYPEFACE), 0);
 +	ReleaseDC(hwndDlg, hdc);
 +	return;
 +}
 +
 +static
 +int
 +CALLBACK
 +EnumFontScriptsProc
 +	( IN ENUMLOGFONTEX* lpelfe
 +	, IN NEWTEXTMETRICEX* lpntme
 +	, IN int FontType
 +	, IN LPARAM lParam
 +	)
 +{
 +	if (CB_ERR == SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)lpelfe->elfScript))
 +	{
 +		int i = SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)lpelfe->elfScript);
 +		SendMessage((HWND)lParam, CB_SETITEMDATA, i, lpelfe->elfLogFont.lfCharSet);
 +	}
 +	return TRUE;
 +}
 +
 +static
 +void
 +GetDefaultFontSetting
 +	( IN BOOL bFltContacts
 +	, IN int nFontId
 +	, IN LOGFONTA* lf
 +	, IN COLORREF* colour
 +	)
 +{
 +	SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(LOGFONTA), lf, FALSE);
 +	*colour = GetSysColor(COLOR_WINDOWTEXT);
 +	if (bFltContacts)
 +	{
 +		switch (nFontId)
 +		{
 +		case FLT_FONTID_OFFINVIS:
 +		case FLT_FONTID_INVIS:
 +			lf->lfItalic = !lf->lfItalic;
 +			break;
 +
 +		case FLT_FONTID_NOTONLIST:
 +			*colour = GetSysColor(COLOR_3DSHADOW);
 +			break;
 +		}
 +	}
 +	else
 +	{
 +		switch (s_rgnMirandaFontId[nFontId])
 +		{
 +		case FONTID_OFFINVIS:
 +		case FONTID_INVIS:
 +			lf->lfItalic = !lf->lfItalic;
 +			break;
 +
 +		case FONTID_NOTONLIST:
 +			*colour = GetSysColor(COLOR_3DSHADOW);
 +			break;
 +		}
 +	}
 +}
 +
 +void
 +GetFontSetting
 +	( IN BOOL bFltContacts
 +	, IN int nFontId
 +	, IN LOGFONTA* lf
 +	, IN COLORREF* colour
 +	)
 +{
 +	DBVARIANT dbv;
 +	char idstr[10];
 +	BYTE style;
 +	const char* pModule = (bFltContacts ? sModule : "CLC");
 +
 +	GetDefaultFontSetting(bFltContacts, nFontId, lf, colour);
 +	if (!bFltContacts)
 +		nFontId = s_rgnMirandaFontId[nFontId];
 +	wsprintfA(idstr, "Font%dName", nFontId);
 +	if (!DBGetContactSetting(NULL, pModule, idstr, &dbv))
 +	{
 +		lstrcpyA(lf->lfFaceName, dbv.pszVal);
 +		DBFreeVariant(&dbv);
 +	}
 +
 +	wsprintfA(idstr, "Font%dCol", nFontId);
 +	*colour = DBGetContactSettingDword(NULL, pModule, idstr, *colour);
 +
 +	wsprintfA(idstr, "Font%dSize", nFontId);
 +	lf->lfHeight = (char)DBGetContactSettingByte(NULL, pModule, idstr, lf->lfHeight);
 +
 +	wsprintfA(idstr, "Font%dSty", nFontId);
 +	style = (BYTE)DBGetContactSettingByte(NULL, pModule, idstr
 +							, (lf->lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD)
 +								| (lf->lfItalic ? DBFONTF_ITALIC : 0)
 +								| (lf->lfUnderline ? DBFONTF_UNDERLINE : 0)
 +							);
 +	lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
 +	lf->lfWeight = ((style & DBFONTF_BOLD) ? FW_BOLD : FW_NORMAL);
 +	lf->lfItalic = (0 != (style & DBFONTF_ITALIC));
 +	lf->lfUnderline = (0 != (style & DBFONTF_UNDERLINE));
 +	lf->lfStrikeOut = 0;
 +
 +	wsprintfA(idstr, "Font%dSet", nFontId);
 +	lf->lfCharSet = (BYTE)DBGetContactSettingByte(NULL, pModule, idstr, lf->lfCharSet);
 +	lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
 +	lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
 +	lf->lfQuality = DEFAULT_QUALITY;
 +	lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
 +
 +	if (bFltContacts)
 +	{
 +		WORD wSameAs;
 +		BYTE bySameAs;
 +		BYTE bySameAsFlags;
 +
 +		wsprintfA(idstr, "Font%dAs", nFontId);
 +		wSameAs = (WORD)DBGetContactSettingWord(NULL, sModule, idstr, s_rgwFontSameAsDefault[nFontId]);
 +		bySameAs = LOBYTE(wSameAs);
 +		bySameAsFlags = HIBYTE(wSameAs);
 +
 +		if (FLT_SAME_AS_MIRANDA == bySameAs)
 +		{
 +			LOGFONTA lfMiranda;
 +			COLORREF colourMiranda;
 +
 +			GetFontSetting(FALSE, nFontId, &lfMiranda, &colourMiranda);
 +			if (bySameAsFlags & SAMEASF_FACE)
 +			{
 +				lstrcpyA(lf->lfFaceName, lfMiranda.lfFaceName);
 +				lf->lfCharSet = lfMiranda.lfCharSet;
 +			}
 +			if (bySameAsFlags & SAMEASF_SIZE)
 +				lf->lfHeight = lfMiranda.lfHeight;
 +			if (bySameAsFlags & SAMEASF_STYLE)
 +			{
 +				lf->lfWeight = lfMiranda.lfWeight;
 +				lf->lfItalic = lfMiranda.lfItalic;
 +				lf->lfUnderline = lfMiranda.lfUnderline;
 +			}
 +			if (bySameAsFlags & SAMEASF_COLOUR)
 +				*colour = colourMiranda;
 +		}
 +	}
 +}
 +
 +static
 +LRESULT
 +APIENTRY
 +OptWndProc
 +	( IN HWND hwndDlg
 +	, IN UINT uMsg
 +	, IN WPARAM wParam
 +	, IN LPARAM lParam
 +	)
 +{
 +	switch ( uMsg )
 +	{
 +		case WM_INITDIALOG:
 +		{
 +			TranslateDialogDefault(hwndDlg);
 +
 +			// Properties
 +			CheckDlgButton(hwndDlg, IDC_CHK_HIDE_OFFLINE, (fcOpt.bHideOffline ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_CHK_HIDE_ALL, (fcOpt.bHideAll ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_CHK_HIDE_WHEN_FULSCREEN, (fcOpt.bHideWhenFullscreen ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_CHK_STICK, (fcOpt.bMoveTogether ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_CHK_WIDTH, (fcOpt.bFixedWidth ? BST_CHECKED : BST_UNCHECKED));
 +			
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_WIDTH), fcOpt.bFixedWidth);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_WIDTH), fcOpt.bFixedWidth);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_WIDTHSPIN), fcOpt.bFixedWidth);
 +
 +			SendDlgItemMessage(hwndDlg, IDC_WIDTHSPIN, UDM_SETRANGE, 0, MAKELONG(255,0));
 +			SendDlgItemMessage(hwndDlg, IDC_WIDTHSPIN, UDM_SETPOS, 0, fcOpt.nThumbWidth);
 +
 +			CheckDlgButton(hwndDlg, IDC_CHK_TIP, (fcOpt.bShowTip ? BST_CHECKED : BST_UNCHECKED));
 +		
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_TIP), bEnableTip);
 +			
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN), bEnableTip && fcOpt.bShowTip);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN_CMT), bEnableTip && fcOpt.bShowTip);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TIMEIN), bEnableTip && fcOpt.bShowTip);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEINSPIN), bEnableTip && fcOpt.bShowTip);
 +
 +			SendDlgItemMessage(hwndDlg, IDC_TIMEINSPIN, UDM_SETRANGE, 0, MAKELONG(5000,0));
 +			SendDlgItemMessage(hwndDlg, IDC_TIMEINSPIN, UDM_SETPOS, 0, fcOpt.TimeIn);
 +
 +			CheckDlgButton(hwndDlg, IDC_CHK_TOTOP, (fcOpt.bToTop ? BST_CHECKED : BST_UNCHECKED));
 +
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TOTOP), fcOpt.bToTop);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TOTOPTIME), fcOpt.bToTop);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TOTOPTIMESPIN), fcOpt.bToTop);
 +
 +			SendDlgItemMessage(hwndDlg, IDC_TOTOPTIMESPIN, UDM_SETRANGE, 0, MAKELONG(TOTOPTIME_MAX,1));
 +			SendDlgItemMessage(hwndDlg, IDC_TOTOPTIMESPIN, UDM_SETPOS, 0, fcOpt.ToTopTime);
 +
 +			CheckDlgButton(hwndDlg, IDC_CHK_HIDE_WHEN_CLISTSHOW, (fcOpt.bHideWhenCListShow ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_CHK_SINGLECLK, (fcOpt.bUseSingleClick ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_CHK_SHOWIDLE, (fcOpt.bShowIdle ? BST_CHECKED : BST_UNCHECKED));
 +
 +			return TRUE;
 +		}
 +		case WM_COMMAND:
 +		{
 +			switch (LOWORD(wParam))
 +			{
 +				case IDC_CHK_WIDTH:
 +				{
 +					if (BN_CLICKED == HIWORD(wParam))
 +					{
 +						BOOL bChecked = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_WIDTH);
 +						
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_WIDTH ), bChecked);
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_WIDTH ), bChecked);
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_WIDTHSPIN), bChecked);
 +					}
 +					break;
 +				}
 +				case IDC_TXT_WIDTH:
 +				{
 +					if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus())
 +						return 0;
 +					break;
 +				}
 +				case IDC_CHK_TIP:
 +				{
 +					if (BN_CLICKED == HIWORD(wParam))
 +					{
 +						BOOL bChecked = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TIP);
 +						
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN ), bChecked);
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN_CMT ), bChecked);
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TIMEIN ), bChecked);
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEINSPIN), bChecked);
 +					}
 +					break;
 +				}
 +				case IDC_TXT_TIMEIN:
 +				{
 +					if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus())
 +						return 0;
 +					break;
 +				}
 +				case IDC_CHK_TOTOP:
 +				{
 +					if (BN_CLICKED == HIWORD(wParam))
 +					{
 +						BOOL bChecked = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TOTOP);
 +						
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TOTOP ), bChecked);
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TOTOPTIME ), bChecked);
 +						EnableWindow(GetDlgItem(hwndDlg, IDC_TOTOPTIMESPIN), bChecked);
 +					}
 +					break;
 +				}
 +				case IDC_TXT_TOTOPTIME:
 +				{
 +					if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus())
 +						return 0;
 +					break;
 +				}
 +			}
 +			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			break;
 +		}
 +		case WM_NOTIFY:
 +		{
 +			LPNMHDR phdr = (LPNMHDR)(lParam);
 +			
 +			if (0 == phdr->idFrom)
 +			{
 +				switch (phdr->code) 
 +				{
 +					case PSN_APPLY:
 +					{
 +						BOOL bSuccess = FALSE;
 +
 +						fcOpt.bHideOffline = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_OFFLINE);
 +						DBWriteContactSettingByte(NULL, sModule, "HideOffline", (BYTE)fcOpt.bHideOffline);
 +						
 +						fcOpt.bHideAll = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_ALL);
 +						DBWriteContactSettingByte(NULL, sModule, "HideAll", (BYTE)fcOpt.bHideAll);
 +						
 +						fcOpt.bHideWhenFullscreen = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_WHEN_FULSCREEN);
 +						DBWriteContactSettingByte(NULL, sModule, "HideWhenFullscreen", (BYTE)fcOpt.bHideWhenFullscreen);
 +						
 +						fcOpt.bMoveTogether = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_STICK);
 +						DBWriteContactSettingByte(NULL, sModule, "MoveTogether", (BYTE)fcOpt.bMoveTogether);
 +						
 +						fcOpt.bFixedWidth = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_WIDTH);
 +						DBWriteContactSettingByte(NULL, sModule, "FixedWidth", (BYTE)fcOpt.bFixedWidth);
 +						fcOpt.nThumbWidth	 =  GetDlgItemInt(hwndDlg, IDC_TXT_WIDTH, &bSuccess, FALSE);
 +						DBWriteContactSettingDword(NULL, sModule, "Width", fcOpt.nThumbWidth );
 +						
 +						if (bEnableTip)
 +						{
 +							fcOpt.bShowTip = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TIP);
 +							DBWriteContactSettingByte(NULL, sModule, "ShowTip", (BYTE)fcOpt.bShowTip);
 +							fcOpt.TimeIn	 =  GetDlgItemInt(hwndDlg, IDC_TXT_TIMEIN, &bSuccess, FALSE);
 +							DBWriteContactSettingWord(NULL, sModule, "TimeIn", fcOpt.TimeIn );
 +						}
 +
 +						fcOpt.bToTop = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TOTOP);
 +						DBWriteContactSettingByte(NULL, sModule, "ToTop", (BYTE)fcOpt.bToTop);
 +						fcOpt.ToTopTime	 =  GetDlgItemInt(hwndDlg, IDC_TXT_TOTOPTIME, &bSuccess, FALSE);
 +						DBWriteContactSettingWord(NULL, sModule, "ToTopTime", fcOpt.ToTopTime );
 +	
 +						fcOpt.bHideWhenCListShow = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_WHEN_CLISTSHOW);
 +						DBWriteContactSettingByte(NULL, sModule, "HideWhenCListShow", (BYTE)fcOpt.bHideWhenCListShow);
 +						
 +						fcOpt.bUseSingleClick = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_SINGLECLK);
 +						DBWriteContactSettingByte(NULL, sModule, "UseSingleClick", (BYTE)fcOpt.bUseSingleClick);
 +
 +						fcOpt.bShowIdle = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_SHOWIDLE);
 +						DBWriteContactSettingByte(NULL, sModule, "ShowIdle", (BYTE)fcOpt.bShowIdle);
 +
 +						ApplyOptionsChanges();
 +						OnStatusChanged();
 +						return TRUE;
 +					}
 +				}
 +			}
 +			break;
 +		}
 +	}
 +	return FALSE;
 +}
 +
 +static
 +LRESULT
 +APIENTRY
 +OptSknWndProc
 +	( IN HWND hwndDlg
 +	, IN UINT uMsg
 +	, IN WPARAM wParam
 +	, IN LPARAM lParam
 +	)
 +{
 +	static HFONT hFontSample;
 +
 +	switch ( uMsg )
 +	{
 +		case WM_INITDIALOG:
 +		{
 +			BYTE btOpacity;
 +			char szPercent[20];
 +
 +			TranslateDialogDefault(hwndDlg);
 +
 +			// Border
 +			CheckDlgButton(hwndDlg, IDC_DRAWBORDER
 +				, DBGetContactSettingByte(NULL, sModule, "DrawBorder", FLT_DEFAULT_DRAWBORDER)
 +					? BST_CHECKED : BST_UNCHECKED
 +				);
 +			SendMessage(hwndDlg, M_REFRESHBORDERPICKERS, 0, 0);
 +			SendDlgItemMessage(hwndDlg, IDC_LTEDGESCOLOR, CPM_SETDEFAULTCOLOUR, 0, FLT_DEFAULT_LTEDGESCOLOR);
 +			SendDlgItemMessage(hwndDlg, IDC_LTEDGESCOLOR, CPM_SETCOLOUR, 0
 +				, DBGetContactSettingDword(NULL, sModule, "LTEdgesColor", FLT_DEFAULT_LTEDGESCOLOR)
 +				);
 +			SendDlgItemMessage(hwndDlg, IDC_RBEDGESCOLOR, CPM_SETDEFAULTCOLOUR, 0, FLT_DEFAULT_RBEDGESCOLOR);
 +			SendDlgItemMessage(hwndDlg, IDC_RBEDGESCOLOR, CPM_SETCOLOUR, 0
 +				, DBGetContactSettingDword(NULL, sModule, "RBEdgesColor", FLT_DEFAULT_RBEDGESCOLOR)
 +				);
 +
 +			// Background
 +			CheckDlgButton(hwndDlg, IDC_CHK_WIDTH, (fcOpt.bFixedWidth ? BST_CHECKED : BST_UNCHECKED));
 +
 +			SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETDEFAULTCOLOUR, 0, FLT_DEFAULT_BKGNDCOLOR);
 +			SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETCOLOUR, 0
 +				, DBGetContactSettingDword(NULL, sModule, "BkColor", FLT_DEFAULT_BKGNDCOLOR)
 +				);
 +			CheckDlgButton(hwndDlg, IDC_BITMAP
 +				, DBGetContactSettingByte(NULL, sModule, "BkUseBitmap", FLT_DEFAULT_BKGNDUSEBITMAP)
 +					? BST_CHECKED : BST_UNCHECKED
 +				);
 +			SendMessage(hwndDlg, M_REFRESHBKGBOXES, 0, 0);
 +			{
 +				DBVARIANT dbv;
 +
 +				if (!DBGetContactSetting(NULL, sModule, "BkBitmap", &dbv))
 +				{
 +					SetDlgItemTextA(hwndDlg, IDC_FILENAME, dbv.pszVal);
 +					DBFreeVariant(&dbv);
 +				}
 +			}
 +			{
 +				WORD bmpUse = (WORD)DBGetContactSettingWord(NULL, sModule, "BkBitmapOpt", FLT_DEFAULT_BKGNDBITMAPOPT);
 +
 +				CheckDlgButton(hwndDlg, IDC_STRETCHH, ((bmpUse & CLB_STRETCHH) ? BST_CHECKED : BST_UNCHECKED));
 +				CheckDlgButton(hwndDlg, IDC_STRETCHV, ((bmpUse & CLB_STRETCHV) ? BST_CHECKED : BST_UNCHECKED));
 +				CheckDlgButton(hwndDlg, IDC_TILEH, ((bmpUse & CLBF_TILEH) ? BST_CHECKED : BST_UNCHECKED));
 +				CheckDlgButton(hwndDlg, IDC_TILEV, ((bmpUse & CLBF_TILEV) ? BST_CHECKED : BST_UNCHECKED));
 +				CheckDlgButton(hwndDlg, IDC_PROPORTIONAL, ((bmpUse & CLBF_PROPORTIONAL) ? BST_CHECKED : BST_UNCHECKED));
 +			}
 +			{
 +				HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD);
 +
 +				MySHAutoComplete = (HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandle(_T("shlwapi")), "SHAutoComplete");
 +				if (MySHAutoComplete)
 +					MySHAutoComplete(GetDlgItem(hwndDlg, IDC_FILENAME), 1);
 +			}
 +
 +			// Windows 2K/XP
 +			btOpacity = (BYTE)DBGetContactSettingByte(NULL, sModule, "Opacity", 100);
 +			SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_SETRANGE, TRUE, MAKELONG(0, 100));
 +			SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_SETPOS, TRUE, btOpacity);
 +				
 +			wsprintfA(szPercent, "%d%%", btOpacity);
 +			SetDlgItemTextA(hwndDlg, IDC_OPACITY, szPercent);
 +
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_SLIDER_OPACITY), (NULL != pSetLayeredWindowAttributes));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_OPACITY), (NULL != pSetLayeredWindowAttributes));
 +
 +			// Fonts
 +			hFontSample = NULL;
 +			SetDlgItemText(hwndDlg, IDC_SAMPLE, TranslateT("Sample"));
 +			FillFontListThread(hwndDlg);
 +			{
 +				int i;
 +				int itemId;
 +				LOGFONTA lf;
 +				COLORREF colour;
 +				WORD sameAs;
 +				char str[32];
 +
 +				for (i = 0; i < FLT_FONTIDS; i++)
 +				{
 +					// Floating contacts fonts
 +					GetFontSetting(TRUE, i, &lf, &colour);
 +					wsprintfA(str, "Font%dAs", i);
 +					sameAs = (WORD)DBGetContactSettingWord(NULL, sModule, str, s_rgwFontSameAsDefault[i]);
 +					s_rgFontSettings[i].sameAs = LOBYTE(sameAs);
 +					s_rgFontSettings[i].sameAsFlags = HIBYTE(sameAs);
 +					s_rgFontSettings[i].style = (FW_NORMAL == lf.lfWeight? 0 : DBFONTF_BOLD)
 +													| (lf.lfItalic ? DBFONTF_ITALIC : 0)
 +													| (lf.lfUnderline ? DBFONTF_UNDERLINE : 0);
 +					if (lf.lfHeight < 0)
 +					{
 +						HDC hdc;
 +						SIZE size;
 +						HFONT hFont = CreateFontIndirectA(&lf);
 +
 +						hdc = GetDC(hwndDlg);
 +						SelectObject(hdc, hFont);
 +						GetTextExtentPoint32A(hdc, "x", 1, &size);
 +						ReleaseDC(hwndDlg, hdc);
 +						DeleteObject(hFont);
 +						s_rgFontSettings[i].size = (char)size.cy;
 +					}
 +					else
 +						s_rgFontSettings[i].size = (char)lf.lfHeight;
 +					s_rgFontSettings[i].charset = lf.lfCharSet;
 +					s_rgFontSettings[i].colour = colour;
 +					lstrcpyA(s_rgFontSettings[i].szFace, lf.lfFaceName);
 +					itemId = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_ADDSTRING, 0, (LPARAM)TranslateTS(s_rgszFontIdDescr[i]));
 +					SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_SETITEMDATA, itemId, i);
 +
 +					// Miranda contact list fonts
 +					GetFontSetting(FALSE, i, &lf, &colour);
 +					s_rgFontSettingsMiranda[i].sameAs = 0;
 +					s_rgFontSettingsMiranda[i].sameAsFlags = 0;
 +					lstrcpyA(s_rgFontSettingsMiranda[i].szFace, lf.lfFaceName);
 +					s_rgFontSettingsMiranda[i].charset = lf.lfCharSet;
 +					s_rgFontSettingsMiranda[i].style = (FW_NORMAL == lf.lfWeight? 0 : DBFONTF_BOLD)
 +															| (lf.lfItalic ? DBFONTF_ITALIC : 0)
 +															| (lf.lfUnderline ? DBFONTF_UNDERLINE : 0);
 +					if (lf.lfHeight < 0)
 +					{
 +						HDC hdc;
 +						SIZE size;
 +						HFONT hFont = CreateFontIndirectA(&lf);
 +
 +						hdc = GetDC(hwndDlg);
 +						SelectObject(hdc, hFont);
 +						GetTextExtentPoint32A(hdc, "x", 1, &size);
 +						ReleaseDC(hwndDlg, hdc);
 +						DeleteObject(hFont);
 +						s_rgFontSettingsMiranda[i].size = (char)size.cy;
 +					}
 +					else
 +						s_rgFontSettingsMiranda[i].size = (char)lf.lfHeight;
 +					s_rgFontSettingsMiranda[i].colour = colour;
 +				}
 +				SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_SETCURSEL, 0, 0);
 +				for (i = 0; i < sizeof(s_rgszFontSizes)/sizeof(s_rgszFontSizes[0]); i++)
 +					SendDlgItemMessageA(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)s_rgszFontSizes[i]);
 +			}
 +			SendMessage(hwndDlg, M_REBUILDFONTGROUP, 0, 0);
 +			SendMessage(hwndDlg, M_SAVEFONT, 0, 0);
 +			return TRUE;
 +		}
 +		case M_REFRESHBKGBOXES:
 +		{
 +			BOOL bEnable = IsDlgButtonChecked(hwndDlg, IDC_BITMAP);
 +
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), bEnable);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), bEnable);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_STRETCHH), bEnable);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_STRETCHV), bEnable);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TILEH), bEnable);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TILEV), bEnable);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_PROPORTIONAL), bEnable);
 +			break;
 +		}
 +		case M_REFRESHBORDERPICKERS:
 +		{
 +			BOOL bEnable = IsDlgButtonChecked(hwndDlg, IDC_DRAWBORDER);
 +
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_LTEDGESCOLOR), bEnable);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_RBEDGESCOLOR), bEnable);
 +			break;
 +		}
 +		// remake all the needed controls when the user changes the font selector at the top
 +		case M_REBUILDFONTGROUP:
 +		{
 +			int i = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETCURSEL, 0, 0);
 +			int j;
 +			int itemId;
 +			int nSameAs = FLT_SAME_AS_NONE;
 +			char szText[256];
 +
 +			SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_RESETCONTENT, 0, 0);
 +			itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM)TranslateT("<none>"));
 +			SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, FLT_SAME_AS_NONE);
 +			SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0);
 +			itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM)TranslateT("<Contact List Text>"));
 +			SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, FLT_SAME_AS_MIRANDA);
 +			if (FLT_SAME_AS_MIRANDA == s_rgFontSettings[i].sameAs)
 +			{
 +				SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0);
 +				nSameAs = FLT_SAME_AS_MIRANDA;
 +			}
 +			for (j = 0; j < FLT_FONTIDS; j++)
 +			{
 +				int nDependsOn = j;
 +
 +				while (nDependsOn != i)
 +				{
 +					if (FLT_SAME_AS_NONE == nDependsOn || FLT_SAME_AS_MIRANDA == nDependsOn)
 +					{
 +						SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETLBTEXT, j, (LPARAM)szText);
 +						itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM)szText);
 +						SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, j);
 +						if (j == s_rgFontSettings[i].sameAs)
 +						{
 +							SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0);
 +							nSameAs = j;
 +						}
 +						break;
 +					}
 +					else
 +						nDependsOn = s_rgFontSettings[nDependsOn].sameAs;
 +				}
 +			}
 +			if (FLT_SAME_AS_NONE == nSameAs)
 +				s_rgFontSettings[i].sameAsFlags = 0;
 +
 +			SendMessage(hwndDlg, M_LOADFONT, i, 0);
 +			SendMessage(hwndDlg, M_SETSAMEASBOXES, i, 0);
 +			SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, i, 0);
 +			SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0);
 +			break;
 +		}
 +		//fill the script combo box and set the selection to the value for fontid wParam
 +		case M_FILLSCRIPTCOMBO:
 +		{	
 +			int i;
 +			HDC hdc = GetDC(hwndDlg);
 +			LOGFONT lf = {0};
 +
 +			lf.lfCharSet = DEFAULT_CHARSET;
 +			lf.lfPitchAndFamily = 0;
 +			GetDlgItemText(hwndDlg, IDC_TYPEFACE, lf.lfFaceName, sizeof(lf.lfFaceName));
 +			SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_RESETCONTENT, 0, 0);
 +			EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontScriptsProc, (LPARAM)GetDlgItem(hwndDlg, IDC_SCRIPT), 0);
 +			ReleaseDC(hwndDlg, hdc);
 +			for (i = SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCOUNT, 0, 0) - 1; i >= 0; i--)
 +			{
 +				if (SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, i, 0) == s_rgFontSettings[wParam].charset)
 +				{
 +					SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, i, 0);
 +					break;
 +				}
 +			}
 +			if (i < 0)
 +				SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, 0, 0);
 +			break;
 +		}
 +		// set the check mark in the 'same as' boxes to the right value for fontid wParam
 +		case M_SETSAMEASBOXES:
 +		{
 +			CheckDlgButton(hwndDlg, IDC_SAMETYPE, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_SAMESIZE, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_SIZE ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_SAMESTYLE, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_SAMECOLOUR, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_COLOUR ? BST_CHECKED : BST_UNCHECKED));
 +			break;
 +		}
 +		// set the disabled flag on the 'same as' checkboxes to the values for fontid wParam
 +		case M_REFRESHSAMEASBOXES:
 +		{
 +			BOOL bSameAsNone = (FLT_SAME_AS_NONE == s_rgFontSettings[wParam].sameAs);
 +
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_SAMETYPE), !bSameAsNone);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_SAMESIZE), !bSameAsNone);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_SAMESTYLE), !bSameAsNone);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_SAMECOLOUR), !bSameAsNone);
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEFACE), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_SCRIPT), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_FONTSIZE), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_SIZE));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_BOLD), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_ITALIC), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_UNDERLINE), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE));
 +			EnableWindow(GetDlgItem(hwndDlg, IDC_COLOUR), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_COLOUR));
 +			break;
 +		}
 +		// remake the sample edit box font based on the settings in the controls
 +		case M_REMAKESAMPLE:
 +		{
 +			LOGFONTA lf;
 +
 +			if (hFontSample)
 +			{
 +				SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDC_FONTID, WM_GETFONT, 0, 0), 0);
 +				DeleteObject(hFontSample);
 +			}
 +			lf.lfHeight = GetDlgItemInt(hwndDlg, IDC_FONTSIZE, NULL, FALSE);
 +			{
 +				HDC hdc = GetDC(NULL);				
 +				lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
 +				ReleaseDC(NULL,hdc);				
 +			}
 +			lf.lfWidth = 0;
 +			lf.lfEscapement = 0;
 +			lf.lfOrientation = 0;
 +			lf.lfWeight = (IsDlgButtonChecked(hwndDlg, IDC_BOLD) ? FW_BOLD : FW_NORMAL);
 +			lf.lfItalic = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ITALIC);
 +			lf.lfUnderline = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE);
 +			lf.lfStrikeOut = 0;
 +			lf.lfCharSet = (BYTE)SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCURSEL, 0, 0), 0);
 +			lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
 +			lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
 +			lf.lfQuality = DEFAULT_QUALITY;
 +			lf.lfPitchAndFamily = (DEFAULT_PITCH | FF_DONTCARE);
 +			GetDlgItemTextA(hwndDlg, IDC_TYPEFACE, lf.lfFaceName, sizeof(lf.lfFaceName));
 +			if (NULL != (hFontSample = CreateFontIndirectA(&lf)))
 +				SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, (WPARAM)hFontSample, TRUE);
 +			break;
 +		}
 +		// copy the 'same as' settings for fontid wParam from their sources
 +		case M_RECALCONEFONT:
 +		{
 +			if (FLT_SAME_AS_NONE != s_rgFontSettings[wParam].sameAs)
 +			{
 +				SFontSettings* pSameAs = ((FLT_SAME_AS_MIRANDA == s_rgFontSettings[wParam].sameAs)
 +											? &s_rgFontSettingsMiranda[wParam]
 +											: &s_rgFontSettings[s_rgFontSettings[wParam].sameAs]
 +											);
 +
 +				if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE)
 +				{
 +					lstrcpyA(s_rgFontSettings[wParam].szFace, pSameAs->szFace);
 +					s_rgFontSettings[wParam].charset = pSameAs->charset;
 +				}
 +				if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_SIZE)
 +					s_rgFontSettings[wParam].size = pSameAs->size;
 +				if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE)
 +					s_rgFontSettings[wParam].style = pSameAs->style;
 +				if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_COLOUR)
 +					s_rgFontSettings[wParam].colour = pSameAs->colour;
 +			}
 +			break;
 +		}
 +		// recalculate the 'same as' settings for all fonts but wParam
 +		case M_RECALCOTHERFONTS:
 +		{	
 +			int nFont;
 +			int nDepth;
 +			int nRecalcedFonts = 1;
 +			int nRecalcDepth;
 +			int nFontId = (int)wParam;
 +			int nSameAs;
 +
 +			for (nRecalcDepth = 0; nRecalcedFonts < FLT_FONTIDS && nRecalcDepth < FLT_FONTIDS; nRecalcDepth++)
 +			{
 +				for (nFont = 0; nFont < FLT_FONTIDS; nFont++)
 +				{
 +					if (nFontId == nFont)
 +						continue;
 +
 +					nSameAs = s_rgFontSettings[nFont].sameAs;
 +					for (nDepth = 0; nDepth < nRecalcDepth; nDepth++)
 +					{
 +						if (FLT_SAME_AS_NONE == nSameAs || FLT_SAME_AS_MIRANDA == nSameAs || nFontId == nSameAs)
 +							break;
 +
 +						nSameAs = s_rgFontSettings[nSameAs].sameAs;
 +					}
 +					if (nDepth == nRecalcDepth)
 +					{
 +						if (nFontId == nSameAs)
 +						{
 +							SendMessage(hwndDlg, M_RECALCONEFONT, nFont, 0);
 +							nRecalcedFonts++;
 +						}
 +						else if (FLT_SAME_AS_NONE == nSameAs || FLT_SAME_AS_MIRANDA == nSameAs)
 +							nRecalcedFonts++;
 +					}
 +				}
 +			}
 +			break;
 +		}
 +		//save the font settings from the controls to font wParam
 +		case M_SAVEFONT:
 +		{
 +			s_rgFontSettings[wParam].sameAsFlags = (IsDlgButtonChecked(hwndDlg, IDC_SAMETYPE) ? SAMEASF_FACE : 0)
 +													| (IsDlgButtonChecked(hwndDlg, IDC_SAMESIZE) ? SAMEASF_SIZE : 0)
 +													| (IsDlgButtonChecked(hwndDlg, IDC_SAMESTYLE) ? SAMEASF_STYLE : 0)
 +													| (IsDlgButtonChecked(hwndDlg, IDC_SAMECOLOUR) ? SAMEASF_COLOUR : 0);
 +			s_rgFontSettings[wParam].sameAs = (BYTE)SendDlgItemMessage(hwndDlg
 +														, IDC_SAMEAS
 +														, CB_GETITEMDATA
 +														, SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETCURSEL, 0, 0)
 +														, 0
 +														);
 +			GetDlgItemTextA(hwndDlg, IDC_TYPEFACE, s_rgFontSettings[wParam].szFace, sizeof(s_rgFontSettings[wParam].szFace));
 +			s_rgFontSettings[wParam].charset = (BYTE)SendDlgItemMessage(hwndDlg
 +														, IDC_SCRIPT
 +														, CB_GETITEMDATA
 +														, SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCURSEL, 0, 0)
 +														, 0
 +														);
 +			s_rgFontSettings[wParam].size = (char)GetDlgItemInt(hwndDlg, IDC_FONTSIZE, NULL, FALSE);
 +			s_rgFontSettings[wParam].style =  (IsDlgButtonChecked(hwndDlg, IDC_BOLD) ? DBFONTF_BOLD : 0)
 +												| (IsDlgButtonChecked(hwndDlg, IDC_ITALIC) ? DBFONTF_ITALIC : 0)
 +												| (IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE) ? DBFONTF_UNDERLINE : 0);
 +			s_rgFontSettings[wParam].colour = SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_GETCOLOUR, 0, 0);
 +			break;
 +		}
 +		// load font wParam into the controls
 +		case M_LOADFONT:
 +		{
 +			LOGFONTA lf;
 +			COLORREF colour;
 +
 +			SetDlgItemTextA(hwndDlg, IDC_TYPEFACE, s_rgFontSettings[wParam].szFace);
 +			SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, wParam, 0);
 +			SetDlgItemInt(hwndDlg, IDC_FONTSIZE, s_rgFontSettings[wParam].size, FALSE);
 +			CheckDlgButton(hwndDlg, IDC_BOLD, ((s_rgFontSettings[wParam].style & DBFONTF_BOLD) ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_ITALIC, ((s_rgFontSettings[wParam].style & DBFONTF_ITALIC) ? BST_CHECKED : BST_UNCHECKED));
 +			CheckDlgButton(hwndDlg, IDC_UNDERLINE, ((s_rgFontSettings[wParam].style & DBFONTF_UNDERLINE) ? BST_CHECKED : BST_UNCHECKED));
 +			GetDefaultFontSetting(TRUE, wParam, &lf, &colour);
 +			SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_SETDEFAULTCOLOUR, 0, colour);
 +			SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_SETCOLOUR, 0, s_rgFontSettings[wParam].colour);
 +			break;
 +		}
 +		// guess suitable values for the 'same as' checkboxes for fontId wParam
 +		case M_GUESSSAMEASBOXES:
 +		{
 +			s_rgFontSettings[wParam].sameAsFlags = 0;
 +			if (FLT_SAME_AS_NONE != s_rgFontSettings[wParam].sameAs)
 +			{
 +				SFontSettings* pSameAs = ((FLT_SAME_AS_MIRANDA == s_rgFontSettings[wParam].sameAs)
 +											? &s_rgFontSettingsMiranda[wParam]
 +											: &s_rgFontSettings[s_rgFontSettings[wParam].sameAs]
 +											);
 +
 +				if (!lstrcmpA(s_rgFontSettings[wParam].szFace, pSameAs->szFace) && s_rgFontSettings[wParam].charset == pSameAs->charset)
 +    				s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_FACE;
 +				if (s_rgFontSettings[wParam].size == pSameAs->size)
 +    				s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_SIZE;
 +				if (s_rgFontSettings[wParam].style == pSameAs->style)
 +    				s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_STYLE;
 +				if (s_rgFontSettings[wParam].colour == pSameAs->colour)
 +    				s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_COLOUR;
 +				SendMessage(hwndDlg,M_SETSAMEASBOXES,wParam,0);
 +			}
 +			break;
 +		}
 +		case WM_CTLCOLORSTATIC:
 +		{
 +			if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SAMPLE))
 +			{
 +				SetTextColor((HDC)wParam, SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_GETCOLOUR, 0, 0));
 +				SetBkColor((HDC)wParam, GetSysColor(COLOR_3DFACE));
 +				return (BOOL)GetSysColorBrush(COLOR_3DFACE);
 +			}
 +			break;
 +		}
 +		case WM_HSCROLL:
 +		{
 +			if (wParam != TB_ENDTRACK)
 +			{
 +				int nPos;
 +				char szPercent[20];
 +
 +				nPos = (BYTE)SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_GETPOS, 0, 0);
 +				fcOpt.thumbAlpha	 =  (BYTE)(( nPos * 255 ) / 100 );
 +				SetThumbsOpacity(fcOpt.thumbAlpha);
 +				
 +				wsprintfA(szPercent, "%d%%", nPos);
 +				SetDlgItemTextA(hwndDlg, IDC_OPACITY, szPercent);
 +				SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			}
 +			break;
 +		}
 +		case WM_COMMAND:
 +		{
 +			int nFontId = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETITEMDATA
 +								, SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETCURSEL, 0, 0)
 +								, 0
 +								);
 +
 +			switch (LOWORD(wParam))
 +			{
 +				case IDC_DRAWBORDER:
 +				{
 +					SendMessage(hwndDlg, M_REFRESHBORDERPICKERS, 0, 0);
 +					break;
 +				}
 +				case IDC_BROWSE:
 +				{
 +					char str[MAX_PATH];
 +					OPENFILENAMEA ofn = {0};
 +					char filter[512];
 +
 +					GetDlgItemTextA(hwndDlg, IDC_FILENAME, str, sizeof(str));
 +					ofn.lStructSize = sizeof(OPENFILENAMEA);
 +					ofn.hwndOwner = hwndDlg;
 +					ofn.hInstance = NULL;
 +					CallService(MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof(filter), (LPARAM)filter);
 +					ofn.lpstrFilter = filter;
 +					ofn.lpstrFile = str;
 +					ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
 +					ofn.nMaxFile = sizeof(str);
 +					ofn.nMaxFileTitle = MAX_PATH;
 +					ofn.lpstrDefExt = "bmp";
 +					if (!GetOpenFileNameA(&ofn))
 +						return FALSE;
 +					SetDlgItemTextA(hwndDlg, IDC_FILENAME, str);
 +					break;
 +				}
 +				case IDC_FILENAME:
 +				{
 +					if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus())
 +						return FALSE;
 +					break;
 +				}
 +				case IDC_BITMAP:
 +				{
 +					SendMessage(hwndDlg, M_REFRESHBKGBOXES, 0, 0);
 +					break;
 +				}
 +				case IDC_FONTID:
 +				{
 +					if (CBN_SELCHANGE == HIWORD(wParam))
 +						SendMessage(hwndDlg, M_REBUILDFONTGROUP, 0, 0);
 +					return FALSE;
 +				}
 +				case IDC_SAMETYPE:
 +				case IDC_SAMESIZE:
 +				case IDC_SAMESTYLE:
 +				case IDC_SAMECOLOUR:
 +				{
 +					SendMessage(hwndDlg, M_SAVEFONT, nFontId, 0);
 +					SendMessage(hwndDlg, M_RECALCONEFONT, nFontId, 0);
 +					SendMessage(hwndDlg, M_RECALCOTHERFONTS, nFontId, 0);
 +					SendMessage(hwndDlg, M_LOADFONT, nFontId, 0);
 +					SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, nFontId, 0);
 +					SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0);
 +					break;
 +				}
 +				case IDC_SAMEAS:
 +				{
 +					if (CBN_SELCHANGE != HIWORD(wParam))
 +						return FALSE;
 +					SendMessage(hwndDlg, M_SAVEFONT, nFontId, 0);
 +					SendMessage(hwndDlg, M_GUESSSAMEASBOXES, nFontId, 0);
 +					SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, nFontId, 0);
 +					break;
 +				}
 +				case IDC_TYPEFACE:
 +				case IDC_SCRIPT:
 +				case IDC_FONTSIZE:
 +				{
 +					if (CBN_EDITCHANGE != HIWORD(wParam) && CBN_SELCHANGE != HIWORD(wParam))
 +						return FALSE;
 +					if (CBN_SELCHANGE == HIWORD(wParam))
 +						SendDlgItemMessage(hwndDlg, LOWORD(wParam), CB_SETCURSEL, SendDlgItemMessage(hwndDlg, LOWORD(wParam), CB_GETCURSEL, 0, 0), 0);
 +					if (IDC_TYPEFACE == LOWORD(wParam))
 +						SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, nFontId, 0);
 +					// FALL THRU
 +				}
 +				case IDC_BOLD:
 +				case IDC_ITALIC:
 +				case IDC_UNDERLINE:
 +				case IDC_COLOUR:
 +				{
 +					SendMessage(hwndDlg, M_SAVEFONT, nFontId, 0);
 +					//SendMessage(hwndDlg, M_GUESSSAMEASBOXES, nFontId, 0);
 +					//SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, nFontId, 0);
 +					SendMessage(hwndDlg, M_RECALCOTHERFONTS, nFontId, 0);
 +					SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0);
 +					break;
 +				}
 +				case IDC_SAMPLE:
 +					return 0;
 +			}
 +			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
 +			break;
 +		}
 +		case WM_NOTIFY:
 +		{
 +			LPNMHDR phdr = (LPNMHDR)(lParam);
 +			
 +			if (0 == phdr->idFrom)
 +			{
 +				switch (phdr->code) 
 +				{
 +					case PSN_APPLY:
 +					{
 +						int i;
 +						char str[20];
 +						//BOOL bSuccess = FALSE;
 +
 +						// Border
 +						DBWriteContactSettingByte(NULL, sModule, "DrawBorder", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DRAWBORDER));
 +						{	
 +							COLORREF col;
 +
 +							col = SendDlgItemMessage(hwndDlg, IDC_LTEDGESCOLOR, CPM_GETCOLOUR, 0, 0);
 +							DBWriteContactSettingDword(NULL, sModule, "LTEdgesColor", col);
 +							col = SendDlgItemMessage(hwndDlg, IDC_RBEDGESCOLOR, CPM_GETCOLOUR, 0, 0);
 +							DBWriteContactSettingDword(NULL, sModule, "RBEdgesColor", col);
 +						}
 +
 +						// Backgroud
 +						{	
 +							COLORREF col;
 +
 +							col = SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0);
 +							DBWriteContactSettingDword(NULL, sModule, "BkColor", col);
 +						}
 +						DBWriteContactSettingByte(NULL, sModule, "BkUseBitmap", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_BITMAP));
 +						{	
 +							char str[MAX_PATH];
 +
 +							GetDlgItemTextA(hwndDlg, IDC_FILENAME, str, sizeof(str));
 +							DBWriteContactSettingString(NULL, sModule, "BkBitmap", str);
 +						}
 +						{
 +							WORD flags = 0;
 +
 +							if (IsDlgButtonChecked(hwndDlg, IDC_STRETCHH))
 +								flags |= CLB_STRETCHH;
 +							if (IsDlgButtonChecked(hwndDlg, IDC_STRETCHV))
 +								flags |= CLB_STRETCHV;
 +							if (IsDlgButtonChecked(hwndDlg, IDC_TILEH))
 +								flags |= CLBF_TILEH;
 +							if (IsDlgButtonChecked(hwndDlg, IDC_TILEV))
 +								flags |= CLBF_TILEV;
 +							if (IsDlgButtonChecked(hwndDlg, IDC_PROPORTIONAL))
 +								flags |= CLBF_PROPORTIONAL;
 +							DBWriteContactSettingWord(NULL, sModule, "BkBitmapOpt", flags);
 +						}
 +
 +						DBWriteContactSettingByte(NULL, sModule, "Opacity"
 +							, (BYTE)SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_GETPOS, 0, 0)
 +							);
 +
 +						for (i = 0; i < FLT_FONTIDS; i++)
 +						{
 +							wsprintfA(str, "Font%dName", i);
 +							DBWriteContactSettingString(NULL, sModule, str, s_rgFontSettings[i].szFace);
 +							wsprintfA(str, "Font%dSet", i);
 +							DBWriteContactSettingByte(NULL, sModule, str, s_rgFontSettings[i].charset);
 +							wsprintfA(str, "Font%dSize", i);
 +							DBWriteContactSettingByte(NULL, sModule, str, s_rgFontSettings[i].size);
 +							wsprintfA(str, "Font%dSty", i);
 +							DBWriteContactSettingByte(NULL, sModule, str, s_rgFontSettings[i].style);
 +							wsprintfA(str, "Font%dCol", i);
 +							DBWriteContactSettingDword(NULL, sModule, str, s_rgFontSettings[i].colour);
 +							wsprintfA(str, "Font%dAs", i);
 +							DBWriteContactSettingWord(NULL, sModule, str, MAKEWORD(s_rgFontSettings[i].sameAs, s_rgFontSettings[i].sameAsFlags));
 +						}
 +
 +						ApplyOptionsChanges();
 +						OnStatusChanged();
 +						return TRUE;
 +					}
 +					case PSN_RESET:
 +					//case PSN_KILLACTIVE:
 +					{
 +						fcOpt.thumbAlpha = (BYTE)((double)DBGetContactSettingByte(NULL, sModule, "Opacity", 100) * 2.55);
 +						SetThumbsOpacity(fcOpt.thumbAlpha);
 +						break;
 +					}
 +				}
 +			}
 +			break;
 +		}
 +		case WM_DESTROY:
 +		{
 +			if (hFontSample)
 +			{
 +				SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDC_FONTID, WM_GETFONT, 0, 0), 0);
 +				DeleteObject(hFontSample);
 +			}
 +			break;
 +		}
 +
 +	}
 +	return FALSE;
 +}
 +
 diff --git a/plugins/FloatingContacts/src/resource.h b/plugins/FloatingContacts/src/resource.h new file mode 100644 index 0000000000..fec93538d8 --- /dev/null +++ b/plugins/FloatingContacts/src/resource.h @@ -0,0 +1,75 @@ +//{{NO_DEPENDENCIES}}
 +// Microsoft Visual C++ generated include file.
 +// Used by Script.rc
 +//
 +#define IDD_OPT_FLTCONT                 101
 +#define IDI_ICON1                       103
 +#define IDI_HIDE                        103
 +#define IDI_SHOW                        105
 +#define IDD_OPT_FNT                     106
 +#define IDD_OPT_SKIN                    106
 +#define IDC_SLIDER_OPACITY              1001
 +#define IDC_OPACITY                     1002
 +#define IDC_CHK_HIDE_OFFLINE            1003
 +#define IDC_CHK_STICK                   1004
 +#define IDC_CHK_WIDTH                   1005
 +#define IDC_LBL_WIDTH                   1006
 +#define IDC_TXT_WIDTH                   1007
 +#define IDC_WIDTHSPIN                   1008
 +#define IDC_TXT_TIMEIN                  1009
 +#define IDC_TIMEINSPIN                  1010
 +#define IDC_TXT_TOTOPTIME               1011
 +#define IDC_CHK_HIDE_ALL                1012
 +#define IDC_CHK_DEF_BACKGROUND          1013
 +#define IDC_TOTOPTIMESPIN               1013
 +#define IDC_CHK_HIDE_WHEN_FULSCREEN     1014
 +#define IDC_CHK_TIP                     1015
 +#define IDC_LBL_TIMEIN                  1016
 +#define IDC_CHK_TOTOP                   1017
 +#define IDC_LBL_TOTOP                   1018
 +#define IDC_CHK_HIDE_WHEN_CLISTSHOW     1019
 +#define IDC_CHECK1                      1020
 +#define IDC_CHK_SINGLECLK               1020
 +#define IDC_CHECK2                      1021
 +#define IDC_CHK_SHOWIDLE                1021
 +#define IDC_FONTID                      1100
 +#define IDC_SAMEAS                      1101
 +#define IDC_LBL_TIMEIN_CMT              1101
 +#define IDC_SAMETYPE                    1102
 +#define IDC_SAMESIZE                    1103
 +#define IDC_SAMESTYLE                   1104
 +#define IDC_SAMECOLOUR                  1105
 +#define IDC_TYPEFACE                    1106
 +#define IDC_SCRIPT                      1107
 +#define IDC_FONTSIZE                    1108
 +#define IDC_BOLD                        1109
 +#define IDC_ITALIC                      1110
 +#define IDC_UNDERLINE                   1111
 +#define IDC_COLOUR                      1112
 +#define IDC_SAMPLE                      1113
 +#define IDC_STSAMETEXT                  1114
 +#define IDC_STASTEXT                    1115
 +#define IDC_STHORZBAR                   1116
 +#define IDC_BKGCOLOUR                   1200
 +#define IDC_BITMAP                      1201
 +#define IDC_FILENAME                    1202
 +#define IDC_BROWSE                      1203
 +#define IDC_STRETCHH                    1204
 +#define IDC_STRETCHV                    1205
 +#define IDC_TILEH                       1206
 +#define IDC_TILEV                       1207
 +#define IDC_PROPORTIONAL                1208
 +#define IDC_DRAWBORDER                  1209
 +#define IDC_LTEDGESCOLOR                1210
 +#define IDC_RBEDGESCOLOR                1211
 +
 +// Next default values for new objects
 +// 
 +#ifdef APSTUDIO_INVOKED
 +#ifndef APSTUDIO_READONLY_SYMBOLS
 +#define _APS_NEXT_RESOURCE_VALUE        107
 +#define _APS_NEXT_COMMAND_VALUE         40001
 +#define _APS_NEXT_CONTROL_VALUE         1022
 +#define _APS_NEXT_SYMED_VALUE           101
 +#endif
 +#endif
 diff --git a/plugins/FloatingContacts/src/stdhdr.h b/plugins/FloatingContacts/src/stdhdr.h new file mode 100644 index 0000000000..03b671515f --- /dev/null +++ b/plugins/FloatingContacts/src/stdhdr.h @@ -0,0 +1,64 @@ +
 +#ifndef __STDHDR_H__
 +#define __STDHDR_H__
 +
 +// disable security warnings about "*_s" functions
 +#define _CRT_SECURE_NO_DEPRECATE
 +
 +// disable warnings about underscore in stdc functions
 +#pragma warning(disable: 4996)
 +
 +// Unreferenced formal parameter
 +#pragma warning(disable: 4100)
 +
 +#if _MSC_VER >= 1000
 +#pragma once
 +#endif // _MSC_VER >= 1000
 +
 +/////////////////////////////////////////////////////////////////////////////
 +//
 +
 +#define STRICT
 +
 +#include <windows.h>
 +#include <stdio.h>
 +#include <assert.h>
 +
 +#pragma warning ( disable : 4201 ) //nonstandard extension used : nameless struct/union
 +#include <commctrl.h>
 +
 +#define MIRANDA_VER 0x0A00
 +
 +#include <newpluginapi.h>
 +#include <m_system.h>
 +#include <m_system_cpp.h>
 +#include <m_skin.h>
 +#include <m_utils.h>
 +#include <m_langpack.h>
 +#include <m_protocols.h>
 +#include <m_protosvc.h>
 +#include <m_database.h>
 +#include <m_message.h>
 +//#include "../../include/msgs.h"
 +#include <m_file.h>
 +#include <m_clist.h>
 +#include <m_clui.h>
 +#include <m_options.h>
 +#include <m_clc.h>
 +//#include "../../include/clc.h"
 +#include <m_clistint.h>
 +#include <m_hotkeys.h>
 +
 +#include "bitmap_funcs.h"
 +
 +#include "fltcont.h"
 +#include "thumbs.h"
 +#include "filedrop.h"
 +#include "resource.h"
 +
 +/////////////////////////////////////////////////////////////////////////////
 +
 +#endif	// #ifndef __STDHDR_H__
 +
 +/////////////////////////////////////////////////////////////////////////////
 +// End Of File stdhdr.h
 diff --git a/plugins/FloatingContacts/src/thumbs.cpp b/plugins/FloatingContacts/src/thumbs.cpp new file mode 100644 index 0000000000..0195ff0717 --- /dev/null +++ b/plugins/FloatingContacts/src/thumbs.cpp @@ -0,0 +1,1013 @@ +#include "stdhdr.h"
 +#include "Wingdi.h"
 +
 +ThumbList thumbList;
 +
 +/////////////////////////////////////////////////////////////////////////////
 +// ThumbInfo
 +static POINT	ptOld;
 +static BOOL	bMouseDown		 =  FALSE;
 +static BOOL	bMouseIn		 =  FALSE;
 +static BOOL	bMouseMoved		 =  FALSE;
 +static short	nLeft			 =  0;
 +static short	nTop			 =  0;
 +static int		nOffs			 =  5;
 +static ThumbInfo *pThumbMouseIn	 =  NULL;
 +
 +static void SnapToScreen( RECT rcThumb, int nX, int nY, int *pX, int *pY )
 +{
 +	int nWidth;
 +	int nHeight;
 +
 +	assert( NULL != pX );
 +	assert( NULL != pY );
 +	
 +	nWidth	 =  rcThumb.right - rcThumb.left;
 +	nHeight = rcThumb.bottom - rcThumb.top;
 +
 +	*pX = nX < ( nOffs + rcScreen.left ) ? rcScreen.left : nX;
 +	*pY = nY < ( nOffs + rcScreen.top ) ? rcScreen.top : nY;
 +	*pX = *pX > ( rcScreen.right - nWidth - nOffs ) ? ( rcScreen.right - nWidth ) : *pX;
 +	*pY = *pY > ( rcScreen.bottom - nHeight - nOffs ) ? ( rcScreen.bottom - nHeight ) : *pY;
 +}
 +
 +ThumbInfo::ThumbInfo()
 +{
 +	dropTarget = new CDropTarget;
 +	dropTarget->AddRef();
 +	btAlpha = 255;
 +}
 +
 +ThumbInfo::~ThumbInfo()
 +{
 +	if (pThumbMouseIn == this){
 +		pThumbMouseIn = NULL;
 +		KillTimer(hwnd, TIMERID_LEAVE_T);
 +	}
 +	dropTarget->Release();
 +}
 +
 +void ThumbInfo::GetThumbRect(RECT *rc)
 +{
 +	rc->left = ptPos.x;
 +	rc->top = ptPos.y;
 +	rc->right = ptPos.x + szSize.cx;
 +	rc->bottom = ptPos.y + szSize.cy;
 +}
 +
 +void ThumbInfo::PositionThumb(short nX, short nY)
 +{
 +	POINT pos = { nX, nY };
 +	HDWP hdwp;
 +
 +	hdwp = BeginDeferWindowPos(1);
 +
 +	ThumbInfo *pThumb = this;
 +	while (pThumb)
 +	{
 +		pThumb->PositionThumbWorker( (short)pos.x, (short)pos.y, &pos );
 +
 +		DeferWindowPos(	hdwp,
 +						pThumb->hwnd, 
 +						HWND_TOPMOST, 
 +						pos.x, 
 +						pos.y, 
 +						0, 
 +						0,
 +						SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
 +
 +		pThumb->ptPos = pos;
 +		pos.x += pThumb->szSize.cx;
 +
 +		pThumb = fcOpt.bMoveTogether ? thumbList.FindThumb( pThumb->dockOpt.hwndRight ) : NULL;
 +	}
 +
 +	EndDeferWindowPos(hdwp);
 +}
 +
 +void ThumbInfo::PositionThumbWorker(short nX, short nY, POINT *newPos)
 +{
 +	RECT		rc;
 +	RECT		rcThumb;
 +	int			nNewX;
 +	int			nNewY;
 +	int			nWidth;
 +	int			nHeight;
 +	POINT		pt;
 +	RECT		rcLeft;
 +	RECT		rcTop;
 +	RECT		rcRight;
 +	RECT		rcBottom;
 +	BOOL		bDocked;
 +	BOOL		bDockedLeft;
 +	BOOL		bDockedRight;
 +	BOOL		bLeading;
 +
 +	// Get thumb dimnsions
 +	GetThumbRect( &rcThumb );
 +	nWidth	 =  rcThumb.right - rcThumb.left;
 +	nHeight = rcThumb.bottom - rcThumb.top;
 +
 +	// Docking and screen boundaries check
 +	SnapToScreen( rcThumb, nX, nY, &nNewX, &nNewY );
 +	
 +	bLeading = dockOpt.hwndRight != NULL;
 +
 +	if ( fcOpt.bMoveTogether )
 +	{
 +		UndockThumbs( this, thumbList.FindThumb( dockOpt.hwndLeft ));
 +	}
 +
 +
 +	for (int i = 0; i < thumbList.getCount(); ++i)
 +	{
 +		ThumbInfo	*pCurThumb	 =  thumbList[i];
 +
 +		if ( pCurThumb != this )
 +		{
 +			GetThumbRect( &rcThumb );
 +			OffsetRect( &rcThumb, nX - rcThumb.left, nY - rcThumb.top );
 +			
 +			pCurThumb->GetThumbRect( &rc );
 +
 +			// These are rects we will dock into
 +					
 +			rcLeft.left		 =  rc.left - nOffs;
 +			rcLeft.top		 =  rc.top - nOffs;
 +			rcLeft.right	 =  rc.left + nOffs;
 +			rcLeft.bottom	 =  rc.bottom + nOffs;
 +						
 +			rcTop.left		 =  rc.left - nOffs;
 +			rcTop.top		 =  rc.top - nOffs;
 +			rcTop.right		 =  rc.right + nOffs;
 +			rcTop.bottom	 =  rc.top + nOffs;
 +
 +			rcRight.left	 =  rc.right - nOffs;
 +			rcRight.top		 =  rc.top - nOffs;
 +			rcRight.right	 =  rc.right + nOffs;
 +			rcRight.bottom	 =  rc.bottom + nOffs;
 +
 +			rcBottom.left	 =  rc.left - nOffs;
 +			rcBottom.top	 =  rc.bottom - nOffs;
 +			rcBottom.right	 =  rc.right + nOffs;
 +			rcBottom.bottom = rc.bottom + nOffs;
 +
 +			
 +			bDockedLeft		 =  FALSE;
 +			bDockedRight	 =  FALSE;
 +
 +			// Upper-left
 +			pt.x	 =  rcThumb.left;
 +			pt.y	 =  rcThumb.top;
 +			bDocked	 =  FALSE;
 +			
 +			if ( PtInRect( &rcRight, pt ))
 +			{
 +				nNewX	 =  rc.right;
 +				bDocked = TRUE;
 +			}
 +			
 +			if ( PtInRect( &rcBottom, pt ))
 +			{
 +				nNewY = rc.bottom;
 +
 +				if ( PtInRect( &rcLeft, pt ))
 +				{
 +					nNewX = rc.left;
 +				}
 +			}
 +
 +			if ( PtInRect( &rcTop, pt ))
 +			{
 +				nNewY		 =  rc.top;
 +				bDockedLeft	 =  bDocked;
 +			}
 +			
 +			// Upper-right
 +			pt.x	 =  rcThumb.right;
 +			pt.y	 =  rcThumb.top;
 +			bDocked	 =  FALSE;
 +
 +			if ( !bLeading && PtInRect( &rcLeft, pt ))
 +			{
 +				if ( !bDockedLeft )
 +				{
 +					nNewX	 =  rc.left - nWidth;
 +					bDocked	 =  TRUE;
 +				}
 +				else if ( rc.right == rcThumb.left )
 +				{
 +					bDocked = TRUE;
 +				}
 +			}
 +			
 +
 +			if ( PtInRect( &rcBottom, pt ))
 +			{
 +				nNewY = rc.bottom;
 +
 +				if ( PtInRect( &rcRight, pt ))
 +				{
 +					nNewX = rc.right - nWidth;
 +				}
 +			}
 +
 +			if ( !bLeading && PtInRect( &rcTop, pt ))
 +			{
 +				nNewY			 =  rc.top;
 +				bDockedRight	 =  bDocked;
 +			}
 +			
 +			if ( fcOpt.bMoveTogether )
 +			{
 +				if ( bDockedRight )
 +				{
 +					DockThumbs( this, pCurThumb, TRUE );
 +				}
 +				
 +				if ( bDockedLeft )
 +				{
 +					DockThumbs( pCurThumb, this, FALSE );
 +				}
 +			}									
 +
 +			// Lower-left
 +			pt.x = rcThumb.left;
 +			pt.y = rcThumb.bottom;
 +
 +			if ( PtInRect( &rcRight, pt ))
 +			{
 +				nNewX = rc.right;
 +			}
 +
 +			if ( PtInRect( &rcTop, pt ))
 +			{
 +				nNewY = rc.top - nHeight;
 +
 +				if ( PtInRect( &rcLeft, pt ))
 +				{
 +					nNewX = rc.left;
 +				}
 +			}
 +			
 +
 +			// Lower-right
 +			pt.x = rcThumb.right;
 +			pt.y = rcThumb.bottom;
 +
 +			if ( !bLeading && PtInRect( &rcLeft, pt ))
 +			{
 +				nNewX = rc.left - nWidth;
 +			}
 +
 +			if ( !bLeading && PtInRect( &rcTop, pt ))
 +			{
 +				nNewY = rc.top - nHeight;
 +
 +				if ( PtInRect( &rcRight, pt ))
 +				{
 +					nNewX = rc.right - nWidth;
 +				}
 +			}
 +		}
 +	}
 +
 +	// Adjust coords once again
 +	SnapToScreen( rcThumb, nNewX, nNewY, &nNewX, &nNewY );
 +	
 +	newPos->x = nNewX;
 +	newPos->y = nNewY;
 +}
 +
 +void ThumbInfo::ResizeThumb()
 +{
 +	HDC		hdc			 =  NULL;
 +	HFONT	hOldFont	 =  NULL;
 +	POINT	ptText;
 +	SIZEL	sizeIcon;
 +	SIZEL	sizeText;
 +	RECT	rcThumb;
 +	int		index		 =  FLT_FONTID_NOTONLIST;
 +
 +	ThumbInfo *pNextThumb = NULL;
 +	
 +	himl = ( HIMAGELIST )CallService( MS_CLIST_GETICONSIMAGELIST, 0, 0 );
 +	
 +	if ( himl == NULL ) return;
 +	
 +	ImageList_GetIconSize_my(himl, sizeIcon);
 +
 +	hdc = GetWindowDC(hwnd);
 +
 +	if (!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
 +	{
 +		int nStatus;
 +		int nContactStatus;
 +		int nApparentMode;
 +		char* szProto;
 +
 +		szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
 +		
 +		if ( NULL != szProto )
 +		{
 +			nStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
 +			nContactStatus = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
 +			nApparentMode = DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0);
 +			
 +			if (	(nStatus == ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_ONLINE)
 +				||	(nStatus != ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_OFFLINE)
 +				)
 +			{
 +				if (ID_STATUS_OFFLINE == nContactStatus)
 +				{
 +					index = FLT_FONTID_OFFINVIS;
 +				}
 +				else
 +				{
 +					index  = 	FLT_FONTID_INVIS;
 +				}
 +			}
 +			else if (ID_STATUS_OFFLINE == nContactStatus)
 +			{
 +				index = FLT_FONTID_OFFLINE;
 +			}
 +			else
 +			{
 +				index = FLT_FONTID_CONTACTS;
 +			}
 +		}
 +	}
 +	else
 +	{
 +		index = FLT_FONTID_NOTONLIST;
 +	}
 +
 +	hOldFont = (HFONT)SelectObject( hdc, hFont[ index ] );
 +	
 +	// Get text and icon sizes
 +	GetTextExtentPoint32( hdc, ptszName, _tcslen( ptszName ), &sizeText );
 +	
 +	
 +	SelectObject( hdc, hOldFont );
 +	
 +	// Transform text size
 +	ptText.x = sizeText.cx;
 +	ptText.y = sizeText.cy;
 +	LPtoDP( hdc, &ptText, 1 );
 +
 +	
 +	szSize.cx = fcOpt.bFixedWidth ? fcOpt.nThumbWidth : sizeIcon.cx + ptText.x + 10;
 +	szSize.cy = ( ( sizeIcon.cy > ptText.y ) ? sizeIcon.cy : ptText.y ) + 4;
 +
 +	SetWindowPos(	hwnd, 
 +					HWND_TOPMOST, 
 +					0, 
 +					0, 
 +					szSize.cx, 
 +					szSize.cy,
 +					SWP_NOMOVE | /*SWP_NOZORDER |*/ SWP_NOACTIVATE );
 +	
 +	RefreshContactIcon(0xFFFFFFFF);
 +	
 +	ReleaseDC( hwnd, hdc );
 +
 +	// Move the docked widnow if needed
 +	if (pNextThumb = thumbList.FindThumb(dockOpt.hwndRight))
 +	{
 +		GetThumbRect( &rcThumb );
 +		pNextThumb->PositionThumb( (short)rcThumb.right, (short)rcThumb.top );
 +	}
 +}
 +
 +void ThumbInfo::RefreshContactIcon(int iIcon)
 +{
 +	if ( iIcon == 0xFFFFFFFF || ImageList_GetImageCount(himl)<=iIcon )
 +	{
 +		this->iIcon = CallService( MS_CLIST_GETCONTACTICON, (WPARAM)hContact, 0 );	
 +	}
 +	else
 +	{
 +		this->iIcon = iIcon;
 +	}
 +
 +	UpdateContent();
 +}
 +
 +void ThumbInfo::RefreshContactStatus(int idStatus)
 +{
 +	if ( IsStatusVisible( idStatus ))
 +	{
 +		RegisterFileDropping( hwnd, dropTarget );
 +	}
 +	else
 +	{
 +		UnregisterFileDropping( hwnd );
 +	}
 +
 +	ShowWindow( hwnd, fcOpt.bHideAll || HideOnFullScreen() || ( fcOpt.bHideOffline && ( !IsStatusVisible( idStatus )) ) || (fcOpt.bHideWhenCListShow && bIsCListShow) ? SW_HIDE : SW_SHOWNA );
 +}
 +
 +void ThumbInfo::DeleteContactPos()
 +{
 +	DBDeleteContactSetting( hContact, sModule, "ThumbsPos" );
 +}
 +
 +void ThumbInfo::OnLButtonDown(short nX, short nY)
 +{
 +	RECT rc;
 +
 +	if (bEnableTip && fcOpt.bShowTip) KillTip();
 +
 +//	ptOld.x = nX;
 +//	ptOld.y = nY;
 +	
 +//	ClientToScreen( hwnd, &ptOld );
 +
 +	GetCursorPos(&ptOld);
 +	GetThumbRect(&rc);
 +	
 +	nLeft	 =  (short)rc.left;
 +	nTop	 =  (short)rc.top;
 +	
 +	//bMouseIn	 =  FALSE;
 +	bMouseDown	 =  TRUE;
 +	bMouseMoved	 =  FALSE;
 +
 +//	SetCapture(hwnd);
 +}
 +
 +void ThumbInfo::OnLButtonUp()
 +{
 +	RECT	rcMiranda;
 +	RECT	rcThumb;
 +	RECT	rcOverlap;
 +
 +	if (!bMouseMoved && fcOpt.bUseSingleClick && bMouseIn){
 +		PopUpMessageDialog();
 +	}
 +
 +	//ThumbDeselect( TRUE );
 +
 +	if ( bMouseDown )
 +	{
 +		bMouseDown = FALSE;
 +		SetCursor( LoadCursor( NULL, IDC_ARROW ));
 +	
 +		// Check whether we shoud remove the window
 +		GetWindowRect( hwndMiranda, &rcMiranda );
 +		GetThumbRect( &rcThumb );
 +
 +		if ( IntersectRect( &rcOverlap, &rcMiranda, &rcThumb ))
 +		{
 +			if ( IsWindowVisible( hwndMiranda ))
 +			{
 +				DeleteContactPos( );
 +				thumbList.RemoveThumb( this );
 +			}
 +		}
 +	}
 +
 +	SaveContactsPos();
 +}
 +
 +void ThumbInfo::OnMouseMove(short nX, short nY, WPARAM wParam)
 +{
 +//	if (bMouseDown && !wParam&MK_LBUTTON) OnLButtonUp();
 +
 +	int		dX;
 +	int		dY;
 +	POINT	ptNew;
 +
 +	// Position thumb
 +	
 +	if ( bMouseDown )
 +	{
 +
 +		ptNew.x = nX;
 +		ptNew.y = nY;
 +
 +		ClientToScreen( hwnd, &ptNew );				
 +		
 +		dX = ptNew.x - ptOld.x;
 +		dY = ptNew.y - ptOld.y;
 +		
 +		if (dX || dY){
 +			bMouseMoved	 =  TRUE;
 +
 +			nLeft	+= (short)dX;
 +			nTop	+= (short)dY;
 +
 +			PositionThumb( nLeft, nTop );
 +		}
 +
 +		ptOld = ptNew;
 +	}
 +	else
 +	{
 +		SetCursor( LoadCursor( NULL, IDC_ARROW ));
 +	}
 +
 +	// Update selection status
 +	if ( !pThumbMouseIn )//
 +	{
 +	    SetTimer( hwnd, TIMERID_LEAVE_T, 10, NULL ); 
 +		pThumbMouseIn = this;
 +
 +		ThumbSelect( TRUE );
 +	}
 +	if (bEnableTip && fcOpt.bShowTip && !bMouseDown){
 +		WORD tmpTimeIn;
 +		POINT pt;
 +		RECT rc;
 +
 +		GetCursorPos(&pt);
 +		GetThumbRect(&rc);
 +		if (!PtInRect(&rc,pt)) {
 +			KillTip();
 +			return;
 +		}
 +		if (fTipTimerActive && abs(pt.x-ptTipSt.x)<5 && abs(pt.y-ptTipSt.x)<5){
 +			return;
 +		}
 +		ptTipSt = pt;
 +
 +		if (fTipTimerActive) {
 +			KillTimer(hwnd, TIMERID_HOVER_T);
 +		}
 +		if (fTipActive) {
 +			return;
 +		}
 +
 +		tmpTimeIn = (fcOpt.TimeIn>0)?fcOpt.TimeIn:CallService(MS_CLC_GETINFOTIPHOVERTIME, 0, 0);
 +		SetTimer(hwnd, TIMERID_HOVER_T, tmpTimeIn, 0);
 +		fTipTimerActive = TRUE;
 +	}
 +}
 +
 +void ThumbInfo::ThumbSelect(BOOL bMouse)
 +{
 +	if ( bMouse )
 +	{
 +		bMouseIn = TRUE;
 +		SetCapture( hwnd );
 +	}
 +
 +	SetThumbOpacity( 255 );
 +}
 +
 +void ThumbInfo::ThumbDeselect(BOOL bMouse)
 +{
 +	if ( bMouse )
 +	{
 +		bMouseIn = FALSE;
 +		ReleaseCapture();
 +	}
 +	
 +	SetThumbOpacity( fcOpt.thumbAlpha );
 +}
 +
 +void ThumbInfo::SetThumbOpacity(BYTE bAlpha)
 +{
 +	if ( pUpdateLayeredWindow && (bAlpha != btAlpha))
 +	{
 +		btAlpha = bAlpha;
 +		UpdateContent();
 +	}
 +}
 +
 +void ThumbInfo::KillTip()
 +{
 +	if (fTipTimerActive)
 +	{
 +		KillTimer(hwnd, TIMERID_HOVER_T);
 +		fTipTimerActive = FALSE;
 +	}
 +
 +	if (fTipActive)
 +	{
 +		CallService("mToolTip/HideTip", 0, 0);
 +		fTipActive = FALSE;
 +	}
 +}
 +
 +void ThumbInfo::UpdateContent()
 +{
 +	bmpContent.allocate(szSize.cx, szSize.cy);
 +
 +	HFONT	hOldFont;
 +	SIZE	size;
 +	RECT	rc;
 +	RECT	rcText;
 +	DWORD	oldColor;
 +	int		oldBkMode, index = 0;// nStatus;
 +	UINT	fStyle = ILD_NORMAL;
 +	
 +	HDC		hdcDraw	 =  bmpContent.getDC();
 +	SetRect(&rc, 0, 0, szSize.cx, szSize.cy);
 +
 +	if ( NULL != hBmpBackground )
 +	{
 +		RECT rcBkgnd;
 +		BITMAP bmp;
 +		HDC hdcBmp;
 +		HBITMAP hbmTmp;
 +		int x,y;
 +		int maxx,maxy;
 +		int destw,desth;
 +		int width;
 +		int height;
 +
 +		SetRect(&rcBkgnd, 0, 0, szSize.cx, szSize.cy);
 +		if (NULL != hLTEdgesPen)
 +			InflateRect(&rcBkgnd, -1, -1);
 +		width = rcBkgnd.right - rcBkgnd.left;
 +		height = rcBkgnd.bottom - rcBkgnd.top;
 +
 +		GetObject(hBmpBackground, sizeof(bmp), &bmp);
 +		hdcBmp	 =  CreateCompatibleDC( hdcDraw );
 +		hbmTmp = (HBITMAP)SelectObject( hdcBmp, hBmpBackground );
 +
 +		maxx = (0 != (nBackgroundBmpUse & CLBF_TILEH) ? rcBkgnd.right : rcBkgnd.left + 1);
 +		maxy = (0 != (nBackgroundBmpUse & CLBF_TILEV) ? rcBkgnd.bottom : rcBkgnd.top + 1);
 +		switch (nBackgroundBmpUse & CLBM_TYPE)
 +		{
 +		case CLB_STRETCH:
 +			if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL))
 +			{
 +				if (width * bmp.bmHeight < height * bmp.bmWidth)
 +				{
 +					desth = height;
 +					destw = desth * bmp.bmWidth / bmp.bmHeight;
 +				}
 +				else
 +				{
 +					destw = width;
 +					desth = destw * bmp.bmHeight / bmp.bmWidth;
 +				}
 +			}
 +			else
 +			{
 +				destw = width;
 +				desth = height;
 +			}
 +			break;
 +
 +		case CLB_STRETCHH:
 +			destw = width;
 +			if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL))
 +				desth = destw * bmp.bmHeight / bmp.bmWidth;
 +			else
 +				desth = bmp.bmHeight;
 +			break;
 +
 +		case CLB_STRETCHV:
 +			desth = height;
 +			if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL))
 +				destw = desth * bmp.bmWidth / bmp.bmHeight;
 +			else
 +				destw = bmp.bmWidth;
 +			break;
 +
 +		default:    //clb_topleft
 +			destw = bmp.bmWidth;
 +			desth = bmp.bmHeight;
 +			break;
 +		}
 +		SetStretchBltMode(hdcBmp, STRETCH_HALFTONE);
 +
 +		for (x = rcBkgnd.left; x < maxx; x += destw)
 +		{
 +			for (y = rcBkgnd.top; y < maxy; y += desth)
 +			{
 +				StretchBlt( hdcDraw, x, y, destw, desth, hdcBmp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY );
 +			}
 +		}
 +
 +		SelectObject( hdcBmp, hbmTmp );
 +		DeleteDC( hdcBmp );
 +	}
 +	else
 +	{
 +		FillRect( hdcDraw, &rc, hBkBrush );
 +	}
 +
 +	if (NULL != hLTEdgesPen)
 +	{
 +		HPEN  hOldPen = (HPEN)SelectObject( hdcDraw, hLTEdgesPen );
 +
 +		MoveToEx(hdcDraw, 0, 0, NULL);
 +		LineTo(hdcDraw, szSize.cx, 0);
 +		MoveToEx(hdcDraw, 0, 0, NULL);
 +		LineTo(hdcDraw, 0, szSize.cy);
 +
 +		SelectObject(hdcDraw, hRBEdgesPen);
 +
 +		MoveToEx(hdcDraw, 0, szSize.cy - 1, NULL);
 +		LineTo(hdcDraw, szSize.cx - 1, szSize.cy - 1);
 +		MoveToEx(hdcDraw, szSize.cx - 1, szSize.cy - 1, NULL);
 +		LineTo(hdcDraw, szSize.cx - 1, 0);
 +
 +		SelectObject(hdcDraw, hOldPen);
 +		//InflateRect(&rc, -1, -1);
 +	}
 +
 +	bmpContent.setAlpha(btAlpha);
 +
 +	ImageList_GetIconSize_my( himl, size );
 +
 +	oldBkMode	 =  SetBkMode( hdcDraw, TRANSPARENT );
 +
 +	if (!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
 +	{
 +		int nStatus;
 +		int nContactStatus;
 +		int nApparentMode;
 +		char* szProto;
 +
 +
 +		szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
 +		
 +		if ( NULL != szProto )
 +		{
 +			nStatus			 =  CallProtoService(szProto, PS_GETSTATUS, 0, 0);
 +			nContactStatus	 =  DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
 +			nApparentMode	 =  DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0);
 +			
 +			if (	(nStatus == ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_ONLINE) ||
 +					(nStatus != ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_OFFLINE))
 +			{
 +				if (ID_STATUS_OFFLINE == nContactStatus)
 +				{
 +					index = FLT_FONTID_OFFINVIS;
 +				}
 +				else
 +				{
 +					index  = 	FLT_FONTID_INVIS;
 +					if (fcOpt.bShowIdle && DBGetContactSettingDword(hContact, szProto, "IdleTS", 0)) {
 +						fStyle|=ILD_BLEND50;
 +					}
 +				}
 +			}
 +			else if (ID_STATUS_OFFLINE == nContactStatus)
 +			{
 +				index = FLT_FONTID_OFFLINE;
 +			}
 +			else
 +			{
 +				index = FLT_FONTID_CONTACTS;
 +				if (fcOpt.bShowIdle && DBGetContactSettingDword(hContact, szProto, "IdleTS", 0)) {
 +					fStyle|=ILD_BLEND50;
 +				}
 +			}
 +
 +		}
 +	}
 +	else
 +	{
 +		index = FLT_FONTID_NOTONLIST;
 +		fStyle|=ILD_BLEND50;
 +	}
 +
 +	oldColor = SetTextColor( hdcDraw, tColor[ index ] );
 +	
 +/*	ImageList_DrawEx(	himl, 
 +						iIcon, 
 +						hdcDraw, 
 +						2, 
 +						( szSize.cy - size.cx ) / 2, 
 +						0, 
 +						0, 
 +						CLR_NONE, 
 +						CLR_NONE, 
 +						fStyle);
 +*/
 +	{ 
 +		HICON icon = ImageList_GetIcon(himl, iIcon, ILD_NORMAL);
 +		MyBitmap bmptmp(size.cx, size.cy);
 +		bmptmp.DrawIcon(icon,0,0);//bmpContent
 +		BLENDFUNCTION blend;
 +		blend.BlendOp = AC_SRC_OVER;
 +		blend.BlendFlags = 0;
 +		blend.SourceConstantAlpha = (fStyle&ILD_BLEND50)?128:255;
 +		blend.AlphaFormat = AC_SRC_ALPHA;
 +		AlphaBlend(hdcDraw, 2,( szSize.cy - size.cx ) / 2, bmptmp.getWidth(), bmptmp.getHeight(), bmptmp.getDC(), 0, 0, bmptmp.getWidth(), bmptmp.getHeight(), blend);
 +		DestroyIcon(icon);
 +	}
 +	SetRect(&rcText, 0, 0, szSize.cx, szSize.cy);
 +	rcText.left += size.cx + 4;
 +
 +	hOldFont = (HFONT)SelectObject( hdcDraw, hFont[ index ] );
 +
 +	SIZE szText;
 +	GetTextExtentPoint32(hdcDraw, ptszName, _tcslen(ptszName), &szText);
 +	SetTextColor(hdcDraw, bkColor);
 +
 +	// simple border
 +	bmpContent.DrawText(ptszName, rcText.left-1, (rcText.top + rcText.bottom - szText.cy)/2);
 +	bmpContent.DrawText(ptszName, rcText.left+1, (rcText.top + rcText.bottom - szText.cy)/2);
 +	bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2-1);
 +	bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2+1);
 +
 +	// blurred border
 +	// bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2, 3);
 +
 +	// text itself
 +	SetTextColor(hdcDraw, tColor[index]);
 +	bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2);
 +	
 +	SelectObject( hdcDraw, hOldFont );
 +	
 +	SetTextColor( hdcDraw, oldColor );
 +	SetBkMode( hdcDraw, oldBkMode );
 +
 +	if (pUpdateLayeredWindow)
 +	{
 +		SetWindowLongPtr( hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
 +
 +		RECT rc; GetWindowRect(hwnd, &rc);
 +		POINT ptDst = {rc.left, rc.top};
 +		POINT ptSrc = {0, 0};
 +
 +		BLENDFUNCTION blend;
 +		blend.BlendOp =             AC_SRC_OVER;
 +		blend.BlendFlags =          0;
 +		blend.SourceConstantAlpha = 255;
 +		blend.AlphaFormat =         AC_SRC_ALPHA;
 +
 +		pUpdateLayeredWindow(hwnd, NULL, &ptDst, &szSize, bmpContent.getDC(), &ptSrc, 0xffffffff, &blend, ULW_ALPHA);
 +	} else
 +	{
 +		RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
 +		UpdateWindow(hwnd);
 +	}
 +}
 +
 +void ThumbInfo::PopUpMessageDialog( )
 +{
 +	CallService( MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)hContact, (LPARAM)0 );
 +}
 +
 +void ThumbInfo::OnTimer(BYTE idTimer)
 +{
 +	if (idTimer == TIMERID_SELECT_T){
 +		KillTimer( hwnd, TIMERID_SELECT_T );
 +		ThumbDeselect( FALSE );
 +	}
 +	if (idTimer == TIMERID_LEAVE_T && !bMouseDown){
 +		POINT pt;
 +		RECT rc;
 +
 +		GetCursorPos(&pt);
 +		GetThumbRect(&rc);
 +		if (!PtInRect(&rc, pt)) {
 +			KillTimer( hwnd, TIMERID_LEAVE_T );
 +			pThumbMouseIn	 =  NULL;
 +			ThumbDeselect( TRUE );
 +		}
 +	}
 +	if (bEnableTip && fcOpt.bShowTip && idTimer == TIMERID_HOVER_T){
 +		POINT pt;
 +		CLCINFOTIP ti = {0};
 +		ti.cbSize = sizeof(ti);
 +
 +		KillTimer(hwnd, TIMERID_HOVER_T);
 +		fTipTimerActive = FALSE;
 +		GetCursorPos(&pt);
 +		if (abs(pt.x-ptTipSt.x)<5 && abs(pt.y-ptTipSt.y)<5){
 +			ti.ptCursor = pt;
 +
 +			fTipActive = TRUE;
 +			ti.isGroup = 0;
 +			ti.hItem = hContact;
 +			ti.isTreeFocused = 0;
 +			CallService("mToolTip/ShowTip", 0, (LPARAM)&ti);
 +		}
 +	}
 +}
 +
 +void DockThumbs( ThumbInfo *pThumbLeft, ThumbInfo *pThumbRight, BOOL bMoveLeft )
 +{
 +	if ( ( pThumbRight->dockOpt.hwndLeft == NULL ) && ( pThumbLeft->dockOpt.hwndRight == NULL ))
 +	{
 +		pThumbRight->dockOpt.hwndLeft	 =  pThumbLeft->hwnd;
 +		pThumbLeft->dockOpt.hwndRight	 =  pThumbRight->hwnd;
 +	}
 +}
 +
 +
 +void UndockThumbs( ThumbInfo *pThumb1, ThumbInfo *pThumb2 )
 +{
 +	if ( ( pThumb1 == NULL ) || ( pThumb2 == NULL ))
 +	{
 +		return;
 +	}
 +
 +	if ( pThumb1->dockOpt.hwndRight == pThumb2->hwnd )
 +	{
 +		pThumb1->dockOpt.hwndRight = NULL;
 +	}
 +
 +	if ( pThumb1->dockOpt.hwndLeft == pThumb2->hwnd )
 +	{
 +		pThumb1->dockOpt.hwndLeft = NULL;
 +	}
 +	
 +	if ( pThumb2->dockOpt.hwndRight == pThumb1->hwnd )
 +	{
 +		pThumb2->dockOpt.hwndRight = NULL;
 +	}
 +
 +	if ( pThumb2->dockOpt.hwndLeft == pThumb1->hwnd )
 +	{
 +		pThumb2->dockOpt.hwndLeft = NULL;
 +	}
 +}
 +
 +/////////////////////////////////////////////////////////////////////////////
 +// ThumbList
 +ThumbList::ThumbList(): LIST<ThumbInfo>(1, cmp)
 +{
 +}
 +
 +ThumbList::~ThumbList()
 +{
 +	for (int i = 0; i < getCount(); ++i)
 +		delete (*this)[i];
 +	destroy();
 +}
 +
 +ThumbInfo *ThumbList::AddThumb(HWND hwnd, TCHAR *ptszName, HANDLE hContact)
 +{
 +	ThumbInfo *pThumb	 =  NULL;
 +
 +	if ( ptszName == NULL )	return( NULL );
 +	if ( hContact == NULL ) return( NULL );
 +	if ( hwnd == NULL )		return( NULL );
 +
 +	pThumb = new ThumbInfo;
 +	 
 +	if ( pThumb != NULL )
 +	{
 +		_tcsncpy( pThumb->ptszName, ptszName, USERNAME_LEN - 1 );
 +		pThumb->hContact	 =  hContact;
 +		pThumb->hwnd		 =  hwnd;
 +		
 +		pThumb->dockOpt.hwndLeft	 =  NULL;
 +		pThumb->dockOpt.hwndRight	 =  NULL;
 +
 +		pThumb->fTipActive = FALSE;
 +
 +//		RegHotkey(szName, hwnd);
 +		RegHotkey(hContact, hwnd);
 +	}
 +
 +	insert(pThumb);
 +
 +	return( pThumb );
 +}
 +
 +void ThumbList::RemoveThumb(ThumbInfo *pThumb)
 +{
 +	if (!pThumb) return;
 +
 +	if (fcOpt.bMoveTogether)
 +	{
 +		UndockThumbs(pThumb, FindThumb(pThumb->dockOpt.hwndLeft));
 +		UndockThumbs(pThumb, FindThumb(pThumb->dockOpt.hwndRight));
 +	}
 +
 +	remove(pThumb);
 +
 +	UnregisterFileDropping( pThumb->hwnd );
 +	DestroyWindow( pThumb->hwnd );
 +	delete pThumb;
 +}
 +
 +ThumbInfo *ThumbList::FindThumb(HWND hwnd)
 +{
 +	if (!hwnd) return NULL;
 +
 +	for (int i = 0; i < getCount(); ++i)
 +		if ((*this)[i]->hwnd == hwnd)
 +			return (*this)[i];
 +
 +	return NULL;
 +}
 +
 +ThumbInfo *ThumbList::FindThumbByContact(HANDLE hContact)
 +{
 +	if (!hContact) return NULL;
 +
 +	for (int i = 0; i < getCount(); ++i)
 +		if ((*this)[i]->hContact == hContact)
 +			return (*this)[i];
 +
 +	return NULL;
 +}
 +
 +int ThumbList::cmp(const ThumbInfo *p1, const ThumbInfo *p2)
 +{
 +	if ((DWORD)p1->hContact < (DWORD)p2->hContact) return -1;
 +	if ((DWORD)p1->hContact > (DWORD)p2->hContact) return +1;
 +	return 0;
 +}
 diff --git a/plugins/FloatingContacts/src/thumbs.h b/plugins/FloatingContacts/src/thumbs.h new file mode 100644 index 0000000000..ee6db80097 --- /dev/null +++ b/plugins/FloatingContacts/src/thumbs.h @@ -0,0 +1,74 @@ +/////////////////////////////////////////////////////////////////////////////
 +//
 +#define	USERNAME_LEN				50
 +class CDropTarget;
 +
 +typedef struct _DockOpt
 +{
 +	HWND	hwndLeft;
 +	HWND	hwndRight;
 +}
 +DockOpt;
 +
 +struct ThumbInfo
 +{
 +public: // TODO: make private
 +	HWND			hwnd;
 +	TCHAR			ptszName[ USERNAME_LEN ];
 +	HANDLE			hContact;
 +	int				iIcon;
 +	CDropTarget *	dropTarget;
 +	DockOpt			dockOpt;
 +	BOOL			fTipActive;
 +	BOOL			fTipTimerActive;
 +	POINT			ptTipSt;
 +
 +	BYTE			btAlpha;
 +	MyBitmap		bmpContent;
 +
 +	POINT			ptPos;
 +	SIZE			szSize;
 +
 +public:
 +	ThumbInfo();
 +	~ThumbInfo();
 +
 +	void GetThumbRect			(RECT *rc);
 +	void PositionThumb			(short nX, short nY); 
 +	void PositionThumbWorker	(short nX, short nY, POINT *rcNewPos); 
 +	void ResizeThumb			();
 +	void RefreshContactIcon		(int iIcon);
 +	void RefreshContactStatus	(int idStatus);
 +	void DeleteContactPos		();
 +	void OnLButtonDown			(short nX, short nY);
 +	void OnLButtonUp			();
 +	void OnMouseMove			(short nX, short nY, WPARAM wParam);
 +	void ThumbSelect			(BOOL bMouse);
 +	void ThumbDeselect			(BOOL bMouse);
 +	void SetThumbOpacity		(BYTE btAlpha);
 +	void KillTip				();
 +	void UpdateContent			();
 +	void PopUpMessageDialog		();
 +	void OnTimer				(BYTE idTimer);
 +};
 +
 +void UndockThumbs	( ThumbInfo *pThumb1, ThumbInfo *pThumb2 );
 +void DockThumbs		( ThumbInfo *pThumbLeft, ThumbInfo *pThumbRight, BOOL bMoveLeft );
 +
 +class ThumbList: public LIST<ThumbInfo>
 +{
 +public:
 +	ThumbList();
 +	~ThumbList();
 +
 +	ThumbInfo*	AddThumb			(HWND hwnd, TCHAR *ptszName, HANDLE hContact);
 +	void		RemoveThumb			(ThumbInfo *pThumb);
 +
 +	ThumbInfo*	FindThumb			(HWND hwnd);
 +	ThumbInfo*	FindThumbByContact	(HANDLE hContact);
 +
 +private:
 +	static int cmp(const ThumbInfo *p1, const ThumbInfo *p2);
 +};
 +
 +extern ThumbList thumbList;
 diff --git a/plugins/FloatingContacts/src/version.h b/plugins/FloatingContacts/src/version.h new file mode 100644 index 0000000000..3b8d0e8e20 --- /dev/null +++ b/plugins/FloatingContacts/src/version.h @@ -0,0 +1,23 @@ +#define BUILD_NUM 2
 +#define BUILD_NUM_STR  "2"
 +#define REVISION  "$Revision: 1136 $"
 +
 +#define COREVERSION_NUM 1, 0, 2,
 +#define COREVERSION_NUM_STR  "1, 0, 2"
 +
 +#define MINIMAL_COREVERSION 0, 6, 0, 0
 +#define MINIMAL_COREVERSION_STR "0, 6, 0, 0"
 +
 +#define FILE_VERSION	COREVERSION_NUM BUILD_NUM
 +#define FILE_VERSION_STR COREVERSION_NUM_STR  " build " BUILD_NUM_STR	" " REVISION 
 +
 +#define PRODUCT_VERSION	FILE_VERSION
 +#define PRODUCT_VERSION_STR	FILE_VERSION_STR
 +
 +#define __PLUGIN_NAME				"Floating Contacts"
 +#define __FILENAME					"FltContacts.dll"
 +#define __DESC						"Floating Contacts plugin for Miranda"
 +#define __AUTHOR					"Iavor Vajarov, Kosh&chka, Victor Pavlychko"
 +#define __AUTHOREMAIL				"ell-6@ya.ru"
 +#define __AUTHORWEB					"http://www.miranda-im.org/"
 +#define __COPYRIGHT					"© 2002-2004 I. Vajarov (ivajarov@code.bg), © 2008 Kosh&chka, V. Pavlychko"
 | 
