/*
 * astyle --force-indent=tab=4 --brackets=linux --indent-switches
 *		  --pad=oper --one-line=keep-blocks  --unpad=paren
 *
 * Miranda IM: the free IM client for Microsoft* Windows*
 *
 * Copyright 2000-2010 Miranda ICQ/IM project,
 * all portions of this codebase are copyrighted to the people
 * listed in contributors.txt.
 *
 * 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.
 *
 * part of clist_ng plugin for Miranda.
 *
 * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
 *
 * $Id: clcpaint.cpp 134 2010-10-01 10:23:10Z silvercircle $
 *
 */

#include <commonheaders.h>

HANDLE						CLC::hTheme = 0;

extern 	ORDERTREEDATA 		OrderTreeData[];
extern 	HICON 				overlayicons[];
extern  FRAMEWND*			wndFrameCLC;
extern wchar_t*				statusNames[];

int 						g_center, g_ignoreselforgroups, g_selectiveIcon, g_exIconSpacing;
HWND 						g_focusWnd;
BYTE 						selBlend;
int 						my_status;

//static Gdiplus::Graphics*	_g;

static wchar_t wszTimeFormat[] = L"%H:%M";
static LONG		dxBufferDiff, dBufferDiff;

HFONT CLCPaintHelper::changeToFont(const unsigned int id)
{
	HFONT 	hOldFont = 0;

	hOldFont = reinterpret_cast<HFONT>(SelectObject(hdcMem, dat->fontInfo[id].hFont));
	Gfx::setTextColor(dat->fontInfo[id].colour);
	m_fontHeight = dat->fontInfo[id].fontHeight;

	dat->currentFontID = id;
	return hOldFont;
}

void CLCPaintHelper::setHotTrackColour()
{
	if (dat->gammaCorrection) {
		COLORREF oldCol, newCol;
		int oldLum, newLum;

		oldCol = GetTextColor(hdcMem);
		oldLum = (GetRValue(oldCol) * 30 + GetGValue(oldCol) * 59 + GetBValue(oldCol) * 11) / 100;
		newLum = (GetRValue(dat->hotTextColour) * 30 + GetGValue(dat->hotTextColour) * 59 + GetBValue(dat->hotTextColour) * 11) / 100;
		if (newLum == 0) {
			Gfx::setTextColor(dat->hotTextColour);
			return;
		}
		if (newLum >= oldLum + 20) {
			oldLum += 20;
			newCol = RGB(GetRValue(dat->hotTextColour) * oldLum / newLum, GetGValue(dat->hotTextColour) * oldLum / newLum, GetBValue(dat->hotTextColour) * oldLum / newLum);
		} else if (newLum <= oldLum) {
			int r, g, b;
			r = GetRValue(dat->hotTextColour) * oldLum / newLum;
			g = GetGValue(dat->hotTextColour) * oldLum / newLum;
			b = GetBValue(dat->hotTextColour) * oldLum / newLum;
			if (r > 255) {
				g +=(r-255)*3 / 7;
				b +=(r-255)*3 / 7;
				r = 255;
			}
			if (g > 255) {
				r +=(g-255)*59 / 41;
				if (r > 255)
					r = 255;
				b +=(g-255)*59 / 41;
				g = 255;
			}
			if (b > 255) {
				r +=(b-255)*11 / 89;
				if (r > 255)
					r = 255;
				g +=(b-255)*11 / 89;
				if (g > 255)
					g = 255;
				b = 255;
			}
			newCol = RGB(r, g, b);
		} else
			newCol = dat->hotTextColour;
		Gfx::setTextColor(newCol);
	} else
		Gfx::setTextColor(dat->hotTextColour);
}

/**
 * return "relative" onlineness value based on the status mode
 *
 * @param status 				 status mode
 * @param ignoreConnectingState  ignore the special "in
 *  							 connection progress" status
 *
 * @return int  				 "onlineness" value for the
 *  	   given status mode
 */
static int __fastcall GetRealStatus(struct ClcContact *contact, int status)
{
	int i;
	char *szProto = contact->proto;
	if (!szProto)
		return status;
	for (i = 0; i < pcli->hClcProtoCount; i++) {
		if (!lstrcmpA(pcli->clcProto[i].szProto, szProto)) {
			return pcli->clcProto[i].dwStatus;
		}
	}
	return status;
}

int GetBasicFontID(struct ClcContact * contact)
{
	switch (contact->type)	{
		case CLCIT_CONTACT:
			if (contact->flags & CONTACTF_NOTONLIST)
				return FONTID_NOTONLIST;
			else if ((contact->flags&CONTACTF_INVISTO && GetRealStatus(contact, ID_STATUS_OFFLINE) != ID_STATUS_INVISIBLE)
				|| (contact->flags&CONTACTF_VISTO && GetRealStatus(contact, ID_STATUS_OFFLINE) == ID_STATUS_INVISIBLE))
				return contact->flags & CONTACTF_ONLINE ? FONTID_INVIS : FONTID_OFFINVIS;
			else
				return contact->flags & CONTACTF_ONLINE ? FONTID_CONTACTS : FONTID_OFFLINE;
			break;
		case CLCIT_GROUP:
			return FONTID_GROUPS;
		case CLCIT_INFO:
			if(contact->flags & CLCIIF_GROUPFONT)
				return FONTID_GROUPS;
			else
				return FONTID_CONTACTS;
		case CLCIT_DIVIDER:
			return FONTID_DIVIDERS;
		default:
			return FONTID_CONTACTS;
	}
}

static BLENDFUNCTION bf = {0, 0, AC_SRC_OVER, 0};
static BOOL avatar_done = FALSE;
HDC g_HDC;
static BOOL g_RTL;
HDC hdcTempAV;
HBITMAP hbmTempAV, hbmTempOldAV;

LONG g_maxAV_X = 200, g_maxAV_Y = 200;

int CLCPaintHelper::drawAvatar(RECT *rc, ClcContact *contact, int y, WORD cstatus, int rowHeight)
{
	float 		dScale = 0.;
	float 		newHeight, newWidth, dAspect;
	DWORD 		topoffset = 0, leftoffset = 0, dwFlags = contact->dwDFlags;
	LONG 		bmWidth, bmHeight;
	HBITMAP 	hbm;
	HRGN 		rgn = 0;
	int 		avatar_size = cfg::dat.avatarSize;
	DWORD 		av_saved_left;
	TStatusItem *item = contact->wStatus == ID_STATUS_OFFLINE ? &Skin::statusItems[ID_EXTBKAVATARFRAMEOFFLINE] : &Skin::statusItems[ID_EXTBKAVATARFRAME];
	int  		skinMarginX, skinMarginY;
	BOOL 		fOverlay = (cfg::dat.dwFlags & CLUI_FRAME_OVERLAYICONS);

	contact->avatarLeft = -1;
	if(dat->bisEmbedded)
		return 0;

	if(contact->ace) {
		if(contact->ace->dwFlags & AVS_HIDEONCLIST) {
			if (cfg::dat.dwFlags & CLUI_FRAME_ALWAYSALIGNNICK)
				return avatar_size + 2;
			else
				return 0;
		}
		bmHeight = contact->ace->bmHeight;
		bmWidth = contact->ace->bmWidth;
		if(bmWidth != 0)
			dAspect = (float)bmHeight / (float)bmWidth;
		else
			dAspect = 1.0;
		hbm = contact->ace->hbmPic;
		contact->ace->t_lastAccess = cfg::dat.t_now;
	}
	else if (cfg::dat.dwFlags & CLUI_FRAME_ALWAYSALIGNNICK)
		return avatar_size + 2;
	else
		return 0;

	if(bmHeight == 0 || bmWidth == 0 || hbm == 0)
		return 0;

	g_maxAV_X = max(bmWidth, g_maxAV_X);
	g_maxAV_Y = max(bmHeight, g_maxAV_Y);

	if(dAspect >= 1.0) {            // height > width
		skinMarginY = item->IGNORED ? 0 : (item->MARGIN_TOP + item->MARGIN_BOTTOM);
		skinMarginX = item->IGNORED ? 0 : (item->MARGIN_LEFT + item->MARGIN_RIGHT);

		dScale = (float)(avatar_size - 2) / (float)bmHeight;
		newHeight = (float)(avatar_size - skinMarginY - 2);
		newWidth = (float)(bmWidth * dScale) - skinMarginX;
	}
	else {
		skinMarginY = item->IGNORED ? 0 : (item->MARGIN_LEFT + item->MARGIN_RIGHT);
		skinMarginX = item->IGNORED ? 0 : (item->MARGIN_LEFT + item->MARGIN_RIGHT);

		newWidth = (float)(avatar_size - 2) - skinMarginX;
		dScale = (float)(avatar_size - 2) / (float)bmWidth;
		newHeight = (float)(bmHeight * dScale) - skinMarginY;
	}
	topoffset = rowHeight > (int)newHeight ? (rowHeight - (int)newHeight) / 2 : 0;
	if(!item->IGNORED) {
		//topoffset += item->MARGIN_TOP;
		leftoffset = item->MARGIN_LEFT;
	}
	// create the region for the avatar border - use the same region for clipping, if needed.

	av_saved_left = rc->left;
	if(cfg::dat.bCenterStatusIcons && newWidth < newHeight)
		rc->left += (((avatar_size - 2) - ((int)newWidth + skinMarginX)) / 2);

	bf.SourceConstantAlpha = 255;
	bf.AlphaFormat = contact->ace->dwFlags & AVS_PREMULTIPLIED ? AC_SRC_ALPHA : 0;


	FIBITMAP *fib = cfg::fif->FI_CreateDIBFromHBITMAP(contact->ace->hbmPic);
	FIBITMAP *fibnew = cfg::fif->FI_Rescale(fib, newWidth, newHeight, FILTER_LANCZOS3);
	HBITMAP hbmNew = cfg::fif->FI_CreateHBITMAPFromDIB(fibnew);
	HBITMAP hbmTempOld = (HBITMAP)SelectObject(hdcTempAV, hbmNew);

	Api::pfnAlphaBlend(hdcMem, leftoffset + rc->left - (g_RTL ? 1 : 0), y + topoffset, (int)newWidth, (int)newHeight, hdcTempAV, 0, 0, newWidth, newHeight, bf);

	SelectObject(hdcTempAV, hbmTempOld);
	if(hbmNew != contact->ace->hbmPic)
		DeleteObject(hbmNew);
	cfg::fif->FI_Unload(fib);
	cfg::fif->FI_Unload(fibnew);

	if(cfg::dat.dwFlags & CLUI_FRAME_AVATARBORDER) {
		rgn = CreateRectRgn(leftoffset + rc->left, y + topoffset, leftoffset + rc->left + (int)newWidth, y + topoffset + (int)newHeight);
		if(g_RTL)
			OffsetRgn(rgn, -1 , 0);
		FrameRgn(hdcMem, rgn, cfg::dat.hBrushAvatarBorder, 1, 1);
		DeleteObject(rgn);
	}

	if(fOverlay)
		fOverlay = (dwFlags & ECF_HIDEOVERLAY) ? 0 : 1;
	else
		fOverlay = (dwFlags & ECF_FORCEOVERLAY) ? 1 : 0;

	if(fOverlay && cstatus && (int)newHeight >= CYSMICON)
		DrawIconEx(hdcMem, rc->left + (int)newWidth - 15, y + topoffset + (int)newHeight - 15, overlayicons[cstatus - ID_STATUS_OFFLINE], CYSMICON, CXSMICON, 0, 0, DI_NORMAL | DI_COMPAT);

	if(!item->IGNORED) {
		RECT rcFrame;
		bool inClCPaint_save = CLC::fInPaint;
		HDC  hdcTemp = 0;
		HBITMAP hbmOld, hbmTemp;

		CLC::fInPaint = false;
		rcFrame.left = rc->left;
		rcFrame.top = y + topoffset - item->MARGIN_TOP;
		rcFrame.right = rcFrame.left + (int)newWidth + item->MARGIN_RIGHT + item->MARGIN_LEFT;
		rcFrame.bottom = rcFrame.top + (int)newHeight + item->MARGIN_BOTTOM + item->MARGIN_TOP;
		if(g_RTL) {
			RECT rcTemp;

			OffsetRect(&rcFrame, 1, 0);
			rcTemp.left = rcTemp.top = 0;
			rcTemp.right = rcFrame.right - rcFrame.left;
			rcTemp.bottom = rcFrame.bottom - rcFrame.top;
			hdcTemp = CreateCompatibleDC(g_HDC);
			hbmTemp = CreateCompatibleBitmap(g_HDC, rcTemp.right, rcTemp.bottom);
			hbmOld = reinterpret_cast<HBITMAP>(SelectObject(hdcTemp, hbmTemp));
			SetLayout(hdcTemp, LAYOUT_RTL);
			BitBlt(hdcTemp, 0, 0, rcTemp.right, rcTemp.bottom,
				   hdcMem, rcFrame.left, rcFrame.top, SRCCOPY);
			SetLayout(hdcTemp, 0);
			Gfx::renderSkinItem(hdcTemp, &rcTemp, item->imageItem);
			BitBlt(hdcMem, rcFrame.left, rcFrame.top, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top,
				   hdcTemp, 0, 0, SRCCOPY);
			SelectObject(hdcTemp, hbmOld);
			DeleteObject(hbmTemp);
			DeleteDC(hdcTemp);
		} else
			Gfx::renderSkinItem(hdcMem, &rcFrame, item->imageItem);
		CLC::fInPaint = inClCPaint_save;
	}
	contact->avatarLeft = rc->left;
	avatar_done = TRUE;
	rc->left = av_saved_left;
	return avatar_size + 2;

}

static BOOL pi_avatar = FALSE;
static RECT rcContent;
static BOOL pi_selectiveIcon;

static BOOL av_left, av_right, av_rightwithnick;
static BOOL mirror_rtl, mirror_always, mirror_rtltext;

BYTE savedCORNER = -1;
int  g_padding_y = 0;

void CLCPaintHelper::Paint(ClcGroup *group, ClcContact *contact, int rowHeight)
{
	RECT 				rc;
	int 				iImage = -1;
	SIZE 				textSize = { 0 }, countsSize = { 0 }, spaceSize = { 0 };
	int 				width, checkboxWidth;
	TCHAR*				szCounts = 0;
	wchar_t*			wszCounts = 0;
	BOOL 				twoRows = FALSE;
	WORD 				cstatus;
	DWORD 				leftOffset = 0, rightOffset = 0;
	int 				iconXSpace = dat->iconXSpace;
	HFONT 				hPreviousFont = 0;
	BYTE 				type;
	BYTE 				flags;
	COLORREF 			oldGroupColor = -1;
	DWORD 				qLeft = 0;
	int 				leftX = dat->leftMargin + indent * dat->groupIndent;
	int 				bg_indent_r = 0;
	int 				bg_indent_l = 0;
	int 				rightIcons = 0;
	DWORD 				dt_nickflags = 0, dt_2ndrowflags = 0;
	TExtraCache*		cEntry = NULL;
	DWORD 				dwFlags = cfg::dat.dwFlags;
	int 				scanIndex;
	BOOL 				av_local_wanted, fLocalTime;

	if(!isContactFloater)
		current_shape = 0;

	rowHeight -= cfg::dat.bRowSpacing;

	if(group == NULL || contact == NULL)
		return;

	g_RTL = FALSE;
	scanIndex = group->scanIndex;
	av_local_wanted = (CLC::uNrAvatars > 0);

	type = contact->type;
	flags = contact->flags;
	avatar_done = FALSE;
	if(contact->extraCacheEntry >= 0 && contact->extraCacheEntry < cfg::nextCacheEntry)
		cEntry = &cfg::eCache[contact->extraCacheEntry];
	else
		cEntry = cfg::eCache;

	if(dat->bisEmbedded)
		goto set_bg_l;

	if(type == CLCIT_CONTACT && (cEntry->dwCFlags & ECF_RTLNICK || mirror_always)) {
		if(mirror_rtl || mirror_always) {
			g_RTL = TRUE;
			bg_indent_r = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0;
		}
		else if(mirror_rtltext) {
			bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0;
			dt_nickflags = DT_RTLREADING | DT_RIGHT;
		}
		else
			bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0;
	}
	else if(type == CLCIT_GROUP) {
		if((contact->isRtl && cfg::dat.bGroupAlign == CLC_GROUPALIGN_AUTO) || cfg::dat.bGroupAlign == CLC_GROUPALIGN_RIGHT) {
			g_RTL = TRUE;
			bg_indent_r = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0;
		}
		else
			bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0;
	}
	else
		bg_indent_l = cfg::dat.bApplyIndentToBg ? indent * dat->groupIndent : 0;

set_bg_l:
	//setup
	if (type == CLCIT_GROUP) {
		changeToFont(FONTID_GROUPS);
		GetTextExtentPoint32(hdcMem, contact->szText, lstrlen(contact->szText), &textSize);
		width = textSize.cx;
		szCounts = pcli->pfnGetGroupCountsText(dat, contact);
		if (szCounts[0]) {
			GetTextExtentPoint32W(hdcMem, L" ", 1, &spaceSize);
			changeToFont(FONTID_GROUPCOUNTS);
			GetTextExtentPoint32W(hdcMem, szCounts, lstrlenW(szCounts), &countsSize);
			width += spaceSize.cx + countsSize.cx;
			wszCounts = szCounts;
		}
	} else if (type == CLCIT_INFO) {
		if (flags & CLCIIF_GROUPFONT)
			changeToFont(FONTID_GROUPS);
		else
			changeToFont(FONTID_CONTACTS);
	} else if (type == CLCIT_DIVIDER) {
		changeToFont(FONTID_DIVIDERS);
		GetTextExtentPoint32(hdcMem, contact->szText, lstrlen(contact->szText), &textSize);
	}
	else if (type == CLCIT_CONTACT && flags & CONTACTF_NOTONLIST)
		changeToFont(FONTID_NOTONLIST);
	else if (type == CLCIT_CONTACT && ((flags & CONTACTF_INVISTO && GetRealStatus(contact, my_status) != ID_STATUS_INVISIBLE) || (flags & CONTACTF_VISTO && GetRealStatus(contact, my_status) == ID_STATUS_INVISIBLE))) {
		changeToFont(flags & CONTACTF_ONLINE ? FONTID_INVIS : FONTID_OFFINVIS);
	} else if (type == CLCIT_CONTACT && !(flags & CONTACTF_ONLINE))
		changeToFont(FONTID_OFFLINE);
	else
		changeToFont(FONTID_CONTACTS);

	if ((style & CLS_CHECKBOXES && type == CLCIT_CONTACT) || (style & CLS_GROUPCHECKBOXES && type == CLCIT_GROUP) || (type == CLCIT_INFO && flags & CLCIIF_CHECKBOX))
		checkboxWidth = dat->checkboxSize + 2;
	else
		checkboxWidth = 0;

	rc.left = 0;
	cstatus = contact->wStatus;

	/***** BACKGROUND DRAWING *****/
	// contacts

	CLC::fHottrackDone = false;

	if(dat->bisEmbedded) {
		rc.left = bg_indent_l;
		rc.top = y;
		rc.right = clRect->right - bg_indent_r;
		rc.bottom = y + rowHeight;
		if (fSelected) {
			FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_HIGHLIGHT));
			Gfx::setTextColor(dat->selTextColour);
		}
		else {
			FillRect(hdcMem, &rc, type == CLCIT_GROUP ? cfg::dat.hBrushCLCGroupsBk : cfg::dat.hBrushCLCBk);
			if(CLC::iHottrackItem)
				setHotTrackColour();
		}
		goto bgskipped;
	}
	if (type == CLCIT_CONTACT || type == CLCIT_DIVIDER) {
		TStatusItem *sitem, *pp_item;

		if (cstatus >= ID_STATUS_OFFLINE && cstatus <= ID_STATUS_OUTTOLUNCH) {
			BYTE perstatus_ignored;

			if((flags & CONTACTF_IDLE) && !Skin::statusItems[ID_EXTBKIDLE].IGNORED)
				sitem = &Skin::statusItems[ID_EXTBKIDLE];
			else
				sitem = &Skin::statusItems[cstatus - ID_STATUS_OFFLINE];

			if(!dat->bisEmbedded) {
				pp_item = cEntry->status_item ? cEntry->status_item : cEntry->proto_status_item;

				if (!(perstatus_ignored = sitem->IGNORED) && !(flags & CONTACTF_NOTONLIST))
					Gfx::setTextColor(sitem->TEXTCOLOR);

				if(cfg::dat.bUsePerProto && pp_item && !pp_item->IGNORED) {
					sitem = pp_item;
					if((perstatus_ignored || cfg::dat.bOverridePerStatusColors) && sitem->TEXTCOLOR != -1)
						Gfx::setTextColor(sitem->TEXTCOLOR);
				}
			}
			else if(!sitem->IGNORED)
				Gfx::setTextColor(sitem->TEXTCOLOR);

			rc.left = sitem->MARGIN_LEFT + bg_indent_l;
			rc.top = y + sitem->MARGIN_TOP;
			rc.right = clRect->right - sitem->MARGIN_RIGHT - bg_indent_r;
			rc.bottom = y + rowHeight - sitem->MARGIN_BOTTOM;

			// single item in a group
			if (!ssingleitem->IGNORED && scanIndex == 0 && group->cl.count == 1 && group->parent != NULL) {
				rc.left = ssingleitem->MARGIN_LEFT + bg_indent_l;
				rc.top = y + ssingleitem->MARGIN_TOP;
				rc.right = clRect->right - ssingleitem->MARGIN_RIGHT - bg_indent_r;
				rc.bottom = y + rowHeight - ssingleitem->MARGIN_BOTTOM;

				// draw odd/even contact underlay
				if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED)
					Gfx::renderSkinItem(this, sevencontact_pos, &rc);
				else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED)
					Gfx::renderSkinItem(this, soddcontact_pos, &rc);

				if (!sitem->IGNORED)
					Gfx::renderSkinItem(this, sitem, &rc);
				Gfx::renderSkinItem(this, ssingleitem, &rc);

			// first item in a group
			} else if (scanIndex == 0 && group->cl.count > 1 && !sfirstitem->IGNORED && group->parent != NULL) {
				rc.left = sfirstitem->MARGIN_LEFT + bg_indent_l;
				rc.top = y + sfirstitem->MARGIN_TOP;
				rc.right = clRect->right - sfirstitem->MARGIN_RIGHT - bg_indent_r;
				rc.bottom = y + rowHeight - sfirstitem->MARGIN_BOTTOM;

				current_shape = sfirstitem->rect;
				// draw odd/even contact underlay
				if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED)
					Gfx::renderSkinItem(this, sevencontact_pos, &rc);
				else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED)
					Gfx::renderSkinItem(this, soddcontact_pos, &rc);

				if (!sitem->IGNORED)
					Gfx::renderSkinItem(this, sitem, &rc);
				Gfx::renderSkinItem(this, sfirstitem, &rc);

			// last item in a group
			} else if (scanIndex == group->cl.count - 1 && !slastitem->IGNORED && group->parent != NULL) {
				rc.left = slastitem->MARGIN_LEFT + bg_indent_l;
				rc.top = y + slastitem->MARGIN_TOP;
				rc.right = clRect->right - slastitem->MARGIN_RIGHT - bg_indent_r;
				rc.bottom = y + rowHeight - slastitem->MARGIN_BOTTOM;
				rc.bottom = y + rowHeight - slastitem->MARGIN_BOTTOM;

				current_shape = slastitem->rect;
				// draw odd/even contact underlay
				if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED)
					Gfx::renderSkinItem(this, sevencontact_pos, &rc);
				else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED)
					Gfx::renderSkinItem(this, soddcontact_pos, &rc);

				if (!sitem->IGNORED)
					Gfx::renderSkinItem(this, sitem, &rc);
				Gfx::renderSkinItem(this, slastitem, &rc);
			} else {
				// - - - Non-grouped items - - -
				if (type != CLCIT_GROUP && group->parent == NULL && !sfirstitem_NG->IGNORED && scanIndex != group->cl.count - 1 && !(bFirstNGdrawn)) {
					// first NON-grouped
					bFirstNGdrawn = TRUE;
					rc.left = sfirstitem_NG->MARGIN_LEFT + bg_indent_l;
					rc.top = y + sfirstitem_NG->MARGIN_TOP;
					rc.right = clRect->right - sfirstitem_NG->MARGIN_RIGHT - bg_indent_r;
					rc.bottom = y + rowHeight - sfirstitem_NG->MARGIN_BOTTOM;

					// draw odd/even contact underlay
					if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED)
						Gfx::renderSkinItem(this, sevencontact_pos, &rc);
					else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED)
						Gfx::renderSkinItem(this, soddcontact_pos, &rc);

					if (!sitem->IGNORED)
						Gfx::renderSkinItem(this, sitem, &rc);
					Gfx::renderSkinItem(this, sfirstitem, &rc);

				} else if (type != CLCIT_GROUP && group->parent == NULL && !slastitem_NG->IGNORED && scanIndex == group->cl.count - 1 && (bFirstNGdrawn)) {
					// last item of list (NON-group)
					// last NON-grouped
					rc.left = slastitem_NG->MARGIN_LEFT + bg_indent_l;
					rc.top = y + slastitem_NG->MARGIN_TOP;
					rc.right = clRect->right - slastitem_NG->MARGIN_RIGHT - bg_indent_r;
					rc.bottom = y + rowHeight - slastitem_NG->MARGIN_BOTTOM;

					// draw odd/even contact underlay
					if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED)
						Gfx::renderSkinItem(this, sevencontact_pos, &rc);
					else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED)
						Gfx::renderSkinItem(this, soddcontact_pos, &rc);

					if (!sitem->IGNORED)
						Gfx::renderSkinItem(this, sitem, &rc);
					Gfx::renderSkinItem(this, slastitem, &rc);
				} else if (type != CLCIT_GROUP	&& group->parent == NULL && !slastitem_NG->IGNORED && !(bFirstNGdrawn)) {
					// single item of NON-group
					// single NON-grouped
					rc.left = ssingleitem_NG->MARGIN_LEFT + bg_indent_l;
					rc.top = y + ssingleitem_NG->MARGIN_TOP;
					rc.right = clRect->right - ssingleitem_NG->MARGIN_RIGHT - bg_indent_r;
					rc.bottom = y + rowHeight - ssingleitem_NG->MARGIN_BOTTOM;

					// draw odd/even contact underlay
					if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED)
						Gfx::renderSkinItem(this, sevencontact_pos, &rc);
					else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED)
						Gfx::renderSkinItem(this, soddcontact_pos, &rc);

					if (!sitem->IGNORED)
						Gfx::renderSkinItem(this, sitem, &rc);
					Gfx::renderSkinItem(this, ssingleitem, &rc);
				} else {
					// draw default grouped
					// draw odd/even contact underlay
					if ((scanIndex == 0 || scanIndex % 2 == 0) && !sevencontact_pos->IGNORED)
						Gfx::renderSkinItem(this, sevencontact_pos, &rc);
					else if (scanIndex % 2 != 0 && !soddcontact_pos->IGNORED)
						Gfx::renderSkinItem(this, soddcontact_pos, &rc);

					if(!sitem->IGNORED)
						Gfx::renderSkinItem(this, sitem, &rc);
				}
			}
		}
	}
	if (type == CLCIT_GROUP) {
		TStatusItem *sempty = &Skin::statusItems[ID_EXTBKEMPTYGROUPS];
		TStatusItem *sexpanded = &Skin::statusItems[ID_EXTBKEXPANDEDGROUP];
		TStatusItem *scollapsed = &Skin::statusItems[ID_EXTBKCOLLAPSEDDGROUP];

		changeToFont(FONTID_GROUPS);
		if (contact->group->cl.count == 0) {
			if (!sempty->IGNORED) {
				rc.left = sempty->MARGIN_LEFT + bg_indent_l;
				rc.top = y + sempty->MARGIN_TOP;
				rc.right = clRect->right - sempty->MARGIN_RIGHT - bg_indent_r;
				rc.bottom = y + rowHeight - sempty->MARGIN_BOTTOM;
				Gfx::renderSkinItem(this, sempty, &rc);
				oldGroupColor = GetTextColor(hdcMem);
				Gfx::setTextColor(sempty->TEXTCOLOR);
			}
		} else if (contact->group->expanded) {
			if (!sexpanded->IGNORED) {
				rc.left = sexpanded->MARGIN_LEFT + bg_indent_l;
				rc.top = y + sexpanded->MARGIN_TOP;
				rc.right = clRect->right - sexpanded->MARGIN_RIGHT - bg_indent_r;
				rc.bottom = y + rowHeight - (char) sexpanded->MARGIN_BOTTOM;
				Gfx::renderSkinItem(this, sexpanded, &rc);
				oldGroupColor =GetTextColor(hdcMem);
				Gfx::setTextColor(sexpanded->TEXTCOLOR);
			}
		} else {
			if (!scollapsed->IGNORED) {
				// collapsed but not empty
				rc.left = scollapsed->MARGIN_LEFT + bg_indent_l;
				rc.top = y + scollapsed->MARGIN_TOP;
				rc.right = clRect->right - scollapsed->MARGIN_RIGHT - bg_indent_r;
				rc.bottom = y + rowHeight - scollapsed->MARGIN_BOTTOM;
				Gfx::renderSkinItem(this, scollapsed, &rc);
				oldGroupColor = GetTextColor(hdcMem);
				Gfx::setTextColor(scollapsed->TEXTCOLOR);
			}
		}
	}
	if (fSelected) {
		TStatusItem *sselected = &Skin::statusItems[ID_EXTBKSELECTION];

		if (!g_ignoreselforgroups || type != CLCIT_GROUP) {
			rc.left = sselected->MARGIN_LEFT + bg_indent_l;
			rc.top = y + sselected->MARGIN_TOP;
			rc.right = clRect->right - sselected->MARGIN_RIGHT - bg_indent_r;
			rc.bottom = y + rowHeight - sselected->MARGIN_BOTTOM;
			Gfx::renderSkinItem(this, sselected, &rc);
			Gfx::setTextColor(sselected->TEXTCOLOR);
		}
	}
	else if (CLC::iHottrackItem) {
		TStatusItem *ht = &Skin::statusItems[ID_EXTBKHOTTRACK];

		if(ht->IGNORED == 0)
			Gfx::setTextColor(ht->TEXTCOLOR);
		if(!CLC::fHottrackDone) {
			if (ht->IGNORED == 0) {
				Gfx::renderSkinItem(this, ht, &rc);
			}
		}
	}

	if(g_RTL) {
		SetLayout(hdcMem, LAYOUT_RTL | LAYOUT_BITMAPORIENTATIONPRESERVED);
		dxBufferDiff = dBufferDiff;
	}
	else
		dxBufferDiff = 0;					// adjust discrepancy between the width of the buffered paint dc and the actual window width (bug in buffered paint?)
bgskipped:

	rcContent.top = y + g_padding_y;
	rcContent.bottom = y + rowHeight - (2 * g_padding_y);
	rcContent.left = leftX + dxBufferDiff;
	rcContent.right = clRect->right - dat->rightMargin + dxBufferDiff;
	twoRows = ((dat->fontInfo[FONTID_STATUS].fontHeight + m_fontHeight <= rowHeight + 1) && (fSecondLine)) && !dat->bisEmbedded;

	pi_avatar = (!dat->bisEmbedded && fAvatar);

	//checkboxes
	if (checkboxWidth) {
		RECT 	rc;

		rc.left = leftX;
		rc.right = rc.left + dat->checkboxSize;
		rc.top = y + ((rowHeight - dat->checkboxSize) >> 1);
		rc.bottom = rc.top + dat->checkboxSize;
		if (hTheme) {
			Api::pfnDrawThemeBackground(hTheme, hdcMem, BP_CHECKBOX, flags & CONTACTF_CHECKED ? (CLC::iHottrackItem ? CBS_CHECKEDHOT : CBS_CHECKEDNORMAL) :
					(CLC::iHottrackItem ? CBS_UNCHECKEDHOT : CBS_UNCHECKEDNORMAL), &rc, &rc);
		}
		else
			DrawFrameControl(hdcMem, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT | (flags & CONTACTF_CHECKED ? DFCS_CHECKED : 0) | (CLC::iHottrackItem ? DFCS_HOT : 0));
		rcContent.left += checkboxWidth;
		leftX += checkboxWidth;
	}

	if (type == CLCIT_GROUP)
		iImage = (contact->group->expanded) ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT;
	else if (type == CLCIT_CONTACT)
		iImage = contact->iImage;


	if(pi_avatar && (av_left || av_right)) {
		RECT rc;

		rc.left = rcContent.left;
		rc.right = clRect->right;
		rc.top = y;
		rc.bottom = rc.top + rowHeight;

		if(av_left) {
			leftOffset += drawAvatar(&rc, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight);
			rcContent.left += leftOffset;
			leftX += leftOffset;
		}
		else {
			rc.left = (rcContent.right - cfg::dat.avatarSize) + 1;
			rightOffset += drawAvatar(&rc, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight);
			rcContent.right -= (rightOffset);
		}
	}
	else if(type == CLCIT_CONTACT && !dat->bisEmbedded && !g_selectiveIcon && (dwFlags & CLUI_FRAME_ALWAYSALIGNNICK) && av_local_wanted && (av_left || av_right)) {
		if(av_right)
			rcContent.right -= (cfg::dat.avatarSize + 2);
		if(av_left)
			rcContent.left += (cfg::dat.avatarSize + 2);
	}
	//icon

	// skip icon for groups if the option is enabled...

	if(type == CLCIT_GROUP && dwFlags & CLUI_FRAME_NOGROUPICON) {
		iconXSpace = 0;
		goto text;
	}
	if (iImage != -1) {
		// this doesnt use CLS_CONTACTLIST since the colour prolly wont match anyway
		COLORREF colourFg = dat->selBkColour;
		//int clientId = contact->clientId;
		int mode = ILD_NORMAL;
		pi_selectiveIcon = g_selectiveIcon && (type == CLCIT_CONTACT);

		if((dwFlags & CLUI_FRAME_STATUSICONS && !pi_selectiveIcon) || type != CLCIT_CONTACT || (pi_selectiveIcon && !avatar_done)) {
			HIMAGELIST hImgList = CLC::hClistImages;

			if (CLC::iHottrackItem) {
				colourFg = dat->hotTextColour;
			} else if (type == CLCIT_CONTACT && flags & CONTACTF_NOTONLIST) {
				colourFg = dat->fontInfo[FONTID_NOTONLIST].colour;
				mode = ILD_BLEND50;
			}
			if (type == CLCIT_CONTACT && dat->showIdle && (flags & CONTACTF_IDLE) && contact->wStatus != ID_STATUS_OFFLINE)
				mode = ILD_SELECTED;

			if(pi_selectiveIcon && av_right) {
				ImageList_DrawEx(hImgList, iImage, hdcMem, rcContent.right - 18, (twoRows && type == CLCIT_CONTACT && !cfg::dat.bCenterStatusIcons) ? y + 2 : y + ((rowHeight - 16) >> 1), 0, 0, CLR_NONE, colourFg, mode);
				rcContent.right -= 18;
			}
			else {
				LONG offset = 0;
				BOOL centered = FALSE;
				offset +=  (type != CLCIT_CONTACT || avatar_done || !(av_local_wanted) ? 20 : dwFlags & CLUI_FRAME_ALWAYSALIGNNICK && av_left && g_selectiveIcon ? cfg::dat.avatarSize + 2 : 20);
				centered = (cfg::dat.bCenterStatusIcons && offset == cfg::dat.avatarSize + 2);
				ImageList_DrawEx(hImgList, iImage, hdcMem,  centered ? rcContent.left + offset / 2 - 10 : rcContent.left, (twoRows && type == CLCIT_CONTACT && !cfg::dat.bCenterStatusIcons) ? y + 2 : y + ((rowHeight - 16) >> 1), 0, 0, CLR_NONE, colourFg, mode);
				rcContent.left += offset;
			}
		}
		else
			iconXSpace = 0;
		if (type == CLCIT_CONTACT && !dat->bisEmbedded) {
			BYTE bApparentModeDontCare = !((flags & CONTACTF_VISTO) ^ (flags & CONTACTF_INVISTO));
			contact->extraIconRightBegin = 0;
			if(cEntry && (contact->extraCacheEntry >= 0 && contact->extraCacheEntry < cfg::nextCacheEntry && cEntry->iExtraValid)) {
				int i, iIndex, id;
				DWORD dwOldMask = cEntry->dwXMask;

				for(i = EXICON_COUNT - 1; i >= 0; i--) {
					iIndex = cfg::dat.exIconOrder[i] - 1;
					if(iIndex >= 0 && iIndex < EXICON_COUNT) {
						id = OrderTreeData[iIndex].ID;
						if(cEntry->iExtraImage[id] != 0xff && ((1 << id) & cEntry->dwXMask)) {
							if(contact->extraIconRightBegin == 0 && i != (EXICON_COUNT - 1))
								contact->extraIconRightBegin = rcContent.right;
							ImageList_DrawEx(dat->himlExtraColumns, cEntry->iExtraImage[id], hdcMem, rcContent.right - cfg::dat.exIconScale, twoRows ? rcContent.bottom - g_exIconSpacing : y + ((rowHeight - cfg::dat.exIconScale) >> 1),
								0, 0, CLR_NONE, CLR_NONE, ILD_NORMAL);
							rcContent.right -= g_exIconSpacing;
							rightIcons++;
						}
					}
				}
				cEntry->dwXMask = dwOldMask;
			}
			if (!bApparentModeDontCare && (dwFlags & CLUI_SHOWVISI) && contact->proto) {
				BOOL fVisi;

				if(dwFlags & CLUI_SHOWVISI)
					fVisi = contact->dwDFlags & ECF_HIDEVISIBILITY ? 0 : 1;
				else
					fVisi = contact->dwDFlags & ECF_FORCEVISIBILITY ? 1 : 0;

				if(fVisi) {
					if(cEntry->isChatRoom)
						DrawIconEx(hdcMem, rcContent.right - cfg::dat.exIconScale, twoRows ? rcContent.bottom - g_exIconSpacing : y + ((rowHeight - cfg::dat.exIconScale) >> 1),
						cfg::dat.hIconChatactive, cfg::dat.exIconScale, cfg::dat.exIconScale, 0, 0, DI_NORMAL | DI_COMPAT);
					else
						DrawIconEx(hdcMem, rcContent.right - cfg::dat.exIconScale, twoRows ? rcContent.bottom - g_exIconSpacing : y + ((rowHeight - cfg::dat.exIconScale) >> 1),
						flags & CONTACTF_VISTO ? cfg::dat.hIconVisible : cfg::dat.hIconInvisible, cfg::dat.exIconScale, cfg::dat.exIconScale, 0, 0, DI_NORMAL | DI_COMPAT);
					rcContent.right -= g_exIconSpacing;
					rightIcons++;
				}
			}
		}
	}
	//text
text:
	if (type == CLCIT_DIVIDER) {
		RECT rc, rcText;
		rc.top = y + ((rowHeight) >> 1) - 1; rc.bottom = rc.top + 2;
		rc.left = clRect->left + dat->leftMargin;
		rc.right = rc.left - dat->rightMargin + ((clRect->right - rc.left - textSize.cx) >> 1) - 3;
		DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT);
		Api::pfnBufferedPaintSetAlpha(hbp, &rc, 255);
		rcText.left = rc.right + 3;
		rcText.top = y;
		rcText.bottom = y + rowHeight;
		rcText.right = rcText.left + textSize.cx;
		Gfx::renderText(hdcMem, hTheme, contact->szText, &rcText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
		rc.left = rc.right + 6 + textSize.cx;
		rc.right = clRect->right - dat->rightMargin;
		DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT);
		Api::pfnBufferedPaintSetAlpha(hbp, &rc, 255);
	} else if (type == CLCIT_GROUP) {
		RECT rc;
		m_fontHeight = dat->fontInfo[FONTID_GROUPS].fontHeight;
		rc.top = y + ((rowHeight - m_fontHeight) >> 1) + cfg::dat.group_padding;
		rc.bottom = rc.top + textSize.cy;
		if (szCounts[0]) {
			int required, labelWidth, offset = 0;
			COLORREF clr = GetTextColor(hdcMem);

			changeToFont(FONTID_GROUPCOUNTS);
			if(oldGroupColor != -1)
				Gfx::setTextColor(clr);

			rc.left = dat->leftMargin + indent * dat->groupIndent + checkboxWidth + iconXSpace;
			rc.right = clRect->right - dat->rightMargin;

			if(indent == 0 && iconXSpace == 0)
				rc.left += 2;

			required = textSize.cx + countsSize.cx + spaceSize.cx;

			if(required > rc.right - rc.left)
				textSize.cx = (rc.right - rc.left) - countsSize.cx - spaceSize.cx;

			labelWidth = textSize.cx + countsSize.cx + spaceSize.cx;
			if(g_center)
				offset = ((rc.right - rc.left) - labelWidth) / 2;

			RECT rcCounts = rc;
			rcCounts.left += (offset + textSize.cx + spaceSize.cx + dxBufferDiff);
			rcCounts.right += dxBufferDiff;
			rcCounts.top += groupCountsFontTopShift;
			Gfx::renderText(hdcMem, hTheme, wszCounts, &rcCounts, DT_SINGLELINE);
			mir_free(wszCounts);

			if (fSelected && !g_ignoreselforgroups)
				clr = dat->selTextColour;
			else
				Gfx::setTextColor(clr);
			changeToFont(FONTID_GROUPS);
			rc.left += (offset + dxBufferDiff);
			rc.right = rc.left + textSize.cx;
			qLeft = rc.left;

			Gfx::renderText(hdcMem, hTheme, contact->szText, &rc, DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS);
		} else if (g_center && !szCounts[0]) {
			int offset;

			rc.left = rcContent.left;
			rc.right = clRect->right - dat->rightMargin;
			if(textSize.cx >= rc.right - rc.left)
				textSize.cx = rc.right - rc.left;

			offset = ((rc.right - rc.left) - textSize.cx) / 2;
			rc.left += (offset + dxBufferDiff);
			rc.right = rc.left + textSize.cx + dxBufferDiff;
			Gfx::renderText(hdcMem, hTheme, contact->szText, &rc, DT_CENTER | DT_NOPREFIX | DT_SINGLELINE);
			qLeft = rc.left;
		} else {
			qLeft = rcContent.left + (indent == 0 && iconXSpace == 0 ? 2 : 0);
			rc.left = qLeft;
			rc.right = min(rc.left + textSize.cx, clRect->right - dat->rightMargin) + dxBufferDiff;
			Gfx::renderText(hdcMem, hTheme, contact->szText, &rc, DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS);
		}
	} else {
		wchar_t *szText = contact->szText;

		rcContent.top = y + ((rowHeight - m_fontHeight) >> 1);

		// avatar

		if(!dat->bisEmbedded) {
			if(av_local_wanted && !avatar_done && pi_avatar) {
				if(av_rightwithnick) {
					RECT rcAvatar = rcContent;

					rcAvatar.left = rcContent.right - (cfg::dat.avatarSize - 1);
					drawAvatar(&rcAvatar, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight);
					rcContent.right -= (cfg::dat.avatarSize + 2);
				}
				else
					rcContent.left += drawAvatar(&rcContent, contact, y, (WORD)(iImage ? cstatus : 0), rowHeight);
			}
			else if(dwFlags & CLUI_FRAME_ALWAYSALIGNNICK && !avatar_done && av_local_wanted)
				rcContent.left += (dwFlags & (CLUI_FRAME_AVATARSLEFT | CLUI_FRAME_AVATARSRIGHT | CLUI_FRAME_AVATARSRIGHTWITHNICK) ? 0 : cfg::dat.avatarSize + 2);
		}

		// nickname
		if(!twoRows)
			Gfx::renderText(hdcMem, hTheme, szText, &rcContent, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE | dt_nickflags);
		else {
			DWORD dtFlags = DT_WORD_ELLIPSIS | DT_NOPREFIX | DT_NOCLIP | DT_SINGLELINE;
			DWORD saved_right = rcContent.right;
			BOOL verticalfit = FALSE;

			rcContent.top = y + cfg::dat.avatarPadding / 2;

			if(cfg::dat.bShowLocalTime)
				fLocalTime = contact->dwDFlags & ECF_HIDELOCALTIME ? 0 : 1;
			else
				fLocalTime = contact->dwDFlags & ECF_FORCELOCALTIME ? 1 : 0;

			if(cEntry->hTimeZone != 0 && fLocalTime) {
				wchar_t 	szResult[80];
				int  		idOldFont;
				SIZE 		szTime;
				RECT 		rc = rcContent;
				COLORREF 	oldColor = 0;

				if (TimeZone_PrintDateTime(cEntry->hTimeZone, L"t", szResult, _countof(szResult), 0))
					goto nodisplay;

				oldColor = Gfx::getTextColor();
				idOldFont = dat->currentFontID;
				changeToFont(FONTID_TIMESTAMP);
				GetTextExtentPoint32(hdcMem, szResult, lstrlenW(szResult), &szTime);
				verticalfit = ((rowHeight - szTime.cy) >= (cfg::dat.exIconScale + 1));

				if(av_right) {
					if(verticalfit)
						rc.left = rcContent.right + (rightIcons * g_exIconSpacing) - szTime.cx - 2;
					else
						rc.left = rcContent.right - szTime.cx - 2;
				}
				else if(av_rightwithnick) {
					if(verticalfit && rightIcons * g_exIconSpacing >= szTime.cx)
						rc.left = (clRect->right - dat->rightMargin - szTime.cx) + dxBufferDiff;
					else if(verticalfit && !avatar_done)
						rc.left = (clRect->right - dat->rightMargin - szTime.cx) + dxBufferDiff;
					else {
						rc.left = rcContent.right - szTime.cx - 2;
						rcContent.right = rc.left - 2;
					}
				}
				else {
					if(verticalfit)
						rc.left = (clRect->right - dat->rightMargin - szTime.cx) + dxBufferDiff;
					else
						rc.left = rcContent.right - szTime.cx - 2;
				}
				rc.right = clRect->right + dxBufferDiff;
				Gfx::renderText(hdcMem, hTheme, szResult, &rc, DT_NOPREFIX | DT_NOCLIP | DT_SINGLELINE);
				changeToFont(idOldFont);
				Gfx::setTextColor(oldColor);

				verticalfit = (rowHeight - m_fontHeight >= cfg::dat.exIconScale + 1);
				if(verticalfit && av_right)
					rcContent.right = min((clRect->right - cfg::dat.avatarSize - 2) + dxBufferDiff, rc.left - 2);
				else if(verticalfit && !av_rightwithnick)
					rcContent.right = min((clRect->right - dat->rightMargin) + dxBufferDiff, rc.left - 3);

			}
			else {
nodisplay:
				verticalfit = (rowHeight - m_fontHeight >= cfg::dat.exIconScale + 1);
				if(avatar_done) {
					if(verticalfit && av_right)
						rcContent.right = (clRect->right - cfg::dat.avatarSize - 2) + dxBufferDiff;
					else if(verticalfit && !av_rightwithnick)
						rcContent.right = (clRect->right - dat->rightMargin) + dxBufferDiff;
				}
			}
			Gfx::renderText(hdcMem, hTheme, szText, &rcContent, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE | dt_nickflags);

			rcContent.right = saved_right;
			rcContent.top += (m_fontHeight - 1);
			hPreviousFont = changeToFont(FONTID_STATUS);
			rcContent.bottom = y + rowHeight;

			if(cstatus >= ID_STATUS_OFFLINE && cstatus <= ID_STATUS_OUTTOLUNCH) {
				wchar_t *szText = NULL;
				BYTE smsgValid = cEntry->bStatusMsgValid;

				if((dwFlags & CLUI_FRAME_SHOWSTATUSMSG && smsgValid > STATUSMSG_XSTATUSID) || smsgValid == STATUSMSG_XSTATUSNAME)
					szText = cEntry->statusMsg;
				else
					szText = &statusNames[cstatus - ID_STATUS_OFFLINE][0];
				if(cEntry->dwCFlags & ECF_RTLSTATUSMSG && cfg::dat.bUseDCMirroring == 3)
					dt_2ndrowflags |= (DT_RTLREADING | DT_RIGHT);

				if(rightIcons == 0) {
					if((rcContent.bottom - rcContent.top) >= (2 * m_fontHeight)) {
						dtFlags &= ~(DT_SINGLELINE | DT_BOTTOM | DT_NOCLIP);
						dtFlags |= DT_WORDBREAK;
						rcContent.bottom -= ((rcContent.bottom - rcContent.top) % m_fontHeight);
					}
					Gfx::renderText(hdcMem, hTheme, szText, &rcContent, dtFlags | dt_2ndrowflags);
				}
				else {
					if((rcContent.bottom - rcContent.top) < (2 * m_fontHeight) - 2)
						Gfx::renderText(hdcMem, hTheme, szText, &rcContent, dtFlags | dt_2ndrowflags);
					else {
						DRAWTEXTPARAMS dtp = {0};
						LONG 	rightIconsTop = rcContent.bottom - g_exIconSpacing;
						LONG 	old_right = rcContent.right;
						ULONG 	textCounter = 0;
						ULONG 	ulLen = lstrlen(szText);
						LONG 	old_bottom = rcContent.bottom;
						DWORD 	i_dtFlags = DT_WORDBREAK | DT_NOPREFIX | dt_2ndrowflags;
						dtp.cbSize = sizeof(dtp);
						rcContent.right = clRect->right - dat->rightMargin - rightOffset;
						do {
							if(rcContent.top + (m_fontHeight - 1) > rightIconsTop + 1)
								rcContent.right = old_right;
							dtp.uiLengthDrawn = 0;
							rcContent.bottom = rcContent.top + m_fontHeight - 1;
							if(rcContent.bottom + m_fontHeight >= old_bottom)
								i_dtFlags |= DT_END_ELLIPSIS;
							DrawTextEx(hdcMem, &szText[textCounter], -1, &rcContent, i_dtFlags | DT_CALCRECT, &dtp);
							if(dtp.uiLengthDrawn)
								Gfx::renderText(hdcMem, hTheme, &szText[textCounter], &rcContent, i_dtFlags, 0, dtp.uiLengthDrawn);
							rcContent.top += m_fontHeight;
							textCounter += dtp.uiLengthDrawn;
						} while (textCounter <= ulLen && dtp.uiLengthDrawn && rcContent.top + m_fontHeight <= old_bottom);
					}
				}
			}
		}
	}
	if (fSelected) {
		if (type != CLCIT_DIVIDER) {
			wchar_t *szText = contact->szText;
			RECT rc;
			int qlen = lstrlen(dat->szQuickSearch);
			if(hPreviousFont)
				SelectObject(hdcMem, hPreviousFont);
			Gfx::setTextColor(dat->quickSearchColour);
			if(type == CLCIT_CONTACT) {
				rc.left = rcContent.left;
				rc.top = y + ((rowHeight - m_fontHeight) >> 1);
				rc.right = clRect->right - rightOffset;
				rc.right = rcContent.right;
				rc.bottom = rc.top;
				if(twoRows)
					rc.top = y;
			}
			else {
				rc.left = qLeft;
				rc.top = y + ((rowHeight - m_fontHeight) >> 1);
				rc.right = clRect->right - rightOffset;
				rc.bottom = rc.top;
			}
			if (qlen)
				Gfx::renderText(hdcMem, hTheme, szText, &rc, DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP | DT_WORD_ELLIPSIS | DT_SINGLELINE);
		}
	}
	//extra icons
	DWORD spacing = 1;
	for (int i = dat->extraColumnsCount - 1; i >= 0; i--) {
		COLORREF colourFg = dat->selBkColour;
		int mode = ILD_NORMAL;
		if (contact->iExtraImage[i] == 0xffff)
			continue;
		if (fSelected)
			mode = ILD_SELECTED;
		else if (CLC::iHottrackItem) {
			mode = ILD_FOCUS; colourFg = dat->hotTextColour;
		} else if (type == CLCIT_CONTACT && flags & CONTACTF_NOTONLIST) {
			colourFg = dat->fontInfo[FONTID_NOTONLIST].colour; mode = ILD_BLEND50;
		}
		ImageList_DrawEx(dat->himlExtraColumns, contact->iExtraImage[i], hdcMem, clRect->right - rightOffset - dat->extraColumnSpacing * (spacing++), y + ((rowHeight - 16) >> 1), 0, 0, CLR_NONE, colourFg, mode);
	}
	if(g_RTL)
		SetLayout(hdcMem, 0);
}

void CLC::Paint(HWND hwnd, ClcData *dat, HDC hdc, RECT *rcPaint)
{
	RGBQUAD*	rgq = 0;
	ClcContact* contact;
	int			ipxWidth = 0;
	HDC 		hdcMem;
	RECT 		clRect;
	ClcGroup*	group;
	HANDLE 		hbp = 0;
	HFONT 		hOldFont = 0;
	DWORD 		style = GetWindowLong(hwnd, GWL_STYLE);
	int 		grey = 0, groupCountsFontTopShift;
	int 		line_num = -1;
	COLORREF 	tmpbkcolour = style & CLS_CONTACTLIST ? (dat->useWindowsColours ? GetSysColor(COLOR_3DFACE) : dat->bkColour) : dat->bkColour;
	BOOL		isFloating = (wndFrameCLC && wndFrameCLC->floating) ? TRUE : FALSE;
	bool		fFocusCheck;

	fInPaint = true;
	g_focusWnd = GetFocus();
	my_status = getGeneralisedStatus();
	g_HDC = hdc;

	/*
	 * temporary DC for avatar drawing
	*/

	g_padding_y = 0;

	hdcTempAV = CreateCompatibleDC(g_HDC);
	hbmTempAV = CreateCompatibleBitmap(g_HDC, g_maxAV_X, g_maxAV_Y);
	hbmTempOldAV = reinterpret_cast<HBITMAP>(SelectObject(hdcTempAV, hbmTempAV));

	cfg::dat.t_now = time(NULL);

	/*
	 * setup static globals used by PaintItem();
	 */
	av_left = 			(cfg::dat.dwFlags & CLUI_FRAME_AVATARSLEFT);
	av_right = 			(cfg::dat.dwFlags & CLUI_FRAME_AVATARSRIGHT);
	av_rightwithnick = 	(cfg::dat.dwFlags & CLUI_FRAME_AVATARSRIGHTWITHNICK);

	mirror_rtl = 		(cfg::dat.bUseDCMirroring == 2);
	mirror_always = 	(cfg::dat.bUseDCMirroring == 1);
	mirror_rtltext = 	(cfg::dat.bUseDCMirroring == 3);

	g_center = 			cfg::getByte("CLCExt", "EXBK_CenterGroupnames", 0) && !dat->bisEmbedded;
	g_ignoreselforgroups = cfg::getByte("CLC", "IgnoreSelforGroups", 0);
	g_exIconSpacing = 	cfg::dat.exIconScale + 2;

	/*
	 * check if list should be greyed out based on focus or current status
	 */
	if (GetForegroundWindow()!= pcli->hwndContactList && dat->greyoutFlags & GREYF_UNFOCUS)
		grey = 1;
	else if((dat->greyoutFlags & pcli->pfnClcStatusToPf2(my_status)) || style & WS_DISABLED)
		grey = 1;

	GetClientRect(hwnd, &clRect);
	if (rcPaint == NULL)
		rcPaint = &clRect;

#ifndef _USE_D2D
	if (IsRectEmpty(rcPaint)) {
		SelectObject(hdcTempAV, hbmTempOldAV);
		DeleteObject(hbmTempAV);
		DeleteDC(hdcTempAV);
		return;
	}
#endif

#ifdef _USE_D2D
	HBITMAP hbmMem, hbmMemOld;
	if(hwnd == pcli->hwndContactTree) {
		rcPaint = &clRect;
		hdcMem = CreateCompatibleDC(cfg::dat.hdcBg);
		hbmMem = Gfx::createRGBABitmap(clRect.right - clRect.left, clRect.bottom - clRect.top, hdcMem);
		hbmMemOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
	}
	else
		hbp = Gfx::initiateBufferedPaint(hdc, clRect, hdcMem);
#else
	/* explanation for this weird code.. (dBufferDiff etc..)
	 * a bufferend paint dc is normally not the same size as the client rectangle of a
	 * child window (CLC in this case). It's usually much wider. This isn't a problem
	 * for LTR rendering where everything starts at (0,0) but when using SetLayout()
	 * to mirror the DC (for RTL support) it becomes a HUGE problem, because right
	 * becomes left and content will vanish outside the client area.
	 *
	 * dBufferDiff is the difference between the width of the buffered DC and the width
	 * of the actual client rectangle. PaintItem() will add that offset to rcContent.left
	 * when rendering RTL rows to compensate for the difference in width.
	 *
	 */
	dBufferDiff = 0;
	INIT_PAINT(hdc, clRect, hdcMem);
	Api::pfnGetBufferedPaintBits(hbp, &rgq, &ipxWidth);
	dBufferDiff = ipxWidth - clRect.right;
#endif

	{
		TEXTMETRIC tm;
		hOldFont = reinterpret_cast<HFONT>(SelectObject(hdcMem, dat->fontInfo[FONTID_GROUPS].hFont));
		GetTextMetrics(hdcMem, &tm);
		groupCountsFontTopShift = tm.tmAscent;
		SelectObject(hdcMem, dat->fontInfo[FONTID_GROUPCOUNTS].hFont);
		GetTextMetrics(hdcMem, &tm);
		groupCountsFontTopShift -= tm.tmAscent;
	}

	SetBkMode(hdcMem, TRANSPARENT);
	if(!cfg::isAero || dat->bisEmbedded || isFloating) {
		HBRUSH hBrush, hoBrush;
		hBrush = CreateSolidBrush(tmpbkcolour);
		hoBrush = (HBRUSH) SelectObject(hdcMem, hBrush);
		FillRect(hdcMem, rcPaint, hBrush);
		SelectObject(hdcMem, hoBrush);
		DeleteObject(hBrush);
	}

	if(!dat->bisEmbedded && rcPaint && !isFloating)
		Gfx::drawBGFromSurface(hwnd, *rcPaint, hdcMem);

	g_selectiveIcon = (CLC::uNrAvatars > 0) && (cfg::dat.dwFlags & CLUI_FRAME_SELECTIVEICONS) && !dat->bisEmbedded;

	group = &dat->list;
	group->scanIndex = 0;

	CLCPaintHelper* ph = dat->ph;

	fFocusCheck = dat->showSelAlways || dat->exStyle &CLS_EX_SHOWSELALWAYS || g_focusWnd == hwnd;

	// set up the paint helper 
	ph->setHDC(hdcMem);
	ph->aggctx->attach(rgq, ipxWidth, clRect.bottom);
	ph->hTheme = Api::pfnOpenThemeData(hwnd, L"BUTTON");
	ph->style = style;
	ph->clRect = &clRect;
	ph->y = -dat->yScroll;
	ph->indent = 0;
	ph->bFirstNGdrawn = false;
	ph->groupCountsFontTopShift = groupCountsFontTopShift;
	ph->hbp = hbp;

	ph->sevencontact_pos = &Skin::statusItems[ID_EXTBKEVEN_CNTCTPOS];
	ph->soddcontact_pos = &Skin::statusItems[ID_EXTBKODD_CNTCTPOS];
	ph->sfirstitem = &Skin::statusItems[ID_EXTBKFIRSTITEM];
	ph->ssingleitem = &Skin::statusItems[ID_EXTBKSINGLEITEM];
	ph->slastitem = &Skin::statusItems[ID_EXTBKLASTITEM];

	ph->sfirstitem_NG = &Skin::statusItems[ID_EXTBKFIRSTITEM_NG];
	ph->ssingleitem_NG = &Skin::statusItems[ID_EXTBKSINGLEITEM_NG];
	ph->slastitem_NG = &Skin::statusItems[ID_EXTBKLASTITEM_NG];


	hOldFont = ph->changeToFont(FONTID_CONTACTS);

	if ( dat->row_heights == NULL )
		RowHeight::calcRowHeights(dat, hwnd, ph);

	for (ph->index = 0; ph->y < rcPaint->bottom;) {
		if (group->scanIndex == group->cl.count) {
			group = group->parent;
			ph->indent--;
			if (group == NULL) {
				break;
			}
			group->scanIndex++;
			continue;
		}

		line_num++;
		contact = group->cl.items[group->scanIndex];
		if(cfg::dat.bForceRefetchOnPaint)
			contact->ace = (struct avatarCacheEntry*)-1;

		if (ph->y > rcPaint->top - dat->row_heights[line_num] && ph->y <= rcPaint->bottom) {
			if (contact->ace == (struct avatarCacheEntry*)-1 )
				contact->ace = (struct avatarCacheEntry *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)group->cl.items[group->scanIndex]->hContact, 0);

			ph->fSelected = (ph->index == dat->selection && contact->type != CLCIT_DIVIDER && fFocusCheck);
			iHottrackItem = dat->exStyle & CLS_EX_TRACKSELECT && contact->type == CLCIT_CONTACT && dat->iHotTrack == ph->index;
			if (iHottrackItem == ph->fSelected)
				iHottrackItem = 0;
			if(ph->fSelected && dsp_default.dspOverride[DSP_OVR_SELECTED].fActive)
				ph->dsp = &dsp_default.dspOverride[DSP_OVR_SELECTED];
			else if(iHottrackItem && dsp_default.dspOverride[DSP_OVR_HOVERED].fActive)
				ph->dsp = &dsp_default.dspOverride[DSP_OVR_HOVERED];
			else if(ID_STATUS_OFFLINE == contact->wStatus)
				ph->dsp = &dsp_default.dspOverride[DSP_OVR_OFFLINE];
			else if(ID_STATUS_OFFLINE != contact->wStatus)
				ph->dsp = &dsp_default.dspOverride[DSP_OVR_ONLINE];
			else
				ph->dsp = 0;						// calc dsp profile
			RowHeight::getRowHeight(dat, contact, line_num, style, ph);
			ph->Paint(group, contact, dat->row_heights[line_num]);
		}
		ph->index++;
		ph->y += dat->row_heights[line_num];
		if (contact->type == CLCIT_GROUP && (contact->group->expanded)) {
			group = contact->group;
			ph->indent++;
			group->scanIndex = 0;
			continue;
		}
		group->scanIndex++;
	}

	SelectObject(hdcTempAV, hbmTempOldAV);
	DeleteObject(hbmTempAV);
	DeleteDC(hdcTempAV);
	Api::pfnCloseThemeData(ph->hTheme);

	if (dat->iInsertionMark != -1) {
		//insertion mark
		HBRUSH hBrush, hoBrush;
		POINT pts[8];
		HRGN hRgn;

		pts[0].x=dat->leftMargin; pts[0].y = RowHeight::getItemTopY(dat, dat->iInsertionMark) - dat->yScroll - 4;
		//pts[0]. x = dat->leftMargin; pts[0]. y = dat->iInsertionMark * rowHeight - dat->yScroll - 4;
		pts[1]. x = pts[0].x + 2;      pts[1]. y = pts[0].y + 3;
		pts[2]. x = clRect.right - 4;  pts[2]. y = pts[1].y;
		pts[3]. x = clRect.right - 1;  pts[3]. y = pts[0].y - 1;
		pts[4]. x = pts[3].x;        pts[4]. y = pts[0].y + 7;
		pts[5]. x = pts[2].x + 1;      pts[5]. y = pts[1].y + 2;
		pts[6]. x = pts[1].x;        pts[6]. y = pts[5].y;
		pts[7]. x = pts[0].x;        pts[7]. y = pts[4].y;
		hRgn = CreatePolygonRgn(pts, sizeof(pts) / sizeof(pts[0]), ALTERNATE);
		hBrush = CreateSolidBrush(dat->fontInfo[FONTID_CONTACTS].colour);
		hoBrush = (HBRUSH) SelectObject(hdcMem, hBrush);
		FillRgn(hdcMem, hRgn, hBrush);
		SelectObject(hdcMem, hoBrush);
		DeleteObject(hBrush);
	}
	if(hOldFont)
		SelectObject(hdcMem, hOldFont);

	fInPaint = false;
	if (grey)
		Skin::renderNamedImageItem("@GreyOut", &clRect, hdcMem);

#if defined _USE_D2D
	if(hwnd == pcli->hwndContactTree) {
		MapWindowPoints(pcli->hwndContactTree, pcli->hwndContactList, (POINT*)&clRect, 2);
		Gfx::setBitmapAlpha(hbmMem, 0);
		Api::pfnAlphaBlend(cfg::dat.hdcBg, clRect.left, clRect.top, clRect.right - clRect.left, clRect.bottom - clRect.top,
				hdcMem, 0, 0, clRect.right - clRect.left, clRect.bottom - clRect.top, CLUI::bf);
		SelectObject(hdcMem, hbmMemOld);
		DeleteObject(hbmMem);
		DeleteDC(hdcMem);
		CLUI::updateLayers();
	}
	else
		FINALIZE_PAINT(hbp, &clRect);
#else
	//delete _g;
	FINALIZE_PAINT(hbp, &clRect, isFloating ? 255 : 0);
#endif
}