/*

Miranda NG: the free IM client for Microsoft* Windows*

Copyright (�) 2012-17 Miranda NG project (http://miranda-ng.org),
Copyright (c) 2000-08 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.
*/

#include "stdafx.h"
#include "modern_clcpaint.h"

CLCPaint g_clcPainter;

DWORD CLCPaint::HASH[hi_LastItem] = { 0 };
const char* CLCPaint::HASHTEXT[hi_LastItem] = {
	"Module",
	"ID",
	"Type",
	"Open",
	"IsEmpty",
	"SubPos",
	"Protocol",
	"RootGroup",
	"Status",
	"HasAvatar",
	"GroupPos",
	"Selected",
	"Hot",
	"Odd",
	"Indent",
	"Index",
	"Name",
	"Group",
	"True",
	"False",
	"ONLINE",
	"AWAY",
	"DND",
	"NA",
	"OCCUPIED",
	"FREECHAT",
	"INVISIBLE",
	"OUTTOLUNCH",
	"ONTHEPHONE",
	"IDLE",
	"OFFLINE",
	"Row",
	"CL",
	"SubContact",
	"MetaContact",
	"Contact",
	"Divider",
	"Info",
	"First-Single",
	"First",
	"Middle",
	"Mid",
	"Single",
	"Last",
	"Rate",
	"None",
	"Low",
	"Medium",
	"High",
	"State",
	"Active",
	"Inactive"
	//ADD item here
};
const int CLCPaint::HORIZONTAL_SPACE = 2;
const int CLCPaint::EXTRA_CHECKBOX_SPACE = 2;
const int CLCPaint::EXTRA_SPACE = 2;
const int CLCPaint::SELECTION_BORDER = 6;
const int CLCPaint::MIN_TEXT_WIDTH = 20;
const int CLCPaint::BUF2SIZE = 7;

const BYTE CLCPaint::GIM_SELECTED_AFFECT = 1;
const BYTE CLCPaint::GIM_HOT_AFFECT = 2;
const BYTE CLCPaint::GIM_TEMP_AFFECT = 4;
const BYTE CLCPaint::GIM_IDLE_AFFECT = 8;
const BYTE CLCPaint::GIM_EXTRAICON_AFFECT = CLCPaint::GIM_SELECTED_AFFECT | CLCPaint::GIM_HOT_AFFECT | CLCPaint::GIM_IDLE_AFFECT | CLCPaint::GIM_TEMP_AFFECT;
const BYTE CLCPaint::GIM_STATUSICON_AFFECT = CLCPaint::GIM_IDLE_AFFECT | CLCPaint::GIM_TEMP_AFFECT;
const BYTE CLCPaint::GIM_AVATAR_AFFECT = CLCPaint::GIM_IDLE_AFFECT | CLCPaint::GIM_TEMP_AFFECT;

CLCPaint::CLCPaint()
{
	_FillQuickHash();
};

void CLCPaint::cliPaintClc(HWND hwnd, ClcData *dat, HDC hdc, RECT *rcPaint)
{
	if (MirandaExiting()) return;
	g_CluiData.mutexPaintLock++;
	g_clcPainter._PaintClc(hwnd, dat, hdc, rcPaint);
	g_CluiData.mutexPaintLock--;
}

BOOL  CLCPaint::IsForegroundWindow(HWND hWnd)
{
	HWND hWindow;
	hWindow = hWnd;
	while (hWindow) {
		if (GetForegroundWindow() == hWindow) return TRUE;
		hWindow = GetParent(hWindow);
	}
	return FALSE;
}

HFONT CLCPaint::ChangeToFont(HDC hdc, ClcData *dat, int id, int *fontHeight)
{
	if (!dat)
		dat = (ClcData*)GetWindowLongPtr(pcli->hwndContactTree, 0);

	if (!dat)
		return NULL;

	HFONT res = (HFONT)SelectObject(hdc, dat->fontModernInfo[id].hFont);
	SetTextColor(hdc, dat->fontModernInfo[id].colour);

	if (fontHeight)
		*fontHeight = dat->fontModernInfo[id].fontHeight;
	ske_ResetTextEffect(hdc);

	if (dat->hWnd == pcli->hwndContactTree && dat->fontModernInfo[id].effect != 0)
		ske_SelectTextEffect(hdc, dat->fontModernInfo[id].effect - 1, dat->fontModernInfo[id].effectColour1, dat->fontModernInfo[id].effectColour2);
	else
		ske_ResetTextEffect(hdc);

	return res;
}

int CLCPaint::GetBasicFontID(ClcContact *contact)
{
	switch (contact->type) {
	case CLCIT_GROUP:
		return (contact->group->expanded) ? FONTID_OPENGROUPS : FONTID_CLOSEDGROUPS;

	case CLCIT_INFO:
		return (contact->flags & CLCIIF_GROUPFONT) ? FONTID_OPENGROUPS : FONTID_CONTACTS;

	case CLCIT_DIVIDER:
		return FONTID_DIVIDERS;

	case CLCIT_CONTACT:
		if (contact->flags & CONTACTF_NOTONLIST)
			return FONTID_NOTONLIST;
		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))) {
			// the contact is in the always visible list and the proto is invisible
			// the contact is in the always invisible and the proto is in any other mode
			return (contact->flags & CONTACTF_ONLINE) ? FONTID_INVIS : FONTID_OFFINVIS;
		}

		switch (contact->pce->getStatus()) {
		case ID_STATUS_OFFLINE: return FONTID_OFFLINE;
		case ID_STATUS_AWAY: return FONTID_AWAY;
		case ID_STATUS_DND: return FONTID_DND;
		case ID_STATUS_NA: return FONTID_NA;
		case ID_STATUS_OCCUPIED: return FONTID_OCCUPIED;
		case ID_STATUS_FREECHAT: return FONTID_CHAT;
		case ID_STATUS_INVISIBLE: return FONTID_INVISIBLE;
		case ID_STATUS_ONTHEPHONE: return FONTID_PHONE;
		case ID_STATUS_OUTTOLUNCH: return FONTID_LUNCH;
		}

	default:
		return FONTID_CONTACTS;
	}
}

void CLCPaint::GetTextSize(SIZE *text_size, HDC hdcMem, RECT free_row_rc, wchar_t *szText, SortedList *plText, UINT uTextFormat, int smiley_height)
{
	if (szText == NULL || !szText[0]) {
		text_size->cy = 0;
		text_size->cx = 0;
	}
	else {
		RECT text_rc = free_row_rc;
		int free_width;
		int free_height;

		free_width = text_rc.right - text_rc.left;
		free_height = text_rc.bottom - text_rc.top;

		// Always need cy...
		text_size->cy = ske_DrawText(hdcMem, szText, (int)mir_wstrlen(szText), &text_rc, DT_CALCRECT | uTextFormat);
		text_size->cy = min(text_size->cy, free_height);
		if (plText == NULL)
			text_size->cx = min(text_rc.right - text_rc.left + 2, free_width);
		else {
			// See each item of list
			int i;

			text_size->cy = min(max(text_size->cy, smiley_height), free_height);

			text_size->cx = 0;

			for (i = 0; i < plText->realCount && text_size->cx < free_width; i++) {
				ClcContactTextPiece *piece = (ClcContactTextPiece *)plText->items[i];

				if (piece->type == TEXT_PIECE_TYPE_TEXT) {
					text_rc = free_row_rc;

					ske_DrawText(hdcMem, &szText[piece->start_pos], piece->len, &text_rc, DT_CALCRECT | uTextFormat);
					text_size->cx = min(text_size->cx + text_rc.right - text_rc.left + 2, free_width);
				}
				else {
					double factor;

					if (piece->smiley_height > text_size->cy)
						factor = text_size->cy / (double)piece->smiley_height;
					else
						factor = 1;

					text_size->cx = min(text_size->cx + (long)(factor * piece->smiley_width), free_width);
				}
			}
		}
	}
}

void CLCPaint::AddParam(MODERNMASK *mpModernMask, DWORD dwParamHash, const char* const szValue, DWORD dwValueHash)
{
	static MASKPARAM param = { 0 }; //AddParameter will clear it so it can be static to avoid initializations
	_FillParam(&param, dwParamHash, szValue, dwValueHash);
	_AddParameter(mpModernMask, &param);
}

BOOL  CLCPaint::CheckMiniMode(ClcData *dat, BOOL selected)
{
	if (!dat->bCompactMode || ((dat->bCompactMode & 0x01) && selected))
		return FALSE;
	return TRUE;
}

tPaintCallbackProc CLCPaint::PaintCallbackProc(HWND hWnd, HDC hDC, RECT *rcPaint, HRGN, DWORD, void *)
{
	ClcData *dat = (ClcData*)GetWindowLongPtr(hWnd, 0);
	if (dat)
		cliPaintClc(hWnd, dat, hDC, rcPaint);
	return 0;
}

void CLCPaint::_FillQuickHash()
{
	for (int i = 0; i < hi_LastItem; i++)
		HASH[i] = mod_CalcHash(HASHTEXT[i]);
}

void CLCPaint::_SetHotTrackColour(HDC hdc, ClcData *dat)
{
	if (dat->gammaCorrection) {
		COLORREF oldCol, newCol;
		int oldLum, newLum;

		oldCol = GetTextColor(hdc);
		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) {
			SetTextColor(hdc, 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;
		SetTextColor(hdc, newCol);
	}
	else
		SetTextColor(hdc, dat->hotTextColour);
}

int   CLCPaint::_GetStatusOnlineness(int status)
{
	switch (status) {
	case ID_STATUS_FREECHAT:   return 110;
	case ID_STATUS_ONLINE:     return 100;
	case ID_STATUS_OCCUPIED:   return 60;
	case ID_STATUS_ONTHEPHONE: return 50;
	case ID_STATUS_DND:        return 40;
	case ID_STATUS_AWAY:       return 30;
	case ID_STATUS_OUTTOLUNCH: return 20;
	case ID_STATUS_NA:         return 10;
	case ID_STATUS_INVISIBLE:  return 5;
	}
	return 0;
}

int   CLCPaint::_GetGeneralisedStatus()
{
	int status = ID_STATUS_OFFLINE;
	int statusOnlineness = 0;

	for (int i = 0; i < pcli->hClcProtoCount; i++) {
		int thisStatus = pcli->clcProto[i].dwStatus;
		if (thisStatus == ID_STATUS_INVISIBLE)
			return ID_STATUS_INVISIBLE;

		int thisOnlineness = _GetStatusOnlineness(thisStatus);
		if (thisOnlineness > statusOnlineness) {
			status = thisStatus;
			statusOnlineness = thisOnlineness;
		}
	}
	return status;
}

int   CLCPaint::_GetRealStatus(ClcContact *pContact, int nStatus)
{
	if (!pContact->proto)
		return nStatus;

	for (int i = 0; i < pcli->hClcProtoCount; i++) {
		if (!mir_strcmp(pcli->clcProto[i].szProto, pContact->proto))
			return pcli->clcProto[i].dwStatus;
	}
	return nStatus;
}


RECT  CLCPaint::_GetRectangle(ClcData *dat, RECT *row_rc, RECT *free_row_rc, int *left_pos, int *right_pos, BOOL left, int real_width, int width, int height, int horizontal_space)
{
	RECT rc = *free_row_rc;
	int width_tmp = width;
	if (left) {
		if (dat->row_align_left_items_to_left)
			width_tmp = real_width;

		rc.left += (width_tmp - real_width) >> 1;
		rc.right = rc.left + real_width;
		rc.top += (rc.bottom - rc.top - height) >> 1;
		rc.bottom = rc.top + height;
		*left_pos += width_tmp + horizontal_space;
		free_row_rc->left = row_rc->left + *left_pos;
	}
	else {
		if (dat->row_align_right_items_to_right)
			width_tmp = real_width;

		if (width_tmp > rc.right - rc.left) {
			rc.left = rc.right + 1;
		}
		else {
			rc.left = max(rc.left + horizontal_space, rc.right - width_tmp) + ((width_tmp - real_width) >> 1);
			rc.right = min(rc.left + real_width, rc.right);
			rc.top += max(0, (rc.bottom - rc.top - height) >> 1);
			rc.bottom = min(rc.top + height, rc.bottom);

			*right_pos += min(width_tmp + horizontal_space, free_row_rc->right - free_row_rc->left);
			free_row_rc->right = row_rc->right - *right_pos;
		}
	}

	return rc;
}



void CLCPaint::_DrawTextSmiley(HDC hdcMem, RECT *free_rc, SIZE * text_size, wchar_t *szText, int start, int len, SortedList *plText, UINT uTextFormat, BOOL ResizeSizeSmiley)
{
	if (szText == NULL)
		return;

	uTextFormat &= ~DT_RIGHT;
	if (plText == NULL) {
		if (start) {
			SIZE size;
			GetTextExtentPoint32(hdcMem, szText, start, &size);
			free_rc->left += size.cx;
		}

		ske_DrawText(hdcMem, szText + start, len, free_rc, uTextFormat);
	}
	else {
		// Draw list
		int i;
		int pos_x = 0;
		int row_height;
		RECT tmp_rc = *free_rc;
		if (len == -1) len = (int)mir_wstrlen(szText);
		if (uTextFormat & DT_RTLREADING)
			i = plText->realCount - 1;
		else
			i = 0;

		// Get real height of the line
		row_height = ske_DrawText(hdcMem, L"A", 1, &tmp_rc, DT_CALCRECT | uTextFormat);

		// Just draw ellipsis
		if (free_rc->right <= free_rc->left) {
			if (gl_TrimText)
				ske_DrawText(hdcMem, L"...", 3, free_rc, uTextFormat & ~DT_END_ELLIPSIS);
		}
		else {
			// Draw text and smileys
			for (; i < plText->realCount && i >= 0 && pos_x < text_size->cx && len > 0; i += (uTextFormat & DT_RTLREADING ? -1 : 1)) {
				ClcContactTextPiece *piece = (ClcContactTextPiece *)plText->items[i];
				RECT text_rc = *free_rc;

				if (uTextFormat & DT_RTLREADING)
					text_rc.right -= pos_x;
				else
					text_rc.left += pos_x;

				if (piece->type == TEXT_PIECE_TYPE_TEXT) {
					tmp_rc = text_rc;
					tmp_rc.right += 50;
					ske_DrawText(hdcMem, &szText[piece->start_pos + start], min(len, piece->len), &tmp_rc, DT_CALCRECT | (uTextFormat & ~DT_END_ELLIPSIS));
					pos_x += tmp_rc.right - tmp_rc.left + 2;

					if (uTextFormat & DT_RTLREADING)
						text_rc.left = max(text_rc.left, text_rc.right - (tmp_rc.right - tmp_rc.left));

					ske_DrawText(hdcMem, &szText[piece->start_pos + start], min(len, piece->len), &text_rc, uTextFormat);
					len -= piece->len;
				}
				else {
					float factor = 0;

					if (len < piece->len) {
						len = 0;
					}
					else {
						LONG fac_width, fac_height;
						len -= piece->len;

						if (piece->smiley_height > row_height && ResizeSizeSmiley) {
							factor = row_height / (float)piece->smiley_height;
						}
						else {
							factor = 1;
						}

						fac_width = (LONG)(piece->smiley_width * factor);
						fac_height = (LONG)(piece->smiley_height * factor);

						if (uTextFormat & DT_RTLREADING)
							text_rc.left = max(text_rc.right - fac_width, text_rc.left);

						if (fac_width <= text_rc.right - text_rc.left) {
							text_rc.top += (row_height - fac_height) >> 1;

							ske_DrawIconEx(hdcMem, text_rc.left, text_rc.top, piece->smiley,
								fac_width, fac_height, 0, NULL, DI_NORMAL | ((factor < 1) ? 128 : 0)); //TO DO enchance drawing quality
						}
						else {
							ske_DrawText(hdcMem, L"...", 3, &text_rc, uTextFormat);
						}

						pos_x += fac_width;
					}
				}
			}
		}
	}
}


void CLCPaint::_AddParameter(MODERNMASK *mpModernMask, MASKPARAM * lpParam)
{
	mpModernMask->pl_Params = (MASKPARAM *)mir_realloc(mpModernMask->pl_Params, (mpModernMask->dwParamCnt + 1)*sizeof(MASKPARAM));
	memmove(&(mpModernMask->pl_Params[mpModernMask->dwParamCnt]), lpParam, sizeof(MASKPARAM));
	mpModernMask->dwParamCnt++;
	memset(lpParam, 0, sizeof(MASKPARAM));
}

void CLCPaint::_FillParam(MASKPARAM *lpParam, DWORD dwParamHash, const char* const szValue, DWORD dwValueHash)
{
	lpParam->bMaskParamFlag = MPF_EQUAL | MPF_HASHED;
	lpParam->dwId = dwParamHash;

	if (!dwValueHash && szValue && szValue[0])
		lpParam->dwValueHash = mod_CalcHash(szValue);
	else
		lpParam->dwValueHash = dwValueHash;

	if (szValue)
		lpParam->szValue = mir_strndup(szValue, (int)mir_strlen(szValue));
	else
		lpParam->szValue = NULL;
}

void CLCPaint::_AddParamShort(MODERNMASK *mpModernMask, DWORD dwParamIndex, DWORD dwValueIndex)
{
	AddParam(mpModernMask, HASH[dwParamIndex], HASHTEXT[dwValueIndex], HASH[dwValueIndex]);
}

MODERNMASK* CLCPaint::_GetCLCContactRowBackModernMask(ClcGroup *group, ClcContact *Drawing, int indent, int index, BOOL selected, BOOL hottrack, ClcData *dat)
{
	if (Drawing == NULL)
		return 0;

	char buf[BUF2SIZE] = { 0 };
	MODERNMASK *mpModernMask = (MODERNMASK*)mir_calloc(sizeof(MODERNMASK));

	_AddParamShort(mpModernMask, hi_Module, hi_CL);
	_AddParamShort(mpModernMask, hi_ID, hi_Row);
	switch (Drawing->type) {
	case CLCIT_GROUP:
		_AddParamShort(mpModernMask, hi_Type, hi_Group);
		if (Drawing->group) {
			_AddParamShort(mpModernMask, hi_Open, Drawing->group->expanded ? hi_True : hi_False);
			_AddParamShort(mpModernMask, hi_IsEmpty, (Drawing->group->cl.getCount() == 0) ? hi_True : hi_False);
		}
		break;

	case CLCIT_CONTACT:
		{
			ClcContact *mCont = Drawing;
			if (Drawing->iSubNumber) {
				_AddParamShort(mpModernMask, hi_Type, hi_SubContact);
				if (Drawing->iSubNumber == 1 && Drawing->subcontacts->iSubAllocated == 1)
					_AddParamShort(mpModernMask, hi_SubPos, hi_First_Single);
				else if (Drawing->iSubNumber == 1)
					_AddParamShort(mpModernMask, hi_SubPos, hi_First);
				else if (Drawing->iSubNumber == Drawing->subcontacts->iSubAllocated)
					_AddParamShort(mpModernMask, hi_SubPos, hi_Last);
				else
					_AddParamShort(mpModernMask, hi_SubPos, hi_Middle);
				mCont = Drawing->subcontacts;
			}
			else if (Drawing->iSubAllocated) {
				_AddParamShort(mpModernMask, hi_Type, hi_MetaContact);
				_AddParamShort(mpModernMask, hi_Open, (Drawing->bSubExpanded) ? hi_True : hi_False);
			}
			else _AddParamShort(mpModernMask, hi_Type, hi_Contact);

			AddParam(mpModernMask, HASH[hi_Protocol], Drawing->proto, 0);
			_AddParamShort(mpModernMask, hi_RootGroup, (group && group->parent == NULL) ? hi_True : hi_False);
			switch (GetContactCachedStatus(Drawing->hContact)) {
			case ID_STATUS_ONLINE:      _AddParamShort(mpModernMask, hi_Status, hi_ONLINE);    break;
			case ID_STATUS_AWAY:        _AddParamShort(mpModernMask, hi_Status, hi_AWAY);      break;
			case ID_STATUS_DND:         _AddParamShort(mpModernMask, hi_Status, hi_DND);       break;
			case ID_STATUS_NA:          _AddParamShort(mpModernMask, hi_Status, hi_NA);        break;
			case ID_STATUS_OCCUPIED:    _AddParamShort(mpModernMask, hi_Status, hi_OCCUPIED);  break;
			case ID_STATUS_FREECHAT:    _AddParamShort(mpModernMask, hi_Status, hi_FREECHAT);  break;
			case ID_STATUS_INVISIBLE:   _AddParamShort(mpModernMask, hi_Status, hi_INVISIBLE); break;
			case ID_STATUS_OUTTOLUNCH:  _AddParamShort(mpModernMask, hi_Status, hi_OUTTOLUNCH); break;
			case ID_STATUS_ONTHEPHONE:  _AddParamShort(mpModernMask, hi_Status, hi_ONTHEPHONE); break;
			case ID_STATUS_IDLE:        _AddParamShort(mpModernMask, hi_Status, hi_IDLE);      break;
			default:                    _AddParamShort(mpModernMask, hi_Status, hi_OFFLINE);
			}
			_AddParamShort(mpModernMask, hi_HasAvatar, (dat->avatars_show  && Drawing->avatar_data != NULL) ? hi_True : hi_False);
			_AddParamShort(mpModernMask, hi_Rate, hi_None + Drawing->bContactRate);
		}
		break;

	case CLCIT_DIVIDER:
		_AddParamShort(mpModernMask, hi_Type, hi_Divider);
		break;

	case CLCIT_INFO:
		_AddParamShort(mpModernMask, hi_Type, hi_Info);
		break;
	}

	if (group->scanIndex == 0 && group->cl.getCount() == 1)
		_AddParamShort(mpModernMask, hi_GroupPos, hi_First_Single);
	else if (group->scanIndex == 0)
		_AddParamShort(mpModernMask, hi_GroupPos, hi_First);
	else if (group->scanIndex + 1 == group->cl.getCount())
		_AddParamShort(mpModernMask, hi_GroupPos, hi_Last);
	else
		_AddParamShort(mpModernMask, hi_GroupPos, hi_Mid);

	_AddParamShort(mpModernMask, hi_Selected, (selected) ? hi_True : hi_False);
	_AddParamShort(mpModernMask, hi_Hot, (hottrack) ? hi_True : hi_False);
	_AddParamShort(mpModernMask, hi_Odd, (index & 1) ? hi_True : hi_False);

	_itoa(indent, buf, BUF2SIZE);
	AddParam(mpModernMask, HASH[hi_Indent], buf, 0);
	_itoa(index, buf, BUF2SIZE);
	AddParam(mpModernMask, HASH[hi_Index], buf, 0);
	{
		wchar_t *b2 = NEWWSTR_ALLOCA(Drawing->szText);
		for (int i = 0; b2[i] != 0; i++)
			if (b2[i] == ',')
				b2[i] = '.';

		AddParam(mpModernMask, HASH[hi_Name], T2Utf(b2), 0);
	}

	if (group->parent) {
		wchar_t *b2 = NEWWSTR_ALLOCA(group->parent->cl[0]->szText);
		for (int i = 0; b2[i] != 0; i++)
			if (b2[i] == ',')
				b2[i] = '.';

		AddParam(mpModernMask, HASH[hi_Group], T2Utf(b2), 0);
	}
	return mpModernMask;
}


void CLCPaint::_RTLRect(RECT *rect, int width)
{
	if (!rect) return;
	int left = (width)-rect->right;
	int right = (width)-rect->left;
	rect->left = left;//-offset;
	rect->right = right;//-offset;
}

void CLCPaint::_PaintRowItemsEx(HDC hdcMem, ClcData *dat, ClcContact *Drawing, RECT row_rc, RECT free_row_rc, int selected, int hottrack)
{
	int i = 0;
	int dx = free_row_rc.left;
	int dy = row_rc.top + dat->row_border;
	int dg = 0;

	// Let calc placeholder
	int minheight = dat->row_min_heigh;
	int mode2 = -1;
	BOOL InClistWindow = (dat->hWnd == pcli->hwndContactTree);
	int height = RowHeight_CalcRowHeight(dat, Drawing, -1);
	ClcCacheEntry *pdnce = Drawing->pce;

	// TO DO DEPRECATE OLD ROW LAYOUT

	if (Drawing->type == CLCIT_GROUP  &&
		Drawing->group->parent->groupId == 0 &&
		Drawing->group->parent->cl[0] != Drawing) {
		dg = dat->row_before_group_space;
		free_row_rc.top += dg;
		height -= dg;
	}
	if (!InClistWindow || !gl_RowRoot || Drawing->type == CLCIT_GROUP) {
		// to do paint simple
		RECT fr_rc = free_row_rc;

		// 1 draw icon
		if (!(Drawing->type == CLCIT_GROUP && InClistWindow && dat->row_hide_group_icon)) {
			int iImage = -1;
			// Get image
			if (Drawing->type == CLCIT_GROUP) {
				iImage = Drawing->group->expanded ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT;
			}
			else if (Drawing->type == CLCIT_CONTACT)
				iImage = Drawing->iImage;

			if (iImage != -1) {
				COLORREF colourFg;
				int mode;
				RECT p_rect = { 0 };
				p_rect.top = fr_rc.top + ((fr_rc.bottom - fr_rc.top - ICON_HEIGHT) >> 1);
				p_rect.left = fr_rc.left;
				p_rect.right = p_rect.left + ICON_HEIGHT;
				p_rect.bottom = p_rect.top + ICON_HEIGHT;
				// Store pos
				if (dat->text_rtl != 0) _RTLRect(&p_rect, free_row_rc.right);
				Drawing->pos_icon = p_rect;
				if (hottrack) {
					colourFg = dat->hotTextColour;
					mode = ILD_NORMAL;
				}
				else if (Drawing->type == CLCIT_CONTACT && Drawing->flags & CONTACTF_NOTONLIST) {
					colourFg = dat->fontModernInfo[FONTID_NOTONLIST].colour;
					mode = ILD_BLEND50;
				}
				else {
					colourFg = dat->selBkColour;
					mode = ILD_NORMAL;
				}

				if (Drawing->type == CLCIT_CONTACT && dat->bShowIdle && (Drawing->flags & CONTACTF_IDLE) &&
					_GetRealStatus(Drawing, ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
					mode = ILD_SELECTED;
				}
				_DrawStatusIcon(Drawing, dat, iImage, hdcMem, p_rect.left, p_rect.top, 0, 0, CLR_NONE, colourFg, mode);
			}
			fr_rc.left += ICON_HEIGHT + 2;
		}
		// 2 draw extra
		{
			RECT p_rect = { 0 };
			p_rect.top = fr_rc.top + ((fr_rc.bottom - fr_rc.top - ICON_HEIGHT) >> 1);
			p_rect.bottom = p_rect.top + ICON_HEIGHT;

			if ((Drawing->type == CLCIT_GROUP || Drawing->type == CLCIT_CONTACT || Drawing->type == CLCIT_INFO)
				&& dat->extraColumnsCount > 0 && (!InClistWindow || Drawing->type == CLCIT_CONTACT)) {
				int BlendedInActiveState = dat->dbbBlendInActiveState;
				int BlendValue = dat->dbbBlend25 ? ILD_BLEND25 : ILD_BLEND50;
				int iImage;
				int count = 0;
				RECT rc;
				int x = 0;
				for (iImage = dat->extraColumnsCount - 1; iImage >= 0; iImage--) {
					COLORREF colourFg = dat->selBkColour;
					int mode = BlendedInActiveState ? BlendValue : ILD_NORMAL;
					if (Drawing->iExtraImage[iImage] == EMPTY_EXTRA_ICON) {
						x += (x > 0) ? dat->extraColumnSpacing : ICON_HEIGHT;
						SetRect(&rc, fr_rc.right - x, p_rect.top, fr_rc.right - x + ICON_HEIGHT, p_rect.bottom);
						if (dat->text_rtl != 0) _RTLRect(&rc, free_row_rc.right);
						Drawing->pos_extra[iImage] = rc;
						count++;
						continue;
					}

					if (selected)
						mode = BlendedInActiveState ? ILD_NORMAL : ILD_SELECTED;
					else if (hottrack) {
						mode = BlendedInActiveState ? ILD_NORMAL : ILD_FOCUS;
						colourFg = dat->hotTextColour;
					}
					else if (Drawing->type == CLCIT_CONTACT && Drawing->flags&CONTACTF_NOTONLIST) {
						colourFg = dat->fontModernInfo[FONTID_NOTONLIST].colour;
						mode = BlendValue;
					}

					x += (x > 0) ? dat->extraColumnSpacing : ICON_HEIGHT;
					SetRect(&rc, fr_rc.right - x, p_rect.top, fr_rc.right - x + ICON_HEIGHT, p_rect.bottom);
					if (dat->text_rtl != 0) _RTLRect(&rc, free_row_rc.right);
					Drawing->pos_extra[iImage] = rc;
					Drawing->pos_extra[iImage] = rc;
					if (Drawing->iExtraImage[iImage] != EMPTY_EXTRA_ICON)
						ske_ImageList_DrawEx(dat->himlExtraColumns, Drawing->iExtraImage[iImage], hdcMem, rc.left, rc.top, 0, 0, CLR_NONE, colourFg, mode);
				}
				fr_rc.right -= x;
			}
		}
		// 3 draw text
		{
			SIZE text_size = { 0 };
			wchar_t *szCounts = NULL;
			RECT text_rect = fr_rc;
			RECT counts_rc = { 0 };
			UINT uTextFormat = DT_LEFT | DT_VCENTER | (gl_TrimText ? DT_END_ELLIPSIS : 0) | DT_SINGLELINE;
			uTextFormat |= dat->text_rtl ? DT_RTLREADING : 0;
			// Select font
			ChangeToFont(hdcMem, dat, GetBasicFontID(Drawing), NULL);

			// Get text size
			GetTextSize(&text_size, hdcMem, fr_rc, Drawing->szText, Drawing->ssText.plText, uTextFormat,
				dat->text_resize_smileys ? 0 : Drawing->ssText.iMaxSmileyHeight);
			// counters
			if (Drawing->type == CLCIT_GROUP && InClistWindow) {
				RECT nameRect = fr_rc;
				RECT countRect = { 0 };
				RECT count_rc = { 0 };
				SIZE count_size = { 0 };
				int space_width = 0;
				szCounts = pcli->pfnGetGroupCountsText(dat, Drawing);
				// Has to draw the count?
				if (szCounts && mir_wstrlen(szCounts) > 0) {
					// calc width and height
					ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
					ske_DrawText(hdcMem, L" ", 1, &count_rc, DT_CALCRECT | DT_NOPREFIX);
					count_size.cx = count_rc.right - count_rc.left;
					space_width = count_size.cx;
					count_rc.right = 0;
					count_rc.left = 0;
					ske_DrawText(hdcMem, szCounts, (int)mir_wstrlen(szCounts), &count_rc, DT_CALCRECT);
					count_size.cx += count_rc.right - count_rc.left;
					count_size.cy = count_rc.bottom - count_rc.top;
				}
				// modify text rect
				{
					SIZE grp_size = { 0 };
					int wid = fr_rc.right - fr_rc.left;
					ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPS : FONTID_CLOSEDGROUPS, NULL);
					GetTextSize(&grp_size, hdcMem, fr_rc, Drawing->szText, Drawing->ssText.plText, 0, dat->text_resize_smileys ? 0 : Drawing->ssText.iMaxSmileyHeight);

					if (wid - count_size.cx > grp_size.cx) {
						if (dat->row_align_group_mode != 2) { //center or left
							int x = (dat->row_align_group_mode == 1) ? (wid - (grp_size.cx + count_size.cx)) >> 1 : 0;
							nameRect.left += x;
							nameRect.right = nameRect.left + grp_size.cx;
							countRect.left = nameRect.right + space_width;
							countRect.right = countRect.left + count_size.cx - space_width;
						}
						else {
							countRect.right = nameRect.right;
							countRect.left = countRect.right - ((count_size.cx > 0) ? (count_size.cx - space_width) : 0);
							nameRect.right = countRect.left - ((count_size.cx > 0) ? space_width : 0);
							nameRect.left = nameRect.right - grp_size.cx;
						}
					}
					else {
						countRect.right = nameRect.right;
						nameRect.right -= count_size.cx;
						countRect.left = nameRect.right + space_width;
					}
					countRect.bottom = nameRect.bottom;
					countRect.top = nameRect.top;
				}

				uTextFormat |= DT_VCENTER;
				ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPS : FONTID_CLOSEDGROUPS, NULL);
				if (selected)
					SetTextColor(hdcMem, dat->selTextColour);
				else if (hottrack)
					_SetHotTrackColour(hdcMem, dat);
				if (dat->text_rtl != 0) _RTLRect(&nameRect, free_row_rc.right);
				_DrawTextSmiley(hdcMem, &nameRect, &text_size, Drawing->szText, 0, (int)mir_wstrlen(Drawing->szText), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);

				if (selected && !dat->bFilterSearch) {
					SetTextColor(hdcMem, dat->quickSearchColour);
					_DrawTextSmiley(hdcMem, &nameRect, &text_size, Drawing->szText, 0, (int)mir_wstrlen(Drawing->szText), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
				}

				if (szCounts && mir_wstrlen(szCounts) > 0) {
					ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
					if (selected)
						SetTextColor(hdcMem, dat->selTextColour);
					else if (hottrack)
						_SetHotTrackColour(hdcMem, dat);
					if (dat->text_rtl != 0) _RTLRect(&countRect, free_row_rc.right);
					ske_DrawText(hdcMem, szCounts, (int)mir_wstrlen(szCounts), &countRect, uTextFormat);
				}
				Drawing->pos_label = nameRect;
				return;
			}
			else if (Drawing->type == CLCIT_GROUP) {
				szCounts = pcli->pfnGetGroupCountsText(dat, Drawing);
				// Has to draw the count?
				if (szCounts && szCounts[0]) {
					RECT space_rc = fr_rc;

					int text_width = 0;
					SIZE space_size = { 0 };
					SIZE counts_size = { 0 };
					// Get widths
					counts_rc = fr_rc;
					DrawText(hdcMem, L" ", 1, &space_rc, DT_CALCRECT | DT_NOPREFIX);

					space_size.cx = space_rc.right - space_rc.left;
					space_size.cy = min(space_rc.bottom - space_rc.top, fr_rc.bottom - fr_rc.top);

					ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
					DrawText(hdcMem, szCounts, (int)mir_wstrlen(szCounts), &counts_rc, DT_CALCRECT);

					counts_size.cx = counts_rc.right - counts_rc.left;
					counts_size.cy = min(counts_rc.bottom - counts_rc.top, fr_rc.bottom - fr_rc.top);

					text_width = fr_rc.right - fr_rc.left - space_size.cx - counts_size.cx;

					if (text_width > 4) {
						text_size.cx = min(text_width, text_size.cx);
						text_width = text_size.cx + space_size.cx + counts_size.cx;
					}
					else {
						text_width = text_size.cx;
						space_size.cx = 0;
						counts_size.cx = 0;
					}
					text_rect.right = text_rect.left + text_size.cx;
					counts_rc = text_rect;
					counts_rc.left = text_rect.right + space_size.cx;
					counts_rc.right = counts_rc.left + counts_size.cx;
				}
			}
			ChangeToFont(hdcMem, dat, GetBasicFontID(Drawing), NULL);

			// Set color
			if (selected)
				SetTextColor(hdcMem, dat->selTextColour);
			else if (hottrack)
				_SetHotTrackColour(hdcMem, dat);
			if (dat->text_rtl != 0) _RTLRect(&text_rect, free_row_rc.right);
			_DrawTextSmiley(hdcMem, &text_rect, &text_size, Drawing->szText, 0, (int)mir_wstrlen(Drawing->szText), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
			if (((dat->bFilterSearch && Drawing->type != CLCIT_GROUP) || selected) && dat->szQuickSearch[0] != '\0') {
				int idx = 0;
				if (dat->bFilterSearch) {
					wchar_t *lowered = CharLowerW(NEWWSTR_ALLOCA(Drawing->szText));
					wchar_t *lowered_search = CharLowerW(NEWWSTR_ALLOCA(dat->szQuickSearch));
					wchar_t *p1 = wcsstr(lowered, lowered_search);
					if (p1)
						idx = int(p1 - lowered);
				}
				SetTextColor(hdcMem, dat->quickSearchColour);
				_DrawTextSmiley(hdcMem, &text_rect, &text_size, Drawing->szText, idx, (int)mir_wstrlen(dat->szQuickSearch), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
			}
			if (Drawing->type == CLCIT_GROUP && szCounts && szCounts[0] && counts_rc.right - counts_rc.left > 0) {
				ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
				if (dat->text_rtl != 0) _RTLRect(&counts_rc, free_row_rc.right);
				ske_DrawText(hdcMem, szCounts, (int)mir_wstrlen(szCounts), &counts_rc, uTextFormat);
				if (dat->text_rtl == 0)
					text_rect.right = counts_rc.right;
				else
					text_rect.left = counts_rc.left;
			}
			Drawing->pos_label = text_rect;

			RECT rcPos = fr_rc;
			if (dat->text_rtl != 0)
				_RTLRect(&rcPos, free_row_rc.right);

			if ((!InClistWindow || !g_CluiData.fLayered) && ((Drawing->type == CLCIT_DIVIDER) || (Drawing->type == CLCIT_GROUP && dat->exStyle & CLS_EX_LINEWITHGROUPS))) {
				RECT rc = fr_rc;
				if (dat->text_rtl != 0) {
					rc.left = rcPos.left;
					rc.right = text_rect.left - 3;
				}
				else rc.left = text_rect.right + 3;

				if (rc.right - rc.left > 4) {
					rc.top += ((rc.bottom - rc.top) >> 1) - 1;
					rc.bottom = rc.top + 2;
					DrawEdge(hdcMem, &rc, BDR_SUNKENOUTER, BF_RECT);
					ske_SetRectOpaque(hdcMem, &rc);
				}
			}
		}
		return;
	}

	minheight = max(minheight, height);
	dy += (minheight > height) ? ((minheight - height) >> 1) : 0;
	// Call Placement
	cppCalculateRowItemsPos(gl_RowRoot, free_row_rc.right - free_row_rc.left);
	// Now paint
	while ((gl_RowTabAccess[i] != NULL || (i < 2 && Drawing->type == CLCIT_GROUP)) && !(i >= 2 && Drawing->type == CLCIT_GROUP)) {
		if (gl_RowTabAccess[i]->r.right - gl_RowTabAccess[i]->r.left > 0 && gl_RowTabAccess[i]->r.bottom - gl_RowTabAccess[i]->r.top > 0) {
			RECT p_rect = gl_RowTabAccess[i]->r;
			OffsetRect(&p_rect, dx, dy);
			if (dat->text_rtl != 0 && gl_RowTabAccess[i]->type != TC_EXTRA /*each extra icon modified separately*/)
				_RTLRect(&p_rect, free_row_rc.right);

			SIZE text_size;
			switch (gl_RowTabAccess[i]->type) {
			case TC_TEXT1:
				{
					// paint text 1
					UINT uTextFormat = (dat->text_rtl ? DT_RTLREADING : 0);
					text_size.cx = p_rect.right - p_rect.left;
					text_size.cy = p_rect.bottom - p_rect.top;
					ChangeToFont(hdcMem, dat, GetBasicFontID(Drawing), NULL);

					uTextFormat |= (gl_RowTabAccess[i]->valign == TC_VCENTER) ? DT_VCENTER : (gl_RowTabAccess[i]->valign == TC_BOTTOM) ? DT_BOTTOM : 0;
					uTextFormat |= (gl_RowTabAccess[i]->halign == TC_HCENTER) ? DT_CENTER : (gl_RowTabAccess[i]->halign == TC_RIGHT) ? DT_RIGHT : 0;

					uTextFormat = uTextFormat | (gl_TrimText ? DT_END_ELLIPSIS : 0) | DT_SINGLELINE;
					if (Drawing->type == CLCIT_CONTACT) {
						if (selected)
							SetTextColor(hdcMem, dat->selTextColour);
						else if (hottrack)
							_SetHotTrackColour(hdcMem, dat);
						_DrawTextSmiley(hdcMem, &p_rect, &text_size, Drawing->szText, 0, (int)mir_wstrlen(Drawing->szText), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
						if ((dat->bFilterSearch || selected) && dat->szQuickSearch[0] != '\0') {
							int idx = 0;
							if (dat->bFilterSearch) {
								wchar_t *lowered = CharLowerW(NEWWSTR_ALLOCA(Drawing->szText));
								wchar_t *lowered_search = CharLowerW(NEWWSTR_ALLOCA(dat->szQuickSearch));
								wchar_t *p1 = wcsstr(lowered, lowered_search);
								if (p1)
									idx = int(p1 - lowered);
							}
							SetTextColor(hdcMem, dat->quickSearchColour);
							_DrawTextSmiley(hdcMem, &p_rect, &text_size, Drawing->szText, idx, (int)mir_wstrlen(dat->szQuickSearch), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
						}

						SIZE size;
						GetTextSize(&size, hdcMem, p_rect, Drawing->szText, Drawing->ssText.plText, 0, dat->text_resize_smileys ? 0 : Drawing->ssText.iMaxSmileyHeight);
						Drawing->pos_label = p_rect;
						Drawing->pos_label.right = min(Drawing->pos_label.right, Drawing->pos_label.left + size.cx);
					}
					else if (Drawing->type == CLCIT_GROUP) {
						RECT nameRect = p_rect;
						RECT countRect = { 0 };
						RECT count_rc = { 0 };
						SIZE count_size = { 0 };
						int space_width = 0;
						wchar_t *szCounts = pcli->pfnGetGroupCountsText(dat, Drawing);
						// Has to draw the count?
						if (szCounts && mir_wstrlen(szCounts) > 0) {
							// calc width and height
							ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
							ske_DrawText(hdcMem, L" ", 1, &count_rc, DT_CALCRECT | DT_NOPREFIX);
							count_size.cx = count_rc.right - count_rc.left;
							space_width = count_size.cx;
							count_rc.right = 0;
							count_rc.left = 0;
							ske_DrawText(hdcMem, szCounts, (int)mir_wstrlen(szCounts), &count_rc, DT_CALCRECT);
							count_size.cx += count_rc.right - count_rc.left;
							count_size.cy = count_rc.bottom - count_rc.top;
						}
						// modify text rect
						{
							SIZE grp_size = { 0 };
							int wid = p_rect.right - p_rect.left;
							ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPS : FONTID_CLOSEDGROUPS, NULL);
							GetTextSize(&grp_size, hdcMem, p_rect, Drawing->szText, Drawing->ssText.plText, 0, dat->text_resize_smileys ? 0 : Drawing->ssText.iMaxSmileyHeight);

							if (wid - count_size.cx > grp_size.cx) {
								if (dat->row_align_group_mode != 2) { //center or left
									int x = (dat->row_align_group_mode == 1) ? (wid - (grp_size.cx + count_size.cx)) >> 1 : 0;
									nameRect.left += x;
									nameRect.right = nameRect.left + grp_size.cx;
									countRect.left = nameRect.right + space_width;
									countRect.right = countRect.left + count_size.cx - space_width;
								}
								else {
									countRect.right = nameRect.right;
									countRect.left = countRect.right - ((count_size.cx > 0) ? (count_size.cx - space_width) : 0);
									nameRect.right = countRect.left - ((count_size.cx > 0) ? space_width : 0);
									nameRect.left = nameRect.right - grp_size.cx;
								}
							}
							else {
								countRect.right = nameRect.right;
								nameRect.right -= count_size.cx;
								countRect.left = nameRect.right + space_width;
							}
							countRect.bottom = nameRect.bottom;
							countRect.top = nameRect.top;
						}

						uTextFormat |= DT_VCENTER;
						ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPS : FONTID_CLOSEDGROUPS, NULL);
						if (selected)
							SetTextColor(hdcMem, dat->selTextColour);
						else if (hottrack)
							_SetHotTrackColour(hdcMem, dat);
						_DrawTextSmiley(hdcMem, &nameRect, &text_size, Drawing->szText, 0, (int)mir_wstrlen(Drawing->szText), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
						if (selected && !dat->bFilterSearch) {
							SetTextColor(hdcMem, dat->quickSearchColour);
							_DrawTextSmiley(hdcMem, &nameRect, &text_size, Drawing->szText, 0, (int)mir_wstrlen(Drawing->szText), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
						}
						if (szCounts && mir_wstrlen(szCounts) > 0) {
							ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
							if (selected)
								SetTextColor(hdcMem, dat->selTextColour);
							else if (hottrack)
								_SetHotTrackColour(hdcMem, dat);
							ske_DrawText(hdcMem, szCounts, (int)mir_wstrlen(szCounts), &countRect, uTextFormat);
						}
						Drawing->pos_label = nameRect;
					}
				}
				break;

			case TC_TEXT2:
				{
					// paint text 2
					//
					// Select font
					UINT uTextFormat = (dat->text_rtl ? DT_RTLREADING : 0);

					if (dat->secondLine.show && dat->secondLine.type == TEXT_CONTACT_TIME && pdnce->hTimeZone) {
						// Get contact time
						wchar_t buf[70] = L"";
						mir_free_and_nil(pdnce->szSecondLineText);

						TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", buf, _countof(buf), 0);
						pdnce->szSecondLineText = mir_wstrdup(buf);
					}

					uTextFormat |= (gl_RowTabAccess[i]->valign == TC_VCENTER) ? DT_VCENTER : (gl_RowTabAccess[i]->valign == TC_BOTTOM) ? DT_BOTTOM : 0;
					uTextFormat |= (gl_RowTabAccess[i]->halign == TC_HCENTER) ? DT_CENTER : (gl_RowTabAccess[i]->halign == TC_RIGHT) ? DT_RIGHT : 0;

					text_size.cx = p_rect.right - p_rect.left;
					text_size.cy = p_rect.bottom - p_rect.top;

					ChangeToFont(hdcMem, dat, FONTID_SECONDLINE, NULL);
					uTextFormat = uTextFormat | (gl_TrimText ? DT_END_ELLIPSIS : 0) | DT_SINGLELINE;
					if (Drawing->type == CLCIT_CONTACT)
						_DrawTextSmiley(hdcMem, &p_rect, &text_size, pdnce->szSecondLineText, 0, (int)mir_wstrlen(pdnce->szSecondLineText), pdnce->ssSecondLine.plText, uTextFormat, dat->text_resize_smileys);
				}
				break;

			case TC_TEXT3:
				{
					//paint text 3
					// Select font
					UINT uTextFormat = (dat->text_rtl ? DT_RTLREADING : 0);

					if (dat->thirdLine.show && dat->thirdLine.type == TEXT_CONTACT_TIME && pdnce->hTimeZone) {
						// Get contact time
						wchar_t buf[70] = L"";
						mir_free(pdnce->szThirdLineText);

						TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", buf, _countof(buf), 0);
						pdnce->szThirdLineText = mir_wstrdup(buf);
					}

					uTextFormat |= (gl_RowTabAccess[i]->valign == TC_VCENTER) ? DT_VCENTER : (gl_RowTabAccess[i]->valign == TC_BOTTOM) ? DT_BOTTOM : 0;
					uTextFormat |= (gl_RowTabAccess[i]->halign == TC_HCENTER) ? DT_CENTER : (gl_RowTabAccess[i]->halign == TC_RIGHT) ? DT_RIGHT : 0;

					text_size.cx = p_rect.right - p_rect.left;
					text_size.cy = p_rect.bottom - p_rect.top;

					ChangeToFont(hdcMem, dat, FONTID_THIRDLINE, NULL);
					uTextFormat = uTextFormat | (gl_TrimText ? DT_END_ELLIPSIS : 0) | DT_SINGLELINE;
					if (Drawing->type == CLCIT_CONTACT)
						_DrawTextSmiley(hdcMem, &p_rect, &text_size, pdnce->szThirdLineText, 0, (int)mir_wstrlen(pdnce->szThirdLineText), pdnce->ssThirdLine.plText, uTextFormat, dat->text_resize_smileys);
				}
				break;

			case TC_STATUS:
				if ((Drawing->type == CLCIT_GROUP && !dat->row_hide_group_icon) || (Drawing->type == CLCIT_CONTACT && Drawing->iImage != -1
					&& !(dat->icon_hide_on_avatar && dat->avatars_show && Drawing->avatar_data != NULL && !Drawing->bImageIsSpecial))) {
					int iImage = -1;
					// Get image
					if (Drawing->type == CLCIT_GROUP) {
						if (!dat->row_hide_group_icon) iImage = Drawing->group->expanded ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT;
						else iImage = -1;
					}
					else if (Drawing->type == CLCIT_CONTACT)
						iImage = Drawing->iImage;

					if (iImage != -1) {
						COLORREF colourFg;
						int mode;
						// Store pos
						Drawing->pos_icon = p_rect;
						if (hottrack) {
							colourFg = dat->hotTextColour;
							mode = ILD_NORMAL;
						}
						else if (Drawing->type == CLCIT_CONTACT && Drawing->flags & CONTACTF_NOTONLIST) {
							colourFg = dat->fontModernInfo[FONTID_NOTONLIST].colour;
							mode = ILD_BLEND50;
						}
						else {
							colourFg = dat->selBkColour;
							mode = ILD_NORMAL;
						}

						if (Drawing->type == CLCIT_CONTACT && dat->bShowIdle && (Drawing->flags & CONTACTF_IDLE) &&
							_GetRealStatus(Drawing, ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
							mode = ILD_SELECTED;
						}

						_DrawStatusIcon(Drawing, dat, iImage, hdcMem, p_rect.left, p_rect.top, 0, 0, CLR_NONE, colourFg, mode);
					}
				}
				break;

			case TC_AVATAR:
				{
					BOOL hasAvatar = Drawing->avatar_data != NULL;
					BYTE blendmode = 255;
					if (hottrack)
						blendmode = 255;
					else if (Drawing->type == CLCIT_CONTACT && Drawing->flags & CONTACTF_NOTONLIST)
						blendmode = 128;
					if (Drawing->type == CLCIT_CONTACT && dat->bShowIdle && (Drawing->flags & CONTACTF_IDLE) &&
						_GetRealStatus(Drawing, ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE)
						blendmode = 128;
					if (!hasAvatar) { // if no avatar then paint icon image
						int iImage = Drawing->iImage;
						if (iImage != -1) {
							COLORREF colourFg;
							int mode;
							// Store pos
							Drawing->pos_icon = p_rect;
							if (hottrack) {
								colourFg = dat->hotTextColour;
								mode = ILD_NORMAL;
							}
							else if (Drawing->type == CLCIT_CONTACT && Drawing->flags & CONTACTF_NOTONLIST) {
								colourFg = dat->fontModernInfo[FONTID_NOTONLIST].colour;
								mode = ILD_BLEND50;
							}
							else {
								colourFg = dat->selBkColour;
								mode = ILD_NORMAL;
							}

							if (Drawing->type == CLCIT_CONTACT && dat->bShowIdle && (Drawing->flags & CONTACTF_IDLE) &&
								_GetRealStatus(Drawing, ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
								mode = ILD_SELECTED;
							}

							_DrawStatusIcon(Drawing, dat, iImage, hdcMem, p_rect.left, p_rect.top, 0, 0, CLR_NONE, colourFg, mode);

						}
					}
					else {
						HRGN rgn = NULL;
						int round_radius = 0;
						int ava_width = p_rect.right - p_rect.left;
						int ava_height = p_rect.bottom - p_rect.top;
						// Store pos
						Drawing->pos_avatar = p_rect;
						HRGN oldrgn = CreateRectRgn(0, 0, 0, 0);
						GetClipRgn(hdcMem, oldrgn);

						// Round corners
						if (dat->avatars_round_corners) {
							if (dat->avatars_use_custom_corner_size)
								round_radius = dat->avatars_custom_corner_size;
							else
								round_radius = min(ava_width, ava_height) / 5;
						}
						else round_radius = 0;

						if (dat->avatars_draw_border) {
							HBRUSH hBrush = CreateSolidBrush(dat->avatars_border_color);
							HBRUSH hOldBrush = (HBRUSH)SelectObject(hdcMem, hBrush);
							HRGN rgn2;
							rgn = CreateRoundRectRgn(p_rect.left, p_rect.top, p_rect.right + 1, p_rect.bottom + 1, round_radius << 1, round_radius << 1);
							rgn2 = CreateRoundRectRgn(p_rect.left + 1, p_rect.top + 1, p_rect.right, p_rect.bottom, round_radius << 1, round_radius << 1);
							CombineRgn(rgn2, rgn, rgn2, RGN_DIFF);
							// FrameRgn(hdcMem, rgn, hBrush, 1, 1 );
							FillRgn(hdcMem, rgn2, hBrush);
							ske_SetRgnOpaque(hdcMem, rgn2);
							SelectObject(hdcMem, hOldBrush);
							DeleteObject(hBrush);
							DeleteObject(rgn);
							DeleteObject(rgn2);
						}
						if (dat->avatars_round_corners || dat->avatars_draw_border) {
							int k = dat->avatars_draw_border ? 1 : 0;
							rgn = CreateRoundRectRgn(p_rect.left + k, p_rect.top + k, p_rect.right + 1 - k, p_rect.bottom + 1 - k, round_radius * 2, round_radius * 2);
							ExtSelectClipRgn(hdcMem, rgn, RGN_AND);
						}

						// Draw avatar
						_DrawContactAvatar(hdcMem, dat, Drawing, &row_rc, selected, hottrack, &p_rect);

						// Restore region
						if (dat->avatars_round_corners || dat->avatars_draw_border)
							DeleteObject(rgn);

						SelectClipRgn(hdcMem, oldrgn);
						DeleteObject(oldrgn);

						// Draw borders

						//TODO fix overlays
						// Draw overlay
						if (dat->avatars_draw_overlay && dat->avatars_maxheight_size >= ICON_HEIGHT + (dat->avatars_draw_border ? 2 : 0)
							&& GetContactCachedStatus(Drawing->hContact) - ID_STATUS_OFFLINE < _countof(g_pAvatarOverlayIcons)) {
							p_rect.top = p_rect.bottom - ICON_HEIGHT;
							p_rect.left = p_rect.right - ICON_HEIGHT;

							if (dat->avatars_draw_border) {
								p_rect.top--;
								p_rect.left--;
							}

							switch (dat->avatars_overlay_type) {
							case SETTING_AVATAR_OVERLAY_TYPE_NORMAL:
								{
									UINT a = blendmode;
									a = (a << 24);
									ske_ImageList_DrawEx(hAvatarOverlays, g_pAvatarOverlayIcons[GetContactCachedStatus(Drawing->hContact) - ID_STATUS_OFFLINE].listID,
										hdcMem,
										p_rect.left, p_rect.top, ICON_HEIGHT, ICON_HEIGHT,
										CLR_NONE, CLR_NONE,
										(blendmode == 255) ? ILD_NORMAL : (blendmode == 128) ? ILD_BLEND50 : ILD_BLEND25);
								}
								break;
							case SETTING_AVATAR_OVERLAY_TYPE_PROTOCOL:
								{
									int item = pcli->pfnIconFromStatusMode(Drawing->proto, Drawing->proto == NULL ? ID_STATUS_OFFLINE : GetContactCachedStatus(Drawing->hContact), Drawing->hContact);
									if (item != -1)
										_DrawStatusIcon(Drawing, dat, item, hdcMem,
										p_rect.left, p_rect.top, ICON_HEIGHT, ICON_HEIGHT,
										CLR_NONE, CLR_NONE, (blendmode == 255) ? ILD_NORMAL : (blendmode == 128) ? ILD_BLEND50 : ILD_BLEND25);
								}
								break;
							case SETTING_AVATAR_OVERLAY_TYPE_CONTACT:
								if (Drawing->iImage != -1)
									_DrawStatusIcon(Drawing, dat, Drawing->iImage, hdcMem,
									p_rect.left, p_rect.top, ICON_HEIGHT, ICON_HEIGHT,
									CLR_NONE, CLR_NONE, (blendmode == 255) ? ILD_NORMAL : (blendmode == 128) ? ILD_BLEND50 : ILD_BLEND25);
								break;
							}
						}
					}
				}
				break;

			case TC_EXTRA:
				if (Drawing->type == CLCIT_CONTACT &&
					(!Drawing->iSubNumber || dat->dbbMetaHideExtra == 0 && dat->extraColumnsCount > 0)) {
					int BlendedInActiveState = dat->dbbBlendInActiveState;
					int BlendValue = dat->dbbBlend25 ? ILD_BLEND25 : ILD_BLEND50;
					int count = 0;
					RECT rc;
					int x = 0;
					for (int iImage = 0; iImage < dat->extraColumnsCount; iImage++) {
						COLORREF colourFg = dat->selBkColour;
						int mode = BlendedInActiveState ? BlendValue : ILD_NORMAL;
						if (Drawing->iExtraImage[iImage] == EMPTY_EXTRA_ICON) {
							if (!dat->bMetaIgnoreEmptyExtra) {
								SetRect(&rc, p_rect.left + x, p_rect.top, p_rect.left + x + ICON_HEIGHT, p_rect.bottom);
								x += dat->extraColumnSpacing;
								if (dat->text_rtl != 0) _RTLRect(&rc, free_row_rc.right);
								Drawing->pos_extra[iImage] = rc;
								count++;
							}
							continue;
						}

						if (selected)
							mode = BlendedInActiveState ? ILD_NORMAL : ILD_SELECTED;
						else if (hottrack) {
							mode = BlendedInActiveState ? ILD_NORMAL : ILD_FOCUS;
							colourFg = dat->hotTextColour;
						}
						else if (Drawing->type == CLCIT_CONTACT && (Drawing->flags & CONTACTF_NOTONLIST)) {
							colourFg = dat->fontModernInfo[FONTID_NOTONLIST].colour;
							mode = BlendValue;
						}

						SetRect(&rc, p_rect.left + x, p_rect.top, p_rect.left + x + ICON_HEIGHT, p_rect.bottom);
						x += dat->extraColumnSpacing;
						count++;
						if (dat->text_rtl != 0) _RTLRect(&rc, free_row_rc.right);
						Drawing->pos_extra[iImage] = rc;
						if (Drawing->iExtraImage[iImage] != EMPTY_EXTRA_ICON)
							ske_ImageList_DrawEx(dat->himlExtraColumns, Drawing->iExtraImage[iImage], hdcMem,
							rc.left, rc.top, 0, 0, CLR_NONE, colourFg, mode);
					}
				}
				break;

			case TC_EXTRA1:
			case TC_EXTRA2:
			case TC_EXTRA3:
			case TC_EXTRA4:
			case TC_EXTRA5:
			case TC_EXTRA6:
			case TC_EXTRA7:
			case TC_EXTRA8:
			case TC_EXTRA9:
				if (Drawing->type == CLCIT_CONTACT && (!Drawing->iSubNumber || dat->dbbMetaHideExtra == 0 && dat->extraColumnsCount > 0)) {
					int eNum = gl_RowTabAccess[i]->type - TC_EXTRA1;
					if (eNum < dat->extraColumnsCount) {
						if (Drawing->iExtraImage[eNum] != EMPTY_EXTRA_ICON) {
							COLORREF colourFg = RGB(0, 0, 0);
							int mode = 0;
							int BlendedInActiveState = dat->dbbBlendInActiveState;
							int BlendValue = dat->dbbBlend25 ? ILD_BLEND25 : ILD_BLEND50;
							if (mode2 != -1) mode = mode2;
							else {
								if (selected) mode = BlendedInActiveState ? ILD_NORMAL : ILD_SELECTED;
								else if (hottrack) {
									mode = BlendedInActiveState ? ILD_NORMAL : ILD_FOCUS;
									colourFg = dat->hotTextColour;
								}
								else if (Drawing->type == CLCIT_CONTACT && Drawing->flags&CONTACTF_NOTONLIST) {
									colourFg = dat->fontModernInfo[FONTID_NOTONLIST].colour;
									mode = BlendValue;
								}
								mode2 = mode;
							}
							if (dat->text_rtl != 0) _RTLRect(&p_rect, free_row_rc.right);
							Drawing->pos_extra[eNum] = p_rect;
							if (Drawing->iExtraImage[eNum] != EMPTY_EXTRA_ICON)
								ske_ImageList_DrawEx(dat->himlExtraColumns, Drawing->iExtraImage[eNum], hdcMem,
								p_rect.left, p_rect.top, 0, 0, CLR_NONE, colourFg, mode);
						}
					}
				}
				break;

			case TC_TIME:
				wchar_t szResult[80];
				if (!TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", szResult, _countof(szResult), 0)) {
					// Select font
					ChangeToFont(hdcMem, dat, FONTID_CONTACT_TIME, NULL);
					ske_DrawText(hdcMem, szResult, (int)mir_wstrlen(szResult), &p_rect, DT_NOPREFIX | DT_SINGLELINE | (dat->text_rtl ? DT_RTLREADING : 0));
				}
				break;
			}
		}
		i++;
	}
	return;
}

void CLCPaint::_DrawStatusIcon(ClcContact *Drawing, ClcData *dat, int iImage, HDC hdcMem, int x, int y, int cx, int cy, DWORD colorbg, DWORD colorfg, int mode)
{
	if (Drawing->type != CLCIT_CONTACT)
		ske_ImageList_DrawEx(g_himlCListClc, LOWORD(iImage), hdcMem, x, y, cx, cy, colorbg, colorfg, mode);

	else if (Drawing->bImageIsSpecial)
		ske_ImageList_DrawEx(g_himlCListClc, LOWORD(iImage), hdcMem, x, y, cx, cy, colorbg, colorfg, mode);

	else if (iImage != -1 && HIWORD(iImage) && dat->drawOverlayedStatus) {
		int status = GetContactCachedStatus(Drawing->hContact);
		if (status < ID_STATUS_OFFLINE) status = ID_STATUS_OFFLINE;
		else if (status > ID_STATUS_OUTTOLUNCH) status = ID_STATUS_ONLINE;
		ske_ImageList_DrawEx(g_himlCListClc, HIWORD(iImage), hdcMem, x, y, cx, cy, colorbg, colorfg, mode);
		if (dat->drawOverlayedStatus & 2) //draw overlay
			ske_ImageList_DrawEx(hAvatarOverlays, g_pStatusOverlayIcons[status - ID_STATUS_OFFLINE].listID, hdcMem,
			x, y, cx, cy, colorbg, colorfg, mode);
	}
	else ske_ImageList_DrawEx(g_himlCListClc, LOWORD(iImage), hdcMem, x, y, cx, cy, colorbg, colorfg, mode);
}

BOOL CLCPaint::_DrawNonEnginedBackground(HDC hdcMem, RECT *rcPaint, RECT clRect, ClcData *dat)
{
	if (!dat->hBmpBackground)
		return FALSE;

	// XXX: Halftone isnt supported on 9x, however the scretch problems dont happen on 98.
	SetStretchBltMode(hdcMem, HALFTONE);

	BITMAP bmp;
	GetObject(dat->hBmpBackground, sizeof(bmp), &bmp);
	HDC hdcBmp = CreateCompatibleDC(hdcMem);
	HBITMAP oldbm = (HBITMAP)SelectObject(hdcBmp, dat->hBmpBackground);
	int x, y = dat->backgroundBmpUse&CLBF_SCROLL ? -dat->yScroll : 0;
	int maxx = dat->backgroundBmpUse&CLBF_TILEH ? clRect.right : 1;
	int maxy = dat->backgroundBmpUse&CLBF_TILEV ? rcPaint->bottom : y + 1;
	int destw, desth;

	switch (dat->backgroundBmpUse&CLBM_TYPE) {
	case CLB_STRETCH:
		if (dat->backgroundBmpUse&CLBF_PROPORTIONAL) {
			if (clRect.right*bmp.bmHeight < clRect.bottom*bmp.bmWidth) {
				desth = clRect.bottom;
				destw = desth*bmp.bmWidth / bmp.bmHeight;
			}
			else {
				destw = clRect.right;
				desth = destw*bmp.bmHeight / bmp.bmWidth;
			}
		}
		else {
			destw = clRect.right;
			desth = clRect.bottom;
		}
		break;

	case CLB_STRETCHH:
		if (dat->backgroundBmpUse&CLBF_PROPORTIONAL) {
			destw = clRect.right;
			desth = destw*bmp.bmHeight / bmp.bmWidth;
		}
		else {
			destw = clRect.right;
			desth = bmp.bmHeight;
			if (dat->backgroundBmpUse & CLBF_TILEVTOROWHEIGHT)
				desth = dat->row_min_heigh;
		}
		break;

	case CLB_STRETCHV:
		if (dat->backgroundBmpUse&CLBF_PROPORTIONAL) {
			desth = clRect.bottom;
			destw = desth*bmp.bmWidth / bmp.bmHeight;
		}
		else {
			destw = bmp.bmWidth;
			desth = clRect.bottom;
		}
		break;

	default:    //clb_topleft
		destw = bmp.bmWidth;
		desth = bmp.bmHeight;
		if (dat->backgroundBmpUse&CLBF_TILEVTOROWHEIGHT)
			desth = dat->row_min_heigh;
		break;
	}

	for (; y < maxy; y += desth) {
		if (y < rcPaint->top - desth) continue;
		for (x = 0; x < maxx; x += destw)
			StretchBlt(hdcMem, x, y, destw, desth, hdcBmp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
	}
	SelectObject(hdcBmp, oldbm);
	DeleteDC(hdcBmp);
	return TRUE;
}

int CLCPaint::_DetermineDrawMode(HWND hWnd, ClcData *dat)
{
	int paintMode = DM_LAYERED; // by default

	if (dat->bForceInDialog)
		paintMode = DM_CONTROL;
	else if (g_CluiData.fDisableSkinEngine)
		paintMode = DM_CLASSIC;
	else if (!g_CluiData.fLayered)
		paintMode = DM_NON_LAYERED;

	if (!(paintMode&DM_CONTROL) && !CLUI_IsInMainWindow(hWnd))
		paintMode |= DM_FLOAT;

	LONG lStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
	int  nStatus = _GetGeneralisedStatus();
	if ((lStyle & WS_DISABLED) || (dat->greyoutFlags & pcli->pfnClcStatusToPf2(nStatus)) || ((dat->greyoutFlags & GREYF_UNFOCUS) && (GetFocus() != hWnd)))
		paintMode |= DM_GRAY;

	if (lStyle&CLS_GREYALTERNATE)
		paintMode |= DM_GREYALTERNATE;

	return paintMode;
}

void CLCPaint::_PreparePaintContext(ClcData *dat, HDC hdc, int paintMode, RECT& clRect, _PaintContext& pc)
{
	if ((paintMode & DM_GRAY) && !(paintMode & DM_LAYERED)) {
		pc.hdcMem2 = CreateCompatibleDC(hdc);
		if (paintMode & DM_CLASSIC)
			pc.hBmpOsb2 = CreateBitmap(clRect.right, clRect.bottom, 1, GetDeviceCaps(hdc, BITSPIXEL), NULL);
		else
			pc.hBmpOsb2 = ske_CreateDIB32(clRect.right, clRect.bottom);
		pc.oldbmp2 = (HBITMAP)SelectObject(pc.hdcMem2, pc.hBmpOsb2);
		pc.fRelease |= _PaintContext::release_hdcmem2;
	}

	if (paintMode & (DM_DRAW_OFFSCREEN | DM_GRAY)) {
		pc.hdcMem = CreateCompatibleDC(hdc);
		pc.fRelease |= _PaintContext::release_hdcmem;
		pc.hBmpOsb = ske_CreateDIB32(clRect.right, clRect.bottom);
		pc.oldbmp = (HBITMAP)SelectObject(pc.hdcMem, pc.hBmpOsb);
	}

	if ((paintMode & DM_CONTROL) && !dat->bkChanged) {
		pc.tmpbkcolour = GetSysColor(COLOR_3DFACE);
		pc.tmpforecolour = GetSysColor(COLOR_BTNTEXT);
	}
	else {
		pc.tmpbkcolour = (!(paintMode & DM_CONTROL) && dat->bkChanged) ? dat->bkColour : (!dat->bUseWindowsColours ? dat->bkColour : GetSysColor(COLOR_3DFACE));
		pc.tmpforecolour = dat->fontModernInfo[FONTID_CONTACTS].colour;
	}

	if (paintMode & DM_GREYALTERNATE) {
		int rDelta = (GetRValue(pc.tmpbkcolour) > GetRValue(pc.tmpforecolour)) ? -10 : 10;
		int gDelta = (GetGValue(pc.tmpbkcolour) > GetGValue(pc.tmpforecolour)) ? -10 : 10;
		int bDelta = (GetBValue(pc.tmpbkcolour) > GetBValue(pc.tmpforecolour)) ? -10 : 10;
		int rValue = GetRValue(pc.tmpbkcolour) + rDelta;
		int gValue = GetRValue(pc.tmpbkcolour) + gDelta;
		int bValue = GetRValue(pc.tmpbkcolour) + bDelta;

		BYTE brValue = (rValue > 255) ? 255 : rValue < 0 ? 0 : (BYTE)rValue;
		BYTE bgValue = (gValue > 255) ? 255 : gValue < 0 ? 0 : (BYTE)gValue;
		BYTE bbValue = (bValue > 255) ? 255 : bValue < 0 ? 0 : (BYTE)bValue;

		pc.hBrushAlternateGrey = CreateSolidBrush(GetNearestColor(pc.hdcMem, RGB(brValue, bgValue, bbValue)));
	}

	// Set some draw states
	SetBkMode(pc.hdcMem, TRANSPARENT);
	SetStretchBltMode(pc.hdcMem, HALFTONE);

	POINT org;
	GetBrushOrgEx(pc.hdcMem, &org);
	SetBrushOrgEx(pc.hdcMem, org.x, org.y, NULL);
}

void CLCPaint::_DrawBackground(HWND hWnd, ClcData *dat, int paintMode, RECT *rcPaint, RECT& clRect, _PaintContext& pc)
{
	if (paintMode & (DM_FLOAT | DM_CONTROL)) {
		HBRUSH hBrush = CreateSolidBrush(pc.tmpbkcolour);
		FillRect(pc.hdcMem, rcPaint, hBrush);
		DeleteObject(hBrush);
		ske_SetRectOpaque(pc.hdcMem, rcPaint);
		if (!(paintMode & DM_GREYALTERNATE))
			SkinDrawGlyph(pc.hdcMem, &clRect, rcPaint, "CL,ID=Background,Type=Control");
	}
	else if (paintMode & DM_CLASSIC) {
		if (!_DrawNonEnginedBackground(pc.hdcMem, rcPaint, clRect, dat)) {
			HBRUSH hBrush = CreateSolidBrush(pc.tmpbkcolour);
			FillRect(pc.hdcMem, rcPaint, hBrush);
			DeleteObject(hBrush);
		}
	}
	else {
		if (paintMode & DM_NON_LAYERED)
			ske_BltBackImage(hWnd, (paintMode & DM_GRAY) ? pc.hdcMem2 : pc.hdcMem, rcPaint);

		SkinDrawGlyph(pc.hdcMem, &clRect, rcPaint, "CL,ID=Background");
	}
}

void CLCPaint::_DrawLines(HWND hWnd, ClcData *dat, int paintMode, RECT *rcPaint, RECT& clRect, _PaintContext &pc)
{
	ClcGroup *group = &dat->list;
	group->scanIndex = 0;
	int indent = 0;
	int subindex = -1;
	int line_num = -1;
	int y = -dat->yScroll;
	BOOL is_foreground = IsForegroundWindow(hWnd);
	LONG lStyle = GetWindowLongPtr(hWnd, GWL_STYLE);

	while (y < rcPaint->bottom) {
		if (subindex == -1) {
			if (group->scanIndex >= group->cl.getCount()) {
				group = group->parent;
				indent--;
				if (group == NULL) break;  // Finished list
				group->scanIndex++;
				continue;
			}
		}

		line_num++;

		// Draw line, if needed
		if (y > rcPaint->top - dat->getRowHeight(line_num)) {
			RECT rc;

			// Get item to draw
			int subident = 0;
			ClcContact *Drawing;
			if (group->scanIndex < group->cl.getCount()) {
				if (subindex == -1)
					Drawing = group->cl[group->scanIndex];
				else {
					Drawing = &group->cl[group->scanIndex]->subcontacts[subindex];
					subident = dat->subIndent;
				}
			}
			else Drawing = NULL;

			// Something to draw?
			if (Drawing) {
				// Calc row height
				if (!gl_RowRoot)
					RowHeights_GetRowHeight(dat, hWnd, Drawing, line_num);
				else
					RowHeight_CalcRowHeight(dat, Drawing, line_num);

				// Init settings
				int selected = ((line_num == dat->selection) && (dat->hwndRenameEdit != NULL || dat->bShowSelAlways || dat->exStyle&CLS_EX_SHOWSELALWAYS || is_foreground) && Drawing->type != CLCIT_DIVIDER);
				int hottrack = dat->exStyle & CLS_EX_TRACKSELECT && Drawing->type != CLCIT_DIVIDER && dat->iHotTrack == line_num;
				int left_pos = clRect.left + dat->leftMargin + indent * dat->groupIndent + subident;
				int right_pos = dat->rightMargin;   // Border

				RECT row_rc;
				SetRect(&row_rc, clRect.left, y, clRect.right, y + dat->getRowHeight(line_num));

				RECT free_row_rc = row_rc;
				free_row_rc.left += left_pos;
				free_row_rc.right -= right_pos;
				free_row_rc.top += dat->row_border;
				free_row_rc.bottom -= dat->row_border;
				{
					HRGN rgn = CreateRectRgn(row_rc.left, row_rc.top, row_rc.right, row_rc.bottom);
					SelectClipRgn(pc.hdcMem, rgn);
					DeleteObject(rgn);
				}

				// Store pos
				Drawing->pos_indent = free_row_rc.left;
				memset(&Drawing->pos_check, 0, sizeof(Drawing->pos_check));
				memset(&Drawing->pos_avatar, 0, sizeof(Drawing->pos_avatar));
				memset(&Drawing->pos_icon, 0, sizeof(Drawing->pos_icon));
				memset(&Drawing->pos_label, 0, sizeof(Drawing->pos_label));
				memset(&Drawing->pos_extra, 0, sizeof(Drawing->pos_extra));

				//**** Draw Background

				// Alternating grey
				if (paintMode & DM_GREYALTERNATE && (line_num & 1)) {
					if (paintMode & DM_CONTROL || dat->bkChanged)
						FillRect(pc.hdcMem, &row_rc, pc.hBrushAlternateGrey);
					else
						SkinDrawGlyph(pc.hdcMem, &row_rc, rcPaint, "CL,ID=GreyAlternate");
				}
				MODERNMASK *mpRequest = NULL;
				if (!(paintMode & (DM_CLASSIC | DM_CONTROL))) {
					// Row background
					if (!(paintMode & DM_CONTROL)) {   //Build mpRequest string
						mpRequest = _GetCLCContactRowBackModernMask(group, Drawing, indent, line_num, selected, hottrack, dat);

						RECT mrc = row_rc;
						if (group->parent == 0
							&& group->scanIndex != 0
							&& group->scanIndex < group->cl.getCount()
							&& group->cl[group->scanIndex]->type == CLCIT_GROUP) {
							mrc.top += dat->row_before_group_space;
						}
						SkinDrawGlyphMask(pc.hdcMem, &mrc, rcPaint, mpRequest);
					}
					if (selected || hottrack) {
						RECT mrc = row_rc;
						if (Drawing->type == CLCIT_GROUP  &&
							Drawing->group->parent->groupId == 0 &&
							Drawing->group->parent->cl[0] != Drawing) {
							mrc.top += dat->row_before_group_space;
						}
						// Selection background ( only if hole line - full/less )
						if (dat->HiLightMode == 1) { // Full  or default
							if (selected)
								SkinDrawGlyph(pc.hdcMem, &mrc, rcPaint, "CL,ID=Selection");
							if (hottrack)
								SkinDrawGlyph(pc.hdcMem, &mrc, rcPaint, "CL,ID=HotTracking");
						}
						else if (dat->HiLightMode == 2) { // Less
							if (selected)
								SkinDrawGlyph(pc.hdcMem, &mrc, rcPaint, "CL,ID=Selection");      //instead of free_row_rc
							if (hottrack)
								SkinDrawGlyph(pc.hdcMem, &mrc, rcPaint, "CL,ID=HotTracking");
						}
					}
				}
				else {
					// background
					if (selected) {
						int row_height;
						switch (dat->HiLightMode) {
						case 0:
						case 1:
							row_height = row_rc.bottom - row_rc.top;
							for (int i = y; i < y + row_height; i += max(dat->row_min_heigh, 1)) {
								ImageList_DrawEx(dat->himlHighlight, 0, pc.hdcMem, 0, i, clRect.right,
									min(y + row_height - i, max(dat->row_min_heigh, 1)), CLR_NONE, CLR_NONE,
									dat->exStyle & CLS_EX_NOTRANSLUCENTSEL ? ILD_NORMAL : ILD_BLEND25);
							}
							SetTextColor(pc.hdcMem, paintMode&DM_CONTROL ? GetSysColor(COLOR_HIGHLIGHTTEXT) : dat->selTextColour);
							break;

						case 2:
							row_height = row_rc.bottom - row_rc.top - 1;
							for (int i = y + 1; i < y + row_height; i += max(dat->row_min_heigh, 1)) {
								ImageList_DrawEx(dat->himlHighlight, 0, pc.hdcMem, 1, i, clRect.right - 2,
									min(y + row_height - i, max(dat->row_min_heigh, 1)), CLR_NONE, CLR_NONE,
									dat->exStyle & CLS_EX_NOTRANSLUCENTSEL ? ILD_NORMAL : ILD_BLEND25);
							}
							SetTextColor(pc.hdcMem, paintMode & DM_CONTROL ? GetSysColor(COLOR_HIGHLIGHTTEXT) : dat->selTextColour);
							break;
						}
					}
				}
				//**** Checkboxes
				if (Drawing->isCheckBox(lStyle)) {
					rc = free_row_rc;
					rc.right = rc.left + dat->checkboxSize;
					rc.top += (rc.bottom - rc.top - dat->checkboxSize) >> 1;
					rc.bottom = rc.top + dat->checkboxSize;

					if (dat->text_rtl != 0)
						_RTLRect(&rc, free_row_rc.right);

					if (xpt_IsThemed(dat->hCheckBoxTheme))
						xpt_DrawThemeBackground(dat->hCheckBoxTheme, pc.hdcMem, BP_CHECKBOX, Drawing->flags & CONTACTF_CHECKED ? (hottrack ? CBS_CHECKEDHOT : CBS_CHECKEDNORMAL) : (hottrack ? CBS_UNCHECKEDHOT : CBS_UNCHECKEDNORMAL), &rc, &rc);
					else
						DrawFrameControl(pc.hdcMem, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_FLAT | (Drawing->flags & CONTACTF_CHECKED ? DFCS_CHECKED : 0) | (hottrack ? DFCS_HOT : 0));

					left_pos += dat->checkboxSize + EXTRA_CHECKBOX_SPACE + HORIZONTAL_SPACE;
					free_row_rc.left = row_rc.left + left_pos;

					// Store pos
					Drawing->pos_check = rc;
				}
				_PaintRowItems(pc.hdcMem, dat, Drawing, row_rc, free_row_rc, left_pos, right_pos, selected, hottrack, rcPaint);
				if (mpRequest) {
					if (!dat->bForceInDialog) {
						mir_free(mpRequest->pl_Params[1].szValue);
						mpRequest->pl_Params[1].szValue = mir_strndup("Ovl", 3);
						mpRequest->pl_Params[1].dwValueHash = mod_CalcHash("Ovl");

						RECT mrc = row_rc;
						if (Drawing->type == CLCIT_GROUP  &&
							Drawing->group->parent->groupId == 0 &&
							Drawing->group->parent->cl[0] != Drawing) {
							mrc.top += dat->row_before_group_space;
						}
						SkinDrawGlyphMask(pc.hdcMem, &mrc, rcPaint, mpRequest);
						SkinSelector_DeleteMask(mpRequest);
					}
					mir_free(mpRequest);
				}
			}
		}
		y += dat->getRowHeight(line_num);

		// increment by subcontacts
		ClcContact *cc = group->cl[group->scanIndex];
		if (cc != NULL && cc->subcontacts != NULL && cc->type != CLCIT_GROUP && cc->bSubExpanded && dat->bMetaExpanding) {
			if (subindex < cc->iSubAllocated - 1)
				subindex++;
			else
				subindex = -1;
		}

		if (cc && subindex == -1) {
			if (cc->type == CLCIT_GROUP && cc->group->expanded) {
				group = cc->group;
				indent++;
				group->scanIndex = 0;
				subindex = -1;
				continue;
			}
			group->scanIndex++;
		}
		else if (group->scanIndex >= group->cl.getCount()) {
			subindex = -1;
		}
	}
	SelectClipRgn(pc.hdcMem, NULL);
}

void CLCPaint::_DrawInsertionMark(ClcData *dat, RECT &clRect, _PaintContext &pc)
{
	int identation = dat->nInsertionLevel*dat->groupIndent;
	int yt = cliGetRowTopY(dat, dat->iInsertionMark);

	POINT pts[8];
	pts[0].y = yt - dat->yScroll - 4;
	if (pts[0].y < -3) pts[0].y = -3;
	pts[0].x = 1 + identation*(dat->text_rtl ? 0 : 1);

	pts[1].x = pts[0].x + 2;
	pts[1].y = pts[0].y + 3;

	pts[2].x = clRect.right - identation*(dat->text_rtl ? 1 : 0) - 4;
	pts[2].y = pts[1].y;

	pts[3].x = clRect.right - 1 - identation*(dat->text_rtl ? 1 : 0);
	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 hRgn = CreatePolygonRgn(pts, sizeof(pts) / sizeof(pts[0]), ALTERNATE);
	HBRUSH hBrush = CreateSolidBrush(dat->fontModernInfo[FONTID_CONTACTS].colour);
	HBRUSH hoBrush = (HBRUSH)SelectObject(pc.hdcMem, hBrush);
	FillRgn(pc.hdcMem, hRgn, hBrush);
	ske_SetRgnOpaque(pc.hdcMem, hRgn);
	SelectObject(pc.hdcMem, hoBrush);
	DeleteObject(hBrush);
}

void CLCPaint::_CopyPaintToDest(HDC hdc, int paintMode, RECT* rcPaint, _PaintContext& pc)
{
	if (!(paintMode & DM_GRAY) && (paintMode & DM_DRAW_OFFSCREEN))
		BitBlt(hdc, rcPaint->left, rcPaint->top, rcPaint->right - rcPaint->left, rcPaint->bottom - rcPaint->top, pc.hdcMem, rcPaint->left, rcPaint->top, SRCCOPY);

	if ((paintMode & DM_GRAY) && hdc && hdc != pc.hdcMem) {
		BLENDFUNCTION bf = { AC_SRC_OVER, 0, 80, AC_SRC_ALPHA };
		BOOL a = ((paintMode&DM_GRAY) && ((paintMode&DM_NON_LAYERED)));
		ske_AlphaBlend(a ? pc.hdcMem2 : hdc, rcPaint->left, rcPaint->top, rcPaint->right - rcPaint->left, rcPaint->bottom - rcPaint->top, pc.hdcMem, rcPaint->left, rcPaint->top, rcPaint->right - rcPaint->left, rcPaint->bottom - rcPaint->top, bf);
		if (a)
			BitBlt(hdc, rcPaint->left, rcPaint->top, rcPaint->right - rcPaint->left, rcPaint->bottom - rcPaint->top, pc.hdcMem2, rcPaint->left, rcPaint->top, SRCCOPY);
	}
}

void CLCPaint::_FreePaintContext(_PaintContext &pc)
{
	if (pc.hBrushAlternateGrey) DeleteObject(pc.hBrushAlternateGrey);
	SelectObject(pc.hdcMem, (HFONT)GetStockObject(DEFAULT_GUI_FONT));
	if (pc.fRelease&_PaintContext::release_hdcmem) {
		SelectObject(pc.hdcMem, pc.oldbmp);
		DeleteObject(pc.hBmpOsb);
		DeleteDC(pc.hdcMem);
	}
	if (pc.fRelease&_PaintContext::release_hdcmem2) {
		SelectObject(pc.hdcMem2, pc.oldbmp2);
		DeleteObject(pc.hBmpOsb2);
		DeleteDC(pc.hdcMem2);
	}
}

void CLCPaint::_PaintClc(HWND hwnd, ClcData *dat, HDC hdc, RECT *_rcPaint)
{
	g_CluiData.t_now = time(NULL);

	if (_rcPaint && IsRectEmpty(_rcPaint)) return;       // check if draw area is not empty
	if (!IsWindowVisible(hwnd)) return;                  // and window is visible

	RECT clRect;
	GetClientRect(hwnd, &clRect);

	RECT *rcPaint = _rcPaint ? _rcPaint : &clRect;       // if null is transmitted - use whole client area

	// Invalidate ani avatars, avatars have to be validated in row paint routine below
	if (rcPaint->top == 0 && rcPaint->bottom == clRect.bottom && dat->avatars_show)
		AniAva_InvalidateAvatarPositions(NULL);

	// Now determine paint mode
	int paintMode = _DetermineDrawMode(hwnd, dat);

	// Preparing drawing contexts
	_PaintContext pc(hdc);
	_PreparePaintContext(dat, hdc, paintMode, clRect, pc);

	// Draw background
	_DrawBackground(hwnd, dat, paintMode, rcPaint, clRect, pc);

	// Draw lines
	if (!dat->row_variable_height || dat->row_heights) {
		_DrawLines(hwnd, dat, paintMode, rcPaint, clRect, pc);

		// insertion mark
		if (dat->iInsertionMark != -1)
			_DrawInsertionMark(dat, clRect, pc);
	}

	// BitBlt from memory to destination
	_CopyPaintToDest(hdc, paintMode, rcPaint, pc);

	// Free
	_FreePaintContext(pc);

	// all still non-validated animated avatars have to be removed
	AniAva_RemoveInvalidatedAvatars();
}

void CLCPaint::_StoreItemPos(ClcContact *contact, int ItemType, RECT *rc)
{
	contact->ext_mpItemsDesc[contact->ext_nItemsNum].itemType = ItemType;
	contact->ext_mpItemsDesc[contact->ext_nItemsNum].itemRect = *rc;
	contact->ext_nItemsNum++;
	switch (ItemType) {
	case CIT_AVATAR:
		contact->pos_avatar = *rc;
		break;
	case CIT_ICON:
		contact->pos_icon = *rc;
		break;
	case CIT_TIME:
		contact->pos_contact_time = *rc;
		break;
	case CIT_TEXT:
		//	RECT pos_label;//TODO label ( CIT_TEXT??? )
		//	RECT pos_rename; //TODO		( CIT_TEXT??? )
		break;
	case CIT_CHECKBOX:
		break;
	default:
		if ((ItemType & CIT_EXTRA) == CIT_EXTRA) {
			int iImage = ItemType & 0x3F;
			contact->pos_extra[iImage] = *rc;
		}
		break;
	}
}

void CLCPaint::_CalcItemsPos(HDC hdcMem, ClcData *dat, ClcContact *Drawing, RECT *in_row_rc, RECT *in_free_row_rc, int left_pos, int right_pos, int selected)
{
	ClcCacheEntry *pdnce = Drawing->pce;
	int item_iterator, item, item_text = 0, text_left_pos;
	BOOL left = TRUE;               //TODO remove
	RECT free_row_rc = *in_free_row_rc;
	RECT row_rc = *in_row_rc;
	Drawing->ext_nItemsNum = 0;
	text_left_pos = row_rc.right;
	// Now let's check what we have to draw
	for (item_iterator = 0; item_iterator < NUM_ITEM_TYPE && free_row_rc.left < free_row_rc.right; item_iterator++) {
		if (Drawing->ext_nItemsNum >= _countof(Drawing->ext_mpItemsDesc)) break;
		if (left)
			item = item_iterator;
		else
			item = NUM_ITEM_TYPE - (item_iterator - item_text);

		switch (dat->row_items[item]) {
		case ITEM_AVATAR: ///////////////////////////////////////////////////////////////////////////////////////////////////
			{
				int max_width;
				int width;
				int height;
				BOOL miniMode;
				if (!dat->avatars_show || Drawing->type != CLCIT_CONTACT)
					break;
				miniMode = CheckMiniMode(dat, selected);
				AniAva_InvalidateAvatarPositions(Drawing->hContact);
				if (dat->icon_hide_on_avatar && dat->icon_draw_on_avatar_space)
					max_width = max(dat->iconXSpace, dat->avatars_maxheight_size);
				else
					max_width = dat->avatars_maxheight_size;

				// Has to draw?
				if (Drawing->avatar_data == NULL || miniMode) {
					// Don't have to draw avatar

					// Has to draw icon instead?
					if (dat->icon_hide_on_avatar && dat->icon_draw_on_avatar_space && Drawing->iImage != -1) {
						// Make rectangle
						RECT rc = _GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos, left, dat->iconXSpace, max_width, ICON_HEIGHT, HORIZONTAL_SPACE);
						if (rc.left < rc.right) {
							// center icon in avatar place
							if (rc.right - rc.left > 16) rc.left += (((rc.right - rc.left) - 16) >> 1);
							if (rc.bottom - rc.top > 16) rc.top += (((rc.bottom - rc.top) - 16) >> 1);

							// Store position
							_StoreItemPos(Drawing, CIT_ICON, &rc);
						}
					}
					else {
						// Has to keep the empty space??
						if ((left && !dat->row_align_left_items_to_left) || (!left && !dat->row_align_right_items_to_right)) {
							// Make rectangle
							// NOTE: Calling _GetRectangle on next line has to be here, because it provides side-effect for positioning contact name correctly if contact has no avatar.
							// It makes it aligned same way as if avatar was here. Just defining rc variable is useless, as it is never used (and just shows warning).
							/*RECT rc =*/ _GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos, left, max_width, max_width, dat->avatars_maxheight_size, HORIZONTAL_SPACE);

							// Store position
							//StoreItemPos( Drawing, CIT_AVATAR, &rc );
							//Drawing->pos_avatar = rc;
						}
					}
					break;
				}

				// Has to draw avatar
				if (dat->avatar_cache.nodes && Drawing->avatar_pos > AVATAR_POS_DONT_HAVE) {
					width = dat->avatar_cache.nodes[Drawing->avatar_pos].width;
					height = dat->avatar_cache.nodes[Drawing->avatar_pos].height;
				}
				else if (Drawing->avatar_pos == AVATAR_POS_ANIMATED) {
					width = Drawing->avatar_size.cx;
					height = Drawing->avatar_size.cy;
				}
				else {
					width = 0;
					height = 0;
				}

				// Make rectangle
				RECT rc = _GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos, left, width, max_width, height, HORIZONTAL_SPACE);

				rc.top = max(free_row_rc.top, rc.top);
				rc.bottom = min(free_row_rc.bottom, rc.bottom);

				if (rc.left < rc.right) // Store position
					_StoreItemPos(Drawing, CIT_AVATAR, &rc);
				//TO DO: CALC avatar overlays
			}
			break;

		case ITEM_ICON: /////////////////////////////////////////////////////////////////////////////////////////////////////
			{
				int iImage = -1;
				BOOL has_avatar = Drawing->avatar_data != NULL && !CheckMiniMode(dat, selected);

				if (Drawing->type == CLCIT_CONTACT
					&& dat->icon_hide_on_avatar
					&& !dat->icon_draw_on_avatar_space
					&& has_avatar
					&& !Drawing->bImageIsSpecial) {
					// Don't have to draw, but has to keep the empty space?
					if ((left && !dat->row_align_left_items_to_left) || (!left && !dat->row_align_right_items_to_right)) {
						RECT rc = _GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos, left, dat->iconXSpace, dat->iconXSpace, ICON_HEIGHT, HORIZONTAL_SPACE);
						if (rc.left < rc.right) // Store position
							_StoreItemPos(Drawing, CIT_ICON, &rc);
					}
					break;
				}
				if (Drawing->type == CLCIT_CONTACT
					&& dat->icon_hide_on_avatar
					&& dat->icon_draw_on_avatar_space
					&& (!Drawing->bImageIsSpecial || !has_avatar ||
					(dat->avatars_draw_overlay
					&& dat->avatars_maxheight_size >= ICON_HEIGHT + (dat->avatars_draw_border ? 2 : 0)
					&& GetContactCachedStatus(Drawing->hContact) - ID_STATUS_OFFLINE < _countof(g_pAvatarOverlayIcons)
					&& dat->avatars_overlay_type == SETTING_AVATAR_OVERLAY_TYPE_CONTACT))) {
					// Don't have to draw and don't have to keep the empty space
					break;
				}

				// Get image
				iImage = -1;
				if (Drawing->type == CLCIT_GROUP && !dat->row_hide_group_icon)
					iImage = Drawing->group->expanded ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT;
				else if (Drawing->type == CLCIT_CONTACT)
					iImage = Drawing->iImage;

				// Has image to draw?
				if (iImage != -1) {
					// Make rectangle
					RECT rc = _GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos, left, dat->iconXSpace, dat->iconXSpace, ICON_HEIGHT, HORIZONTAL_SPACE);
					if (rc.left < rc.right) // Store position
						_StoreItemPos(Drawing, CIT_ICON, &rc);
				}
			}
			break;

		case ITEM_CONTACT_TIME: /////////////////////////////////////////////////////////////////////////////////////////////////////
			if (Drawing->type == CLCIT_CONTACT && dat->contact_time_show && pdnce->hTimeZone) {
				wchar_t szResult[80];

				if (!TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", szResult, _countof(szResult), 0)) {
					// Select font
					ChangeToFont(hdcMem, dat, FONTID_CONTACT_TIME, NULL);

					// Get text size
					RECT rc;
					SIZE text_size;
					text_size.cy = ske_DrawText(hdcMem, szResult, (int)mir_wstrlen(szResult), &rc, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);
					text_size.cy = min(text_size.cy, free_row_rc.bottom - free_row_rc.top);
					text_size.cx = rc.right - rc.left;

					// Get rc
					rc = _GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos, left, text_size.cx, text_size.cx, text_size.cy, HORIZONTAL_SPACE);
					if (rc.left < rc.right) { // Store pos
						Drawing->pos_contact_time = rc;
						_StoreItemPos(Drawing, CIT_TIME, &rc);
					}
				}
			}
			break;

		case ITEM_TEXT: /////////////////////////////////////////////////////////////////////////////////////////////////////
			// Store init text position:
			text_left_pos = left_pos;

			left_pos += MIN_TEXT_WIDTH;
			free_row_rc.left = row_rc.left + left_pos;

			item_text = item;
			left = FALSE;
			break;

		case ITEM_EXTRA_ICONS: //////////////////////////////////////////////////////////////////////////////////////////////
			// Draw extra icons
			if (!Drawing->iSubNumber || dat->dbbMetaHideExtra == 0 && dat->extraColumnsCount > 0) {
				int iImage;
				int count = 0;

				for (iImage = dat->extraColumnsCount - 1; iImage >= 0; iImage--) {
					if (Drawing->iExtraImage[iImage] != EMPTY_EXTRA_ICON || !dat->bMetaIgnoreEmptyExtra) {
						RECT rc = _GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos, left, dat->extraColumnSpacing, dat->extraColumnSpacing, ICON_HEIGHT, 0);
						if (rc.left < rc.right) {
							// Store position
							_StoreItemPos(Drawing, CIT_EXTRA | (iImage & 0x3F), &rc);
							// Drawing->pos_extra[iImage] = rc;
							count++;
						}
					}
				}
				// Add extra space
				if (count) {
					_GetRectangle(dat, &row_rc, &free_row_rc, &left_pos, &right_pos,
						left, HORIZONTAL_SPACE, HORIZONTAL_SPACE, ICON_HEIGHT, 0);
				}
			}
			break;
		}
	}
	if (text_left_pos < free_row_rc.right) {
		// Draw text
		int max_bottom_selection_border = SELECTION_BORDER;
		UINT uTextFormat = DT_NOPREFIX | /*DT_VCENTER |*/ DT_SINGLELINE | (dat->text_rtl ? DT_RTLREADING : 0) | (dat->text_align_right ? DT_RIGHT : 0);

		free_row_rc.left = text_left_pos;
		int free_height = free_row_rc.bottom - free_row_rc.top;

		// Select font
		ChangeToFont(hdcMem, dat, GetBasicFontID(Drawing), NULL);

		// Get text size
		SIZE text_size = { 0 };
		GetTextSize(&text_size, hdcMem, free_row_rc, Drawing->szText, Drawing->ssText.plText, uTextFormat,
			dat->text_resize_smileys ? 0 : Drawing->ssText.iMaxSmileyHeight);

		// Get rect
		RECT text_rc = free_row_rc;

		free_height -= text_size.cy;
		text_rc.top += free_height >> 1;
		text_rc.bottom = text_rc.top + text_size.cy;

		if (dat->text_align_right)
			text_rc.left = max(free_row_rc.left, free_row_rc.right - text_size.cx);
		else
			text_rc.right = min(free_row_rc.right, free_row_rc.left + text_size.cx);

		RECT selection_text_rc = text_rc;
		SIZE counts_size = { 0 }, second_line_text_size = { 0 }, third_line_text_size = { 0 };

		// If group, can have the size of count
		if (Drawing->type == CLCIT_GROUP) {
			int full_text_width = text_size.cx;
			// Has to draw the count?
			wchar_t *szCounts = pcli->pfnGetGroupCountsText(dat, Drawing);
			if (szCounts && szCounts[0]) {
				RECT space_rc = free_row_rc;
				RECT counts_rc = free_row_rc;

				free_height = free_row_rc.bottom - free_row_rc.top;

				// Get widths
				ske_DrawText(hdcMem, L" ", 1, &space_rc, DT_CALCRECT | DT_NOPREFIX);

				SIZE space_size;
				space_size.cx = space_rc.right - space_rc.left;
				space_size.cy = min(space_rc.bottom - space_rc.top, free_height);

				ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
				DrawText(hdcMem, szCounts, (int)mir_wstrlen(szCounts), &counts_rc, DT_CALCRECT);

				counts_size.cx = counts_rc.right - counts_rc.left;
				counts_size.cy = min(counts_rc.bottom - counts_rc.top, free_height);
				counts_size.cx++; // FIXME: This is workaround for sometimes stripped user counts by one pixel, it somehow wrongly counts width of space or counts text (used wrong font?)

				int text_width = free_row_rc.right - free_row_rc.left - space_size.cx - counts_size.cx;
				if (text_width > 4) {
					text_size.cx = min(text_width, text_size.cx);
					text_width = text_size.cx + space_size.cx + counts_size.cx;
				}
				else {
					text_width = text_size.cx;
					space_size.cx = 0;
					space_size.cy = 0;
					counts_size.cx = 0;
					counts_size.cy = 0;
				}

				// Get rect
				free_height -= max(text_size.cy, counts_size.cy);
				text_rc.top = free_row_rc.top + (free_height >> 1);
				text_rc.bottom = text_rc.top + max(text_size.cy, counts_size.cy);

				if (dat->text_align_right)
					text_rc.left = free_row_rc.right - text_width;
				else
					text_rc.right = free_row_rc.left + text_width;

				selection_text_rc = text_rc;
				full_text_width = text_width;
				ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPS : FONTID_CLOSEDGROUPS, NULL);
			}

			if (dat->row_align_group_mode == 1) { // center
				int x = free_row_rc.left + ((free_row_rc.right - free_row_rc.left - full_text_width) >> 1);
				text_rc.left = x;
				text_rc.right = x + full_text_width;
			}
			else if (dat->row_align_group_mode == 2) { // right
				text_rc.left = free_row_rc.right - full_text_width;
				text_rc.right = free_row_rc.right;
			}
			else { // left
				text_rc.left = free_row_rc.left;
				text_rc.right = free_row_rc.left + full_text_width;
			}
		}
		else if (Drawing->type == CLCIT_CONTACT && !CheckMiniMode(dat, selected)) {
			if (dat->secondLine.show) {
				if (dat->secondLine.type == TEXT_CONTACT_TIME && pdnce->hTimeZone) {
					// Get contact time
					wchar_t buf[70] = L"";
					TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", buf, _countof(buf), 0);
					replaceStrW(pdnce->szSecondLineText, buf);
				}

				if (pdnce->szSecondLineText && pdnce->szSecondLineText[0] && free_height > dat->secondLine.top_space) {
					ChangeToFont(hdcMem, dat, FONTID_SECONDLINE, NULL);

					// Get sizes
					GetTextSize(&second_line_text_size, hdcMem, free_row_rc, pdnce->szSecondLineText, pdnce->ssSecondLine.plText,
						uTextFormat, dat->text_resize_smileys ? 0 : pdnce->ssSecondLine.iMaxSmileyHeight);

					// Get rect
					int tmp = min(free_height, dat->secondLine.top_space + second_line_text_size.cy);

					free_height -= tmp;
					text_rc.top = free_row_rc.top + (free_height >> 1);
					text_rc.bottom = text_rc.top + free_row_rc.bottom - free_row_rc.top - free_height;

					if (dat->text_align_right)
						text_rc.left = max(free_row_rc.left, min(text_rc.left, free_row_rc.right - second_line_text_size.cx));
					else
						text_rc.right = min(free_row_rc.right, max(text_rc.right, free_row_rc.left + second_line_text_size.cx));

					selection_text_rc.top = text_rc.top;
					selection_text_rc.bottom = min(selection_text_rc.bottom, selection_text_rc.top + text_size.cy);

					max_bottom_selection_border = min(max_bottom_selection_border, dat->secondLine.top_space / 2);
				}
			}
			if (dat->thirdLine.show) {
				if (dat->thirdLine.type == TEXT_CONTACT_TIME && pdnce->hTimeZone) {
					// Get contact time
					wchar_t buf[70] = L"";
					TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", buf, _countof(buf), 0);
					replaceStrW(pdnce->szThirdLineText, buf);
				}
				if (pdnce->szThirdLineText != NULL && pdnce->szThirdLineText[0] && free_height > dat->thirdLine.top_space) {
					ChangeToFont(hdcMem, dat, FONTID_THIRDLINE, NULL);

					// Get sizes
					GetTextSize(&third_line_text_size, hdcMem, free_row_rc, pdnce->szThirdLineText, pdnce->ssThirdLine.plText,
						uTextFormat, dat->text_resize_smileys ? 0 : pdnce->ssThirdLine.iMaxSmileyHeight);

					// Get rect
					int tmp = min(free_height, dat->thirdLine.top_space + third_line_text_size.cy);

					free_height -= tmp;
					text_rc.top = free_row_rc.top + (free_height >> 1);
					text_rc.bottom = text_rc.top + free_row_rc.bottom - free_row_rc.top - free_height;

					if (dat->text_align_right)
						text_rc.left = max(free_row_rc.left, min(text_rc.left, free_row_rc.right - third_line_text_size.cx));
					else
						text_rc.right = min(free_row_rc.right, max(text_rc.right, free_row_rc.left + third_line_text_size.cx));

					selection_text_rc.top = text_rc.top;
					selection_text_rc.bottom = min(selection_text_rc.bottom, selection_text_rc.top + text_size.cy);

					max_bottom_selection_border = min(max_bottom_selection_border, dat->thirdLine.top_space / 2);
				}
			}

			ChangeToFont(hdcMem, dat, GetBasicFontID(Drawing), NULL);
		}

		selection_text_rc.left = text_rc.left;
		selection_text_rc.right = text_rc.right;

		Drawing->pos_label = text_rc;

		selection_text_rc.top = max(selection_text_rc.top - SELECTION_BORDER, row_rc.top);
		selection_text_rc.bottom = min(selection_text_rc.bottom + max_bottom_selection_border, row_rc.bottom);

		if (dat->text_align_right)
			selection_text_rc.left = max(selection_text_rc.left - SELECTION_BORDER, free_row_rc.left);
		else
			selection_text_rc.right = min(selection_text_rc.right + SELECTION_BORDER, free_row_rc.right);
		_StoreItemPos(Drawing, CIT_SELECTION, &selection_text_rc);

		// Draw text
		uTextFormat = uTextFormat | (gl_TrimText ? DT_END_ELLIPSIS : 0);

		switch (Drawing->type) {
		case CLCIT_DIVIDER:
			{
				//devider
				RECT trc = free_row_rc;
				RECT rc = free_row_rc;
				rc.top += (rc.bottom - rc.top) >> 1;
				rc.bottom = rc.top + 2;
				rc.right = rc.left + ((rc.right - rc.left - text_size.cx) >> 1) - 3;
				trc.left = rc.right + 3;
				trc.right = trc.left + text_size.cx + 6;
				if (text_size.cy < trc.bottom - trc.top) {
					trc.top += (trc.bottom - trc.top - text_size.cy) >> 1;
					trc.bottom = trc.top + text_size.cy;
				}
				_StoreItemPos(Drawing, CIT_TEXT, &trc);
				rc.left = rc.right + 6 + text_size.cx;
				rc.right = free_row_rc.right;
			}
			break;
		case CLCIT_GROUP:
			{
				RECT rc = text_rc;

				// Get text rectangle
				if (dat->text_align_right)
					rc.left = rc.right - text_size.cx;
				else
					rc.right = rc.left + text_size.cx;

				if (text_size.cy < rc.bottom - rc.top) {
					rc.top += (rc.bottom - rc.top - text_size.cy) >> 1;
					rc.bottom = rc.top + text_size.cy;
				}

				// Draw text
				_StoreItemPos(Drawing, CIT_TEXT, &rc);

				// Has to draw the count?
				if (counts_size.cx > 0) {
					RECT counts_rc = text_rc;
					//counts_size.cx;
					if (dat->text_align_right)
						counts_rc.right = text_rc.left + counts_size.cx;
					else
						counts_rc.left = text_rc.right - counts_size.cx;

					if (counts_size.cy < counts_rc.bottom - counts_rc.top) {
						counts_rc.top += (counts_rc.bottom - counts_rc.top - counts_size.cy + 1) >> 1;
						counts_rc.bottom = counts_rc.top + counts_size.cy;
					}
					// Draw counts
					_StoreItemPos(Drawing, CIT_SUBTEXT1, &counts_rc);
				}
			}
			break;
		case CLCIT_CONTACT:
			{
				RECT free_rc = text_rc;
				if (text_size.cx > 0 && free_rc.bottom > free_rc.top) {
					RECT rc = free_rc;
					rc.bottom = min(rc.bottom, rc.top + text_size.cy);

					if (text_size.cx < rc.right - rc.left) {
						if (dat->text_align_right)
							rc.left = rc.right - text_size.cx;
						else
							rc.right = rc.left + text_size.cx;
					}
					uTextFormat |= DT_VCENTER;
					_StoreItemPos(Drawing, CIT_TEXT, &rc);
					free_rc.top = rc.bottom;
				}
				uTextFormat &= ~DT_VCENTER;
				if (second_line_text_size.cx > 0 && free_rc.bottom > free_rc.top) {
					free_rc.top += dat->secondLine.top_space;

					if (free_rc.bottom > free_rc.top) {
						RECT rc = free_rc;
						rc.bottom = min(rc.bottom, rc.top + second_line_text_size.cy);

						if (second_line_text_size.cx < rc.right - rc.left) {
							if (dat->text_align_right)
								rc.left = rc.right - second_line_text_size.cx;
							else
								rc.right = rc.left + second_line_text_size.cx;
						}
						_StoreItemPos(Drawing, CIT_SUBTEXT1, &rc);
						free_rc.top = rc.bottom;
					}
				}

				if (third_line_text_size.cx > 0 && free_rc.bottom > free_rc.top) {
					free_rc.top += dat->thirdLine.top_space;

					if (free_rc.bottom > free_rc.top) {
						RECT rc = free_rc;
						rc.bottom = min(rc.bottom, rc.top + third_line_text_size.cy);

						if (third_line_text_size.cx < rc.right - rc.left) {
							if (dat->text_align_right)
								rc.left = rc.right - third_line_text_size.cx;
							else
								rc.right = rc.left + third_line_text_size.cx;
						}
						_StoreItemPos(Drawing, CIT_SUBTEXT2, &rc);
						free_rc.top = rc.bottom;
					}
				}
			}
			break;

		default: // CLCIT_INFO
			_StoreItemPos(Drawing, CIT_TEXT, &text_rc);
		}
	}

	*in_free_row_rc = free_row_rc;
	*in_row_rc = row_rc;
	Drawing->ext_fItemsValid = FALSE; /*TO DO: correctly implement placement recalculation*/
}

BOOL CLCPaint::__IsVisible(RECT *firtRect, RECT *secondRect)
{
	RECT res;
	IntersectRect(&res, firtRect, secondRect);
	return !IsRectEmpty(&res);
}

void CLCPaint::_GetBlendMode(IN ClcData *dat, IN ClcContact *Drawing, IN BOOL selected, IN BOOL hottrack, IN BOOL bFlag, OUT COLORREF * OutColourFg, OUT int * OutMode)
{
	COLORREF colourFg;
	int mode;
	int BlendedInActiveState = (dat->dbbBlendInActiveState);
	int BlendValue = dat->dbbBlend25 ? ILD_BLEND25 : ILD_BLEND50;
	if (selected && (bFlag&GIM_SELECTED_AFFECT)) {
		colourFg = dat->selBkColour;
		mode = BlendedInActiveState ? ILD_NORMAL : ILD_SELECTED;
	}
	else if (hottrack && (bFlag&GIM_HOT_AFFECT)) {
		mode = BlendedInActiveState ? ILD_NORMAL : ILD_FOCUS;
		colourFg = dat->hotTextColour;
	}
	else if (Drawing->type == CLCIT_CONTACT && Drawing->flags&CONTACTF_NOTONLIST && (bFlag&GIM_TEMP_AFFECT)) {
		colourFg = dat->fontModernInfo[FONTID_NOTONLIST].colour;
		mode = BlendValue;
	}
	else {
		colourFg = dat->selBkColour;
		mode = ILD_NORMAL;
	}
	if (Drawing->type == CLCIT_CONTACT && dat->bShowIdle && (Drawing->flags&CONTACTF_IDLE) &&
		_GetRealStatus(Drawing, ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE &&
		(bFlag & GIM_IDLE_AFFECT))
		mode = ILD_SELECTED;
	if (OutColourFg) *OutColourFg = colourFg;
	if (OutMode) {
		if (OutColourFg)    *OutMode = mode;  //return ILD_MODE if color requested
		else *OutMode =
			(mode == ILD_BLEND50) ? 128 :
			(mode == ILD_BLEND25) ? 64 :
			255;    //return alpha otherwise
	}
}

void CLCPaint::_DrawContactAvatar(HDC hdcMem, ClcData *dat, ClcContact *Drawing, RECT *row_rc, int &selected, int &hottrack, RECT *prcItem)
{
	if (Drawing->avatar_pos == AVATAR_POS_ANIMATED) {
		int overlayIdx = -1;
		int blendmode = 255;
		if (dat->avatars_draw_overlay && dat->avatars_maxheight_size >= ICON_HEIGHT + (dat->avatars_draw_border ? 2 : 0)
			&& GetContactCachedStatus(Drawing->hContact) - ID_STATUS_OFFLINE < _countof(g_pAvatarOverlayIcons)) {
			switch (dat->avatars_overlay_type) {
			case SETTING_AVATAR_OVERLAY_TYPE_NORMAL:
				overlayIdx = g_pAvatarOverlayIcons[GetContactCachedStatus(Drawing->hContact) - ID_STATUS_OFFLINE].listID;
				break;
			case SETTING_AVATAR_OVERLAY_TYPE_PROTOCOL:
				overlayIdx = pcli->pfnIconFromStatusMode(Drawing->proto, Drawing->proto == NULL ? ID_STATUS_OFFLINE : GetContactCachedStatus(Drawing->hContact), Drawing->hContact);
				break;
			case SETTING_AVATAR_OVERLAY_TYPE_CONTACT:
				overlayIdx = Drawing->iImage;
				break;
			}
		}
		_GetBlendMode(dat, Drawing, selected, hottrack, GIM_AVATAR_AFFECT, NULL, &blendmode);
		AniAva_SetAvatarPos(Drawing->hContact, prcItem, overlayIdx, blendmode);
		AniAva_RenderAvatar(Drawing->hContact, hdcMem, prcItem);
	}
	else if (Drawing->avatar_pos > AVATAR_POS_DONT_HAVE) {
		int round_radius = 0;
		HRGN rgn;
		int blendmode = 255;

		_GetBlendMode(dat, Drawing, selected, hottrack, GIM_AVATAR_AFFECT, NULL, &blendmode);

		//get round corner radius
		if (dat->avatars_round_corners) {
			if (dat->avatars_use_custom_corner_size)
				round_radius = dat->avatars_custom_corner_size;
			else
				round_radius = min(_rcWidth(prcItem), _rcHeight(prcItem)) / 5;
		}
		// draw borders
		if (dat->avatars_draw_border) {
			HBRUSH hBrush = CreateSolidBrush(dat->avatars_border_color);
			HBRUSH hOldBrush = (HBRUSH)SelectObject(hdcMem, hBrush);
			HRGN rgnOutside = CreateRoundRectRgn(prcItem->left, prcItem->top, prcItem->right + 1, prcItem->bottom + 1, round_radius << 1, round_radius << 1);
			HRGN rgnInside = CreateRoundRectRgn(prcItem->left + 1, prcItem->top + 1, prcItem->right, prcItem->bottom, round_radius << 1, round_radius << 1);
			CombineRgn(rgnOutside, rgnOutside, rgnInside, RGN_DIFF);
			FillRgn(hdcMem, rgnOutside, hBrush);
			ske_SetRgnOpaque(hdcMem, rgnOutside);
			SelectObject(hdcMem, hOldBrush);
			DeleteObject(hBrush);
			DeleteObject(rgnInside);
			DeleteObject(rgnOutside);
		}

		//set clip area to clip avatars within borders
		if (dat->avatars_round_corners || dat->avatars_draw_border) {
			int k = dat->avatars_draw_border ? 1 : 0;
			rgn = CreateRoundRectRgn(prcItem->left + k, prcItem->top + k, prcItem->right + 1 - k, prcItem->bottom + 1 - k, round_radius * 2, round_radius * 2);
		}
		else rgn = CreateRectRgn(prcItem->left, prcItem->top, prcItem->right, prcItem->bottom);
		ExtSelectClipRgn(hdcMem, rgn, RGN_AND);

		// Draw avatar
		ImageArray_DrawImage(&dat->avatar_cache, Drawing->avatar_pos, hdcMem, prcItem->left, prcItem->top, blendmode);

		// Restore region
		DeleteObject(rgn);
		rgn = CreateRectRgn(row_rc->left, row_rc->top, row_rc->right, row_rc->bottom);
		SelectClipRgn(hdcMem, rgn);
		DeleteObject(rgn);
		// Draw overlays
		if (dat->avatars_draw_overlay && dat->avatars_maxheight_size >= ICON_HEIGHT + (dat->avatars_draw_border ? 2 : 0)
			&& GetContactCachedStatus(Drawing->hContact) - ID_STATUS_OFFLINE < _countof(g_pAvatarOverlayIcons)) {
			POINT ptOverlay = { prcItem->right - ICON_HEIGHT, prcItem->bottom - ICON_HEIGHT };
			if (dat->avatars_draw_border) {
				ptOverlay.x--;
				ptOverlay.y--;
			}
			switch (dat->avatars_overlay_type) {
			case SETTING_AVATAR_OVERLAY_TYPE_NORMAL:
				ske_ImageList_DrawEx(hAvatarOverlays, g_pAvatarOverlayIcons[GetContactCachedStatus(Drawing->hContact) - ID_STATUS_OFFLINE].listID,
					hdcMem,
					ptOverlay.x, ptOverlay.y, ICON_HEIGHT, ICON_HEIGHT,
					CLR_NONE, CLR_NONE,
					(blendmode == 255) ? ILD_NORMAL : (blendmode == 128) ? ILD_BLEND50 : ILD_BLEND25);
				break;
			case SETTING_AVATAR_OVERLAY_TYPE_PROTOCOL:
				{
					int item = pcli->pfnIconFromStatusMode(Drawing->proto, Drawing->proto == NULL ? ID_STATUS_OFFLINE : GetContactCachedStatus(Drawing->hContact), Drawing->hContact);
					if (item != -1)
						_DrawStatusIcon(Drawing, dat, item, hdcMem,
						ptOverlay.x, ptOverlay.y, ICON_HEIGHT, ICON_HEIGHT,
						CLR_NONE, CLR_NONE, (blendmode == 255) ? ILD_NORMAL : (blendmode == 128) ? ILD_BLEND50 : ILD_BLEND25);
				}
				break;
			case SETTING_AVATAR_OVERLAY_TYPE_CONTACT:
				if (Drawing->iImage != -1)
					_DrawStatusIcon(Drawing, dat, Drawing->iImage, hdcMem,
					ptOverlay.x, ptOverlay.y, ICON_HEIGHT, ICON_HEIGHT,
					CLR_NONE, CLR_NONE, (blendmode == 255) ? ILD_NORMAL : (blendmode == 128) ? ILD_BLEND50 : ILD_BLEND25);
				break;
			}
		}
	}
}

void CLCPaint::_DrawContactIcon(HDC hdcMem, ClcData *dat, ClcContact *Drawing, int& selected, int& hottrack, RECT *prcItem)
{
	// Draw Icon
	int iImage = -1;
	// Get image
	if (Drawing->type == CLCIT_GROUP) {
		if (!dat->row_hide_group_icon) iImage = Drawing->group->expanded ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT;
		else iImage = -1;
	}
	else if (Drawing->type == CLCIT_CONTACT)
		iImage = Drawing->iImage;

	// Has image to draw?
	if (iImage != -1) {
		COLORREF colourFg;
		int mode;
		_GetBlendMode(dat, Drawing, selected, hottrack, GIM_STATUSICON_AFFECT, &colourFg, &mode);
		_DrawStatusIcon(Drawing, dat, iImage, hdcMem,
			prcItem->left, prcItem->top,
			0, 0, CLR_NONE, colourFg, mode);
	}
}

void CLCPaint::_DrawContactText(HDC hdcMem, ClcData *dat, ClcContact *Drawing, int& selected, int& hottrack, RECT& text_rc, RECT *prcItem, UINT uTextFormat)
{
	ChangeToFont(hdcMem, dat, GetBasicFontID(Drawing), NULL);
	if (selected)
		SetTextColor(hdcMem, dat->bForceInDialog ? GetSysColor(COLOR_HIGHLIGHTTEXT) : dat->selTextColour);
	else if (hottrack || (dat->bFilterSearch && dat->szQuickSearch[0] != '\0' && Drawing->type != CLCIT_GROUP))
		_SetHotTrackColour(hdcMem, dat);

	if (Drawing->type == CLCIT_GROUP) {
		ske_DrawText(hdcMem, Drawing->szText, -1, prcItem, uTextFormat);
		if (selected && !dat->bFilterSearch) {
			SetTextColor(hdcMem, dat->quickSearchColour);
			ske_DrawText(hdcMem, Drawing->szText, (int)mir_wstrlen(dat->szQuickSearch), prcItem, uTextFormat);
		}
	}
	else if (Drawing->type == CLCIT_CONTACT) {
		SIZE text_size;
		text_size.cx = _rcWidth(prcItem);
		text_size.cy = _rcHeight(prcItem);
		uTextFormat |= DT_VCENTER;
		//get font
		_DrawTextSmiley(hdcMem, prcItem, &text_size, Drawing->szText, 0, -1, Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
		if ((dat->bFilterSearch || selected) && dat->szQuickSearch[0] != '\0') {
			int idx = 0;
			if (dat->bFilterSearch) {
				wchar_t *lowered = CharLowerW(NEWWSTR_ALLOCA(Drawing->szText));
				wchar_t *lowered_search = CharLowerW(NEWWSTR_ALLOCA(dat->szQuickSearch));
				wchar_t *p1 = wcsstr(lowered, lowered_search);
				if (p1)
					idx = int(p1 - lowered);
			}
			SetTextColor(hdcMem, dat->quickSearchColour);
			_DrawTextSmiley(hdcMem, prcItem, &text_size, Drawing->szText, idx, (int)mir_wstrlen(dat->szQuickSearch), Drawing->ssText.plText, uTextFormat, dat->text_resize_smileys);
		}
	}
	else ske_DrawText(hdcMem, Drawing->szText, -1, prcItem, uTextFormat);

	text_rc.right = max(text_rc.right, prcItem->right);
	text_rc.left = min(text_rc.left, prcItem->left);
}

void CLCPaint::_DrawContactSubText(HDC hdcMem, ClcData *dat, ClcContact *Drawing, int& selected, int& hottrack, RECT& text_rc, RECT *prcItem, UINT uTextFormat, BYTE itemType)
{
	if (Drawing->type == CLCIT_GROUP) {
		wchar_t *szCounts = pcli->pfnGetGroupCountsText(dat, Drawing);

		// Has to draw the count?
		if (szCounts && szCounts[0]) {
			ChangeToFont(hdcMem, dat, Drawing->group->expanded ? FONTID_OPENGROUPCOUNTS : FONTID_CLOSEDGROUPCOUNTS, NULL);
			if (selected)
				SetTextColor(hdcMem, dat->selTextColour);
			else if (hottrack)
				_SetHotTrackColour(hdcMem, dat);
			ske_DrawText(hdcMem, szCounts, -1, prcItem, uTextFormat);
			ske_ResetTextEffect(hdcMem);
		}
	}
	else if (Drawing->type == CLCIT_CONTACT) {
		ClcCacheEntry *pdnce = Drawing->pce;
		SIZE text_size = { _rcWidth(prcItem), _rcHeight(prcItem) };
		ChangeToFont(hdcMem, dat, itemType == CIT_SUBTEXT1 ? FONTID_SECONDLINE : FONTID_THIRDLINE, NULL);
		//draw second and third line
		if (selected)
			SetTextColor(hdcMem, dat->selTextColour);
		else if (hottrack)
			_SetHotTrackColour(hdcMem, dat);
		uTextFormat |= DT_VCENTER;
		if (itemType == CIT_SUBTEXT1)
			_DrawTextSmiley(hdcMem, prcItem, &text_size, pdnce->szSecondLineText, 0, -1, pdnce->ssSecondLine.plText, uTextFormat, dat->text_resize_smileys);
		else
			_DrawTextSmiley(hdcMem, prcItem, &text_size, pdnce->szThirdLineText, 0, -1, pdnce->ssThirdLine.plText, uTextFormat, dat->text_resize_smileys);
	}
	text_rc.right = max(text_rc.right, prcItem->right);
	text_rc.left = min(text_rc.left, prcItem->left);
}

void CLCPaint::_DrawContactTime(HDC hdcMem, ClcData *dat, ClcContact *Drawing, RECT *prcItem)
{
	wchar_t szResult[80];
	ClcCacheEntry *pdnce = Drawing->pce;
	if (!pdnce)
		return;

	if (!TimeZone_PrintDateTime(pdnce->hTimeZone, L"t", szResult, _countof(szResult), 0)) {
		// Select font
		ChangeToFont(hdcMem, dat, FONTID_CONTACT_TIME, NULL);
		ske_DrawText(hdcMem, szResult, (int)mir_wstrlen(szResult), prcItem, DT_NOPREFIX | DT_SINGLELINE);
	}
}

void CLCPaint::_DrawContactSelection(HDC hdcMem, ClcData *dat, int& selected, int& hottrack, RECT *rcPaint, RECT *prcItem)
{
	// Selection background
	if ((selected || hottrack) && dat->HiLightMode == 0) {
		if (selected)
			SkinDrawGlyph(hdcMem, prcItem, rcPaint, "Contact List/Selection");
		else if (hottrack)
			SkinDrawGlyph(hdcMem, prcItem, rcPaint, "Contact List/HotTracking");
	}
}

void CLCPaint::_DrawContactExtraIcon(HDC hdcMem, ClcData *dat, ClcContact *Drawing, int& selected, int& hottrack, RECT *rc, int iImage)
{
	//Draw extra icon
	if (iImage != -1) {
		int mode;
		COLORREF colourFg;
		_GetBlendMode(dat, Drawing, selected, hottrack, GIM_EXTRAICON_AFFECT, &colourFg, &mode);
		if (Drawing->iExtraImage[iImage] != EMPTY_EXTRA_ICON)
			ske_ImageList_DrawEx(dat->himlExtraColumns, Drawing->iExtraImage[iImage], hdcMem,
			rc->left, rc->top, 0, 0, CLR_NONE, colourFg, mode);
	}
}

void CLCPaint::_DrawContactLine(HDC hdcMem, ClcContact *Drawing, RECT *free_row_rc, RECT *rcPaint, RECT& text_rc)
{   //draw line
	RECT rc1 = *free_row_rc;
	RECT rc2 = *free_row_rc;
	rc1.right = text_rc.left - 3;
	rc2.left = text_rc.right + 3;
	rc1.top += (rc1.bottom - rc1.top) >> 1;
	rc1.bottom = rc1.top + 2;
	rc2.top += (rc2.bottom - rc2.top) >> 1;
	rc2.bottom = rc2.top + 2;
	{
		RECT rcTemp = rc1;
		IntersectRect(&rc1, &rcTemp, rcPaint);
	}
	{	//Subtract icon rect from left and right.
		RECT rcTemp;
		IntersectRect(&rcTemp, &Drawing->pos_icon, &rc1);
		if (!IsRectEmpty(&rcTemp)) rc1.right = rcTemp.left;
		IntersectRect(&rcTemp, &Drawing->pos_icon, &rc2);
		if (!IsRectEmpty(&rcTemp)) rc2.left = rcTemp.right;
	}

	if (rc1.right - rc1.left >= 6 && !IsRectEmpty(&rc1)) {
		DrawEdge(hdcMem, &rc1, BDR_SUNKENOUTER, BF_RECT);
		ske_SetRectOpaque(hdcMem, &rc1);
	}
	{
		RECT rcTemp = rc2;
		IntersectRect(&rc2, &rcTemp, rcPaint);
	}
	if (rc2.right - rc2.left >= 6 && !IsRectEmpty(&rc2)) {
		DrawEdge(hdcMem, &rc2, BDR_SUNKENOUTER, BF_RECT);
		ske_SetRectOpaque(hdcMem, &rc2);
	}
}

void CLCPaint::_DrawContactItems(HDC hdcMem, ClcData *dat, ClcContact *Drawing, RECT *row_rc, RECT *free_row_rc, int selected, int hottrack, RECT *rcPaint)
{
	UINT uTextFormat = DT_NOPREFIX |
		/*DT_VCENTER |*/
		DT_SINGLELINE |
		(dat->text_rtl ? DT_RTLREADING : 0) |
		(dat->text_align_right ? DT_RIGHT : 0) |
		(gl_TrimText ? DT_END_ELLIPSIS : 0) |
		((dat->bForceInDialog || dat->bkChanged) ? DT_FORCENATIVERENDER : 0);

	RECT text_rc = *row_rc;

	text_rc.right = row_rc->left;
	text_rc.left = row_rc->right;

	for (int i = 0; i < Drawing->ext_nItemsNum; i++) {
		RECT *prcItem = &(Drawing->ext_mpItemsDesc[i].itemRect);
		if (__IsVisible(rcPaint, prcItem) || (Drawing->ext_mpItemsDesc[i].itemType == CIT_AVATAR && Drawing->avatar_pos == AVATAR_POS_ANIMATED)) {
			switch (Drawing->ext_mpItemsDesc[i].itemType) {
			case CIT_AVATAR:
				_DrawContactAvatar(hdcMem, dat, Drawing, row_rc, selected, hottrack, prcItem);
				break;
			case CIT_ICON:
				_DrawContactIcon(hdcMem, dat, Drawing, selected, hottrack, prcItem);
				break;
			case CIT_TEXT:
				_DrawContactText(hdcMem, dat, Drawing, selected, hottrack, text_rc, prcItem, uTextFormat);
				break;
			case CIT_SUBTEXT1:
			case CIT_SUBTEXT2:
				_DrawContactSubText(hdcMem, dat, Drawing, selected, hottrack, text_rc, prcItem, uTextFormat, Drawing->ext_mpItemsDesc[i].itemType);
				break;
			case CIT_TIME:
				_DrawContactTime(hdcMem, dat, Drawing, prcItem);
				break;
			case CIT_CHECKBOX:
				//_DrawNothing no check boxes in skinned mode
				break;
				//other here
			case CIT_SELECTION:
				_DrawContactSelection(hdcMem, dat, selected, hottrack, rcPaint, prcItem);
				break;
			default:
				if (Drawing->ext_mpItemsDesc[i].itemType&CIT_EXTRA)
					_DrawContactExtraIcon(hdcMem, dat, Drawing, selected, hottrack, prcItem, Drawing->ext_mpItemsDesc[i].itemType & 0x3F);
				break;
			}
		}
	}
	if ((Drawing->type == CLCIT_GROUP && dat->exStyle&CLS_EX_LINEWITHGROUPS)
		|| (Drawing->type == CLCIT_DIVIDER))
		_DrawContactLine(hdcMem, Drawing, free_row_rc, rcPaint, text_rc);
}

void CLCPaint::_PaintRowItems(HDC hdcMem, ClcData *dat, ClcContact *Drawing, RECT row_rc, RECT free_row_rc, int left_pos, int right_pos, int selected, int hottrack, RECT *rcPaint)
{
	// Extended LAYOUT
	if (gl_RowRoot && (dat->hWnd == pcli->hwndContactTree)) {
		_PaintRowItemsEx(hdcMem, dat, Drawing, row_rc, free_row_rc, selected, hottrack);
		ske_ResetTextEffect(hdcMem);
		return;
	}
	// END OFF Extended LAYOUT
	if (!Drawing->ext_fItemsValid) _CalcItemsPos(hdcMem, dat, Drawing, &row_rc, &free_row_rc, left_pos, right_pos, selected);
	_DrawContactItems(hdcMem, dat, Drawing, &row_rc, &free_row_rc, selected, hottrack, rcPaint);
	ske_ResetTextEffect(hdcMem);
}

/* TODO Render items

V avatar
V avatars overlays
V avatar clipping if ignore avatar height for row height calculation is set
V icon
V text
V time
V extra icons
V selection/hot
V groups and divider lines

Milestones to implement Extended row layout

-   1. Implement separate Row item position calculation and drawing
V       a. Separation of painting and positions calculation
V       b. Use Items rect array for hit test
.       c. Calculate row height via appropriate function
.       d. Invalidate row items only when needed

.   2. Implement extended row item layout
.       a. layout template parsing
.       b. calculate positions according to template
.       c. GUI to modify template
.       d. skin defined template
*/