diff options
| -rw-r--r-- | plugins/Clist_modern/src/modern_cachefuncs.cpp | 1804 | ||||
| -rw-r--r-- | plugins/Clist_modern/src/modern_clc.cpp | 3776 | ||||
| -rw-r--r-- | plugins/Clist_modern/src/modern_clcitems.cpp | 1493 | ||||
| -rw-r--r-- | plugins/Clist_modern/src/modern_row.cpp | 1523 | ||||
| -rw-r--r-- | plugins/Clist_modern/src/modern_skinbutton.cpp | 1532 | ||||
| -rw-r--r-- | plugins/Clist_modern/src/modern_skinengine.cpp | 8285 | ||||
| -rw-r--r-- | plugins/Clist_modern/src/modern_skinopt.cpp | 1136 | 
7 files changed, 9776 insertions, 9773 deletions
diff --git a/plugins/Clist_modern/src/modern_cachefuncs.cpp b/plugins/Clist_modern/src/modern_cachefuncs.cpp index 2caf524487..87fae9df20 100644 --- a/plugins/Clist_modern/src/modern_cachefuncs.cpp +++ b/plugins/Clist_modern/src/modern_cachefuncs.cpp @@ -1,900 +1,904 @@ -/*
 -
 -Miranda NG: the free IM client for Microsoft* Windows*
 -
 -Copyright (c) 2012-14 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.
 -
 -Created by Pescuma
 -Modified by FYR
 -*/
 -
 -/************************************************************************/
 -/*             Module for working with lines text and avatars           */
 -/************************************************************************/
 -
 -#include "hdr/modern_commonheaders.h"
 -#include "hdr/modern_cache_funcs.h"
 -#include "newpluginapi.h"
 -#include "./hdr/modern_gettextasync.h"
 -#include "hdr/modern_sync.h"
 -
 -typedef BOOL (* ExecuteOnAllContactsFuncPtr) (ClcContact *contact, BOOL subcontact, void *param);
 -
 -
 -/***********************************/
 -/**   Module static declarations  **/
 -/***********************************/
 -
 -/* 	   Module Static Prototypes    */
 -
 -static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size);
 -
 -static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param);
 -static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param);
 -int CLUI_SyncGetShortData(WPARAM wParam, LPARAM lParam);
 -void CListSettings_FreeCacheItemData(ClcCacheEntry *pDst);
 -void CListSettings_FreeCacheItemDataOption( ClcCacheEntry *pDst, DWORD flag );
 -/*
 - *	Get time zone for contact
 - */
 -void Cache_GetTimezone(ClcData *dat, MCONTACT hContact)
 -{
 -	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
 -	if (dat == NULL && pcli->hwndContactTree)
 -		dat = (ClcData *)GetWindowLongPtr(pcli->hwndContactTree,0);
 -
 -	if (dat && dat->hWnd == pcli->hwndContactTree) {
 -		DWORD flags = dat->contact_time_show_only_if_different ? TZF_DIFONLY : 0;
 -		pdnce->hTimeZone = tmi.createByContact(hContact, 0, flags);
 -	}
 -}
 -
 -/*
 - *	Get all lines of text
 - */
 -
 -void Cache_GetText(ClcData *dat, ClcContact *contact, BOOL forceRenew)
 -{
 -	Cache_GetFirstLineText(dat, contact);
 -	if (!dat->force_in_dialog) {
 -		ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
 -		if ((dat->second_line_show && (forceRenew || pdnce->szSecondLineText == NULL)) || (dat->third_line_show && (forceRenew || pdnce->szThirdLineText == NULL)))
 -			gtaAddRequest(dat,contact, contact->hContact);
 -	}
 -}
 -
 -void CSmileyString::AddListeningToIcon(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR *szText, BOOL replace_smileys)
 -{
 -	iMaxSmileyHeight = 0;
 -	DestroySmileyList();
 -
 -	if (szText == NULL) return;
 -
 -	int text_size = (int)_tcslen( szText );
 -
 -	plText = List_Create( 0, 1 );
 -
 -	// Add Icon
 -	{
 -		ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
 -		piece->type = TEXT_PIECE_TYPE_SMILEY;
 -		piece->len = 0;
 -		piece->smiley = g_hListeningToIcon;
 -		piece->smiley_width = 16;
 -		piece->smiley_height = 16;
 -
 -		ICONINFO icon;
 -		if ( GetIconInfo(piece->smiley, &icon)) {
 -			BITMAP bm;
 -			if (GetObject(icon.hbmColor, sizeof(BITMAP), &bm)) {
 -				piece->smiley_width = bm.bmWidth;
 -				piece->smiley_height = bm.bmHeight;
 -			}
 -
 -			DeleteObject(icon.hbmMask);
 -			DeleteObject(icon.hbmColor);
 -		}
 -
 -		dat->text_smiley_height = max(piece->smiley_height, dat->text_smiley_height);
 -		iMaxSmileyHeight = max(piece->smiley_height, iMaxSmileyHeight);
 -
 -		List_Insert( plText, piece, plText->realCount);
 -	}
 -
 -	// Add text
 -	{
 -		ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
 -
 -		piece->type = TEXT_PIECE_TYPE_TEXT;
 -		piece->start_pos = 0;
 -		piece->len = text_size;
 -		List_Insert( plText, piece, plText->realCount);
 -	}
 -}
 -
 -void CSmileyString::_CopySmileyList( SortedList *plInput )
 -{
 -	//	ASSERT( plText == NULL );
 -
 -	if (!plInput || plInput->realCount == 0 ) return;
 -	plText = List_Create( 0, 1 );
 -	for ( int i=0; i < plInput->realCount; i++ )
 -	{
 -		ClcContactTextPiece *pieceFrom = (ClcContactTextPiece *) plInput->items[i];
 -		if ( pieceFrom != NULL )
 -		{
 -			ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc( sizeof(ClcContactTextPiece));
 -			*piece = *pieceFrom;
 -			if ( pieceFrom->type == TEXT_PIECE_TYPE_SMILEY)
 -				piece->smiley = CopyIcon( pieceFrom->smiley );
 -			List_Insert( plText, piece, plText->realCount );
 -		}
 -	}
 -}
 -
 -void CSmileyString::DestroySmileyList()
 -{
 -	//ASSERT( plText == NULL );
 -
 -	if ( plText == NULL ) return;
 -
 -	if ( IsBadReadPtr( plText, sizeof(SortedList))) {
 -		plText = NULL;
 -		return;
 -	}
 -
 -	if ( plText->realCount != 0 ) {
 -		for ( int i=0 ; i < plText->realCount ; i++ ) {
 -			if ( plText->items[i] != NULL ) {
 -				ClcContactTextPiece *piece = (ClcContactTextPiece *) plText->items[i];
 -
 -				if (!IsBadWritePtr(piece, sizeof(ClcContactTextPiece))) {
 -					if (piece->type == TEXT_PIECE_TYPE_SMILEY && piece->smiley != g_hListeningToIcon)
 -						DestroyIcon_protect(piece->smiley);
 -					mir_free(piece);
 -				}
 -			}
 -		}
 -		List_Destroy( plText );
 -	}
 -	mir_free(plText);
 -
 -	plText = NULL;
 -}
 -
 -/*
 -* Parsing of text for smiley
 -*/
 -
 -void CSmileyString::ReplaceSmileys(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR * szText, BOOL replace_smileys)
 -{
 -	SMADD_BATCHPARSE2 sp = {0};
 -	SMADD_BATCHPARSERES *spr;
 -
 -	int last_pos = 0;
 -	iMaxSmileyHeight = 0;
 -
 -	DestroySmileyList();
 -
 -	if (!dat->text_replace_smileys || !replace_smileys || szText == NULL)
 -		return;
 -
 -	int text_size = (int)_tcslen( szText );
 -
 -	// Call service for the first time to see if needs to be used...
 -	sp.cbSize = sizeof(sp);
 -
 -	if (dat->text_use_protocol_smileys) {
 -		sp.Protocolname = pdnce->m_cache_cszProto;
 -
 -		if (db_get_b(NULL,"CLC","Meta",SETTING_USEMETAICON_DEFAULT) != 1 && pdnce->m_cache_cszProto != NULL && strcmp(pdnce->m_cache_cszProto, META_PROTO) == 0) {
 -			MCONTACT hContact = db_mc_getMostOnline(pdnce->hContact);
 -			if (hContact != 0)
 -				sp.Protocolname = GetContactProto(hContact);
 -		}
 -	}
 -	else sp.Protocolname = "clist";
 -
 -	sp.str = szText;
 -	sp.flag = SAFL_TCHAR;
 -
 -	spr = (SMADD_BATCHPARSERES*)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp);
 -
 -	// Did not find a simley
 -	if (spr == NULL || (INT_PTR)spr == CALLSERVICE_NOTFOUND)
 -		return;
 -
 -	// Lets add smileys
 -	plText = List_Create( 0, 1 );
 -
 -	for (unsigned i=0; i < sp.numSmileys; ++i) {
 -		if (spr[i].hIcon != NULL) { // For deffective smileypacks
 -			// Add text
 -			if (spr[i].startChar - last_pos > 0) {
 -				ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
 -
 -				piece->type = TEXT_PIECE_TYPE_TEXT;
 -				piece->start_pos = last_pos ;//sp.str - text;
 -				piece->len = spr[i].startChar - last_pos;
 -				List_Insert(plText, piece, plText->realCount);
 -			}
 -
 -			// Add smiley
 -			{
 -				BITMAP bm;
 -				ICONINFO icon;
 -				ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
 -
 -				piece->type = TEXT_PIECE_TYPE_SMILEY;
 -				piece->len = spr[i].size;
 -				piece->smiley = spr[i].hIcon;
 -
 -				piece->smiley_width = 16;
 -				piece->smiley_height = 16;
 -				if (GetIconInfo(piece->smiley, &icon)) {
 -					if (GetObject(icon.hbmColor,sizeof(BITMAP),&bm)) {
 -						piece->smiley_width = bm.bmWidth;
 -						piece->smiley_height = bm.bmHeight;
 -					}
 -
 -					DeleteObject(icon.hbmMask);
 -					DeleteObject(icon.hbmColor);
 -				}
 -
 -				dat->text_smiley_height = max( piece->smiley_height, dat->text_smiley_height );
 -				iMaxSmileyHeight = max( piece->smiley_height, iMaxSmileyHeight );
 -
 -				List_Insert(plText, piece, plText->realCount);
 -			}
 -		}
 -		// Get next
 -		last_pos = spr[i].startChar + spr[i].size;
 -	}
 -	CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)spr);
 -
 -	// Add rest of text
 -	if (last_pos < text_size) {
 -		ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
 -
 -		piece->type = TEXT_PIECE_TYPE_TEXT;
 -		piece->start_pos = last_pos;
 -		piece->len = text_size-last_pos;
 -
 -		List_Insert(plText, piece, plText->realCount);
 -	}
 -}
 -
 -/*
 -*	Getting Status name
 -*  -1 for XStatus, 1 for Status
 -*/
 -int GetStatusName(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority)
 -{
 -	BOOL noAwayMsg = FALSE;
 -	BOOL noXstatus = FALSE;
 -	// Hide status text if Offline  /// no offline
 -	WORD nStatus = pdnce___GetStatus(pdnce);
 -	if ((nStatus == ID_STATUS_OFFLINE || nStatus == 0) && g_CluiData.bRemoveAwayMessageForOffline) noAwayMsg = TRUE;
 -	if (nStatus == ID_STATUS_OFFLINE || nStatus == 0) noXstatus = TRUE;
 -	text[0] = '\0';
 -	// Get XStatusName
 -	if (!noAwayMsg && !noXstatus &&  xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
 -		DBVARIANT dbv = { 0 };
 -		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
 -			//lstrcpyn(text, dbv.pszVal, text_size);
 -			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
 -			db_free(&dbv);
 -
 -			if (text[0] != '\0')
 -				return -1;
 -		}
 -	}
 -
 -	// Get Status name
 -	TCHAR *tmp = pcli->pfnGetStatusModeDescription(nStatus, 0);
 -	if (tmp && *tmp) {
 -		_tcsncpy_s(text, text_size, tmp, _TRUNCATE);
 -		return 1;
 -	}
 -
 -	// Get XStatusName
 -	if (!noAwayMsg && !noXstatus && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
 -		DBVARIANT dbv = { 0 };
 -		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
 -			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
 -			db_free(&dbv);
 -
 -			if (text[0] != '\0')
 -				return -1;
 -		}
 -	}
 -
 -	return 1;
 -}
 -
 -/*
 -* Get Listening to information
 -*/
 -
 -void GetListeningTo(TCHAR *text, int text_size, ClcCacheEntry *pdnce)
 -{
 -	DBVARIANT dbv = { 0 };
 -	WORD wStatus = pdnce___GetStatus(pdnce);
 -	text[0] = _T('\0');
 -
 -	if (wStatus == ID_STATUS_OFFLINE || wStatus == 0)
 -		return;
 -
 -	if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "ListeningTo", &dbv)) {
 -		CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
 -		db_free(&dbv);
 -	}
 -}
 -
 -/*
 -*	Getting Status message (Away message)
 -*  -1 for XStatus, 1 for Status
 -*/
 -
 -int GetStatusMessage(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority)
 -{
 -	DBVARIANT dbv = { 0 };
 -	BOOL noAwayMsg = FALSE;
 -	WORD wStatus = pdnce___GetStatus(pdnce);
 -	text[0] = '\0';
 -	// Hide status text if Offline  /// no offline
 -
 -	if (wStatus == ID_STATUS_OFFLINE || wStatus == 0) noAwayMsg = TRUE;
 -	// Get XStatusMsg
 -	if (!noAwayMsg  && xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
 -		// Try to get XStatusMsg
 -		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
 -			//lstrcpyn(text, dbv.pszVal, text_size);
 -			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
 -			db_free(&dbv);
 -
 -			if (text[0] != '\0')
 -				return -1;
 -		}
 -	}
 -
 -	// Get StatusMsg
 -	if (pdnce->hContact && text[0] == '\0') {
 -		if (!db_get_ts(pdnce->hContact, "CList", "StatusMsg", &dbv)) {
 -			//lstrcpyn(text, dbv.pszVal, text_size);
 -			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
 -			db_free(&dbv);
 -
 -			if (text[0] != '\0')
 -				return 1;
 -		}
 -	}
 -
 -	// Get XStatusMsg
 -	if (!noAwayMsg && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto && text[0] == '\0') {
 -		// Try to get XStatusMsg
 -		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
 -			//lstrcpyn(text, dbv.pszVal, text_size);
 -			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
 -			db_free(&dbv);
 -
 -			if (text[0] != '\0')
 -				return -1;
 -		}
 -	}
 -
 -	return 1;
 -}
 -
 -
 -/*
 -*	Get the text for specified lines
 -*/
 -int Cache_GetLineText(
 -	ClcCacheEntry *pdnce, int type, LPTSTR text, int text_size, TCHAR *variable_text, BOOL xstatus_has_priority,
 -	BOOL show_status_if_no_away, BOOL show_listening_if_no_away, BOOL use_name_and_message_for_xstatus,
 -	BOOL pdnce_time_show_only_if_different)
 -{
 -	text[0] = '\0';
 -	switch(type) {
 -	case TEXT_STATUS:
 -		if (GetStatusName(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) {
 -			DBVARIANT dbv = {0};
 -
 -			// Try to get XStatusMsg
 -			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
 -				if (dbv.ptszVal != NULL && dbv.ptszVal[0] != 0) {
 -					TCHAR *tmp = NEWTSTR_ALLOCA(text);
 -					mir_sntprintf(text, text_size, _T("%s: %s"), tmp, dbv.ptszVal);
 -					CopySkipUnprintableChars(text, text, text_size-1);
 -				}
 -				db_free(&dbv);
 -			}
 -		}
 -
 -		return TEXT_STATUS;
 -
 -	case TEXT_NICKNAME:
 -		if (pdnce->hContact && pdnce->m_cache_cszProto) {
 -			DBVARIANT dbv = {0};
 -			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) {
 -				lstrcpyn(text, dbv.ptszVal, text_size);
 -				db_free(&dbv);
 -				CopySkipUnprintableChars(text, text, text_size-1);
 -			}
 -		}
 -
 -		return TEXT_NICKNAME;
 -
 -	case TEXT_STATUS_MESSAGE:
 -		if (GetStatusMessage(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) {
 -			DBVARIANT dbv = {0};
 -
 -			// Try to get XStatusName
 -			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
 -				if (dbv.pszVal != NULL && dbv.pszVal[0] != 0) {
 -					TCHAR *tmp = NEWTSTR_ALLOCA(text);
 -					mir_sntprintf(text, text_size, _T("%s: %s"), dbv.pszVal, tmp);
 -				}
 -				CopySkipUnprintableChars(text, text, text_size-1);
 -				db_free(&dbv);
 -			}
 -		}
 -		else if (use_name_and_message_for_xstatus && xstatus_has_priority) {
 -			DBVARIANT dbv = {0};
 -			// Try to get XStatusName
 -			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
 -				if (dbv.pszVal != NULL && dbv.pszVal[0] != 0)
 -					mir_sntprintf(text, text_size, _T("%s"), dbv.pszVal);
 -				CopySkipUnprintableChars(text, text, text_size-1);
 -				db_free(&dbv);
 -			}
 -		}
 -
 -		if (text[0] == '\0') {
 -			if (show_listening_if_no_away) {
 -				Cache_GetLineText(pdnce, TEXT_LISTENING_TO, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different);
 -				if (text[0] != '\0')
 -					return TEXT_LISTENING_TO;
 -			}
 -
 -			if (show_status_if_no_away) {
 -				//re-request status if no away
 -				return Cache_GetLineText(pdnce, TEXT_STATUS, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different);
 -			}
 -		}
 -		return TEXT_STATUS_MESSAGE;
 -
 -	case TEXT_LISTENING_TO:
 -		GetListeningTo(text, text_size, pdnce);
 -		return TEXT_LISTENING_TO;
 -
 -	case TEXT_TEXT:
 -		{
 -			TCHAR *tmp = variables_parsedup(variable_text, pdnce->tszName, pdnce->hContact);
 -			lstrcpyn(text, tmp, text_size);
 -			mir_free(tmp);
 -			CopySkipUnprintableChars(text, text, text_size-1);
 -		}
 -		return TEXT_TEXT;
 -
 -	case TEXT_CONTACT_TIME:
 -		if (pdnce->hTimeZone) {
 -			// Get pdnce time
 -			text[0] = 0;
 -			tmi.printDateTime( pdnce->hTimeZone, _T("t"), text, text_size, 0);
 -		}
 -
 -		return TEXT_CONTACT_TIME;
 -	}
 -
 -	return TEXT_EMPTY;
 -}
 -
 -/*
 -*	Get the text for First Line
 -*/
 -void Cache_GetFirstLineText(ClcData *dat, ClcContact *contact)
 -{
 -	if (GetCurrentThreadId() != g_dwMainThreadID)
 -		return;
 -
 -	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
 -	TCHAR *name = pcli->pfnGetContactDisplayName(contact->hContact, 0);
 -	if (dat->first_line_append_nick && (!dat->force_in_dialog)) {
 -		DBVARIANT dbv = { 0 };
 -		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) {
 -			TCHAR nick[SIZEOF(contact->szText)];
 -			lstrcpyn(nick, dbv.ptszVal, SIZEOF(contact->szText));
 -			db_free(&dbv);
 -
 -			// They are the same -> use the name to keep the case
 -			if (_tcsicmp(name, nick) == 0)
 -				lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
 -			else
 -				// Append then
 -				mir_sntprintf(contact->szText, SIZEOF(contact->szText), _T("%s - %s"), name, nick);
 -		}
 -		else lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
 -	}
 -	else lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
 -
 -	if (!dat->force_in_dialog) {
 -		struct SHORTDATA data = { 0 };
 -		Sync(CLUI_SyncGetShortData, (WPARAM)pcli->hwndContactTree, (LPARAM)&data);
 -		contact->ssText.ReplaceSmileys(&data, pdnce, contact->szText, dat->first_line_draw_smileys);
 -	}
 -}
 -
 -/*
 -*	Get the text for Second Line
 -*/
 -
 -void Cache_GetSecondLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce)
 -{
 -	TCHAR Text[240-EXTRA_ICON_COUNT] = {0};
 -	int type = TEXT_EMPTY;
 -
 -	if (dat->second_line_show)
 -		type = Cache_GetLineText(pdnce, dat->second_line_type, (TCHAR*)Text, SIZEOF(Text), dat->second_line_text,
 -		dat->second_line_xstatus_has_priority,dat->second_line_show_status_if_no_away,dat->second_line_show_listening_if_no_away,
 -		dat->second_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different);
 -	Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string
 -
 -	mir_free(pdnce->szSecondLineText);
 -
 -	if (dat->second_line_show)// Text[0] != '\0')
 -		pdnce->szSecondLineText = mir_tstrdup((TCHAR*)Text);
 -	else
 -		pdnce->szSecondLineText = NULL;
 -
 -	if (pdnce->szSecondLineText) {
 -		if (type == TEXT_LISTENING_TO && pdnce->szSecondLineText[0] != _T('\0'))
 -			pdnce->ssSecondLine.AddListeningToIcon(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys);
 -		else
 -			pdnce->ssSecondLine.ReplaceSmileys(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys);
 -	}
 -}
 -
 -/*
 -*	Get the text for Third Line
 -*/
 -void Cache_GetThirdLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce)
 -{
 -	TCHAR Text[240-EXTRA_ICON_COUNT] = {0};
 -	int type = TEXT_EMPTY;
 -	if (dat->third_line_show)
 -		type = Cache_GetLineText(pdnce, dat->third_line_type,(TCHAR*)Text, SIZEOF(Text), dat->third_line_text,
 -		dat->third_line_xstatus_has_priority,dat->third_line_show_status_if_no_away,dat->third_line_show_listening_if_no_away,
 -		dat->third_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different);
 -
 -	Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string
 -
 -	mir_free(pdnce->szThirdLineText);
 -
 -	if (dat->third_line_show)//Text[0] != '\0')
 -		pdnce->szThirdLineText = mir_tstrdup((TCHAR*)Text);
 -	else
 -		pdnce->szThirdLineText = NULL;
 -
 -	if (pdnce->szThirdLineText) {
 -		if (type == TEXT_LISTENING_TO && pdnce->szThirdLineText[0] != _T('\0'))
 -			pdnce->ssThirdLine.AddListeningToIcon(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys);
 -		else
 -			pdnce->ssThirdLine.ReplaceSmileys(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys);
 -	}
 -}
 -
 -void RemoveTag(TCHAR *to, TCHAR *tag)
 -{
 -	TCHAR *st = to;
 -	int len = (int)_tcslen(tag);
 -	int lastsize = (int)_tcslen(to)+1;
 -	while (st = _tcsstr(st,tag)) {
 -		lastsize -= len;
 -		memmove((void*)st,(void*)(st+len),(lastsize)*sizeof(TCHAR));
 -	}
 -}
 -
 -/*
 -*	Copy string with removing Escape chars from text
 -*   And BBcodes
 -*/
 -static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size)
 -{
 -	DWORD i;
 -	BOOL keep = 0;
 -	TCHAR * cp = to;
 -	if (!to) return 0;
 -	if (!buf) {
 -		to[0] = '\0';
 -		return 0;
 -	}
 -
 -	for (i=0; i < size; i++) {
 -		if (buf[i] == 0) break;
 -		if (buf[i] > 0 && buf[i] < ' ') {
 -			*cp = ' ';
 -			if (!keep) cp++;
 -			keep = 1;
 -		}
 -		else {
 -			keep = 0;
 -			*cp = buf[i];
 -			cp++;
 -		}
 -	}
 -	*cp = 0;
 -
 -	//remove bbcodes: [b] [i] [u]  <b> <i> <u>
 -	RemoveTag(to,_T("[b]")); RemoveTag(to,_T("[/b]"));
 -	RemoveTag(to,_T("[u]")); RemoveTag(to,_T("[/u]"));
 -	RemoveTag(to,_T("[i]")); RemoveTag(to,_T("[/i]"));
 -
 -	RemoveTag(to,_T("<b>")); RemoveTag(to,_T("</b>"));
 -	RemoveTag(to,_T("<u>")); RemoveTag(to,_T("</u>"));
 -	RemoveTag(to,_T("<i>")); RemoveTag(to,_T("</i>"));
 -
 -	RemoveTag(to,_T("[B]")); RemoveTag(to,_T("[/b]"));
 -	RemoveTag(to,_T("[U]")); RemoveTag(to,_T("[/u]"));
 -	RemoveTag(to,_T("[I]")); RemoveTag(to,_T("[/i]"));
 -
 -	RemoveTag(to,_T("<B>")); RemoveTag(to,_T("</B>"));
 -	RemoveTag(to,_T("<U>")); RemoveTag(to,_T("</U>"));
 -	RemoveTag(to,_T("<I>")); RemoveTag(to,_T("</I>"));
 -	return i;
 -}
 -
 -// If ExecuteOnAllContactsFuncPtr returns FALSE, stop loop
 -// Return TRUE if finished, FALSE if was stoped
 -static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param)
 -{
 -	BOOL res;
 -	res = ExecuteOnAllContactsOfGroup(&dat->list, func, param);
 -	return res;
 -}
 -
 -static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param)
 -{
 -	if (!group)
 -		return TRUE;
 -
 -	for (int scanIndex = 0 ; scanIndex < group->cl.count ; scanIndex++) {
 -		if (group->cl.items[scanIndex]->type == CLCIT_CONTACT) {
 -			if (!func(group->cl.items[scanIndex], FALSE, param))
 -				return FALSE;
 -
 -			if (group->cl.items[scanIndex]->SubAllocated > 0) {
 -				for (int i=0 ; i < group->cl.items[scanIndex]->SubAllocated ; i++)
 -					if (!func(&group->cl.items[scanIndex]->subcontacts[i], TRUE, param))
 -						return FALSE;
 -		}
 -		}
 -		else if (group->cl.items[scanIndex]->type == CLCIT_GROUP)
 -			if (!ExecuteOnAllContactsOfGroup(group->cl.items[scanIndex]->group, func, param))
 -				return FALSE;
 -	}
 -
 -	return TRUE;
 -}
 -
 -
 -/*
 -*	Avatar working routines
 -*/
 -BOOL UpdateAllAvatarsProxy(ClcContact *contact, BOOL subcontact, void *param)
 -{
 -	Cache_GetAvatar((ClcData *)param, contact);
 -	return TRUE;
 -}
 -
 -void UpdateAllAvatars(ClcData *dat)
 -{
 -	ExecuteOnAllContacts(dat,UpdateAllAvatarsProxy,dat);
 -}
 -
 -BOOL ReduceAvatarPosition(ClcContact *contact, BOOL subcontact, void *param)
 -{
 -	if (contact->avatar_pos >= *((int *)param))
 -		contact->avatar_pos--;
 -
 -	return TRUE;
 -}
 -
 -void Cache_ProceedAvatarInList(ClcData *dat, ClcContact *contact)
 -{
 -	struct avatarCacheEntry * ace = contact->avatar_data;
 -	int old_pos = contact->avatar_pos;
 -
 -	if (ace == NULL || ace->dwFlags == AVS_BITMAP_EXPIRED || ace->hbmPic == NULL) {
 -		//Avatar was not ready or removed - need to remove it from cache
 -		if (old_pos >= 0) {
 -			ImageArray_RemoveImage(&dat->avatar_cache, old_pos);
 -			// Update all items
 -			ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos);
 -			contact->avatar_pos = AVATAR_POS_DONT_HAVE;
 -			return;
 -		}
 -	}
 -	else if (contact->avatar_data->hbmPic != NULL) //Lets Add it
 -	{
 -		// Make bounds -> keep aspect radio
 -		LONG width_clip;
 -		LONG height_clip;
 -		RECT rc = {0};
 -
 -		// Clipping width and height
 -		width_clip = dat->avatars_maxwidth_size?dat->avatars_maxwidth_size:dat->avatars_maxheight_size;
 -		height_clip = dat->avatars_maxheight_size;
 -
 -		if (height_clip * ace->bmWidth / ace->bmHeight <= width_clip)
 -			width_clip = height_clip * ace->bmWidth / ace->bmHeight;
 -		else
 -			height_clip = width_clip * ace->bmHeight / ace->bmWidth;
 -
 -		if (wildcmpit(contact->avatar_data->szFilename,_T("*.gif"))) {
 -			if (old_pos == AVATAR_POS_ANIMATED)
 -				AniAva_RemoveAvatar(contact->hContact);
 -
 -			int res = AniAva_AddAvatar(contact->hContact, contact->avatar_data->szFilename, width_clip, height_clip);
 -			if (res) {
 -				contact->avatar_pos = AVATAR_POS_ANIMATED;
 -				contact->avatar_size.cy = HIWORD(res);
 -				contact->avatar_size.cx = LOWORD(res);
 -				return;
 -			}
 -		}
 -
 -		// Create objs
 -		void * pt;
 -		HDC hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
 -		HBITMAP hDrawBmp = ske_CreateDIB32Point(width_clip, height_clip,&pt);
 -		HBITMAP oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
 -		//need to draw avatar bitmap here
 -		{
 -			RECT real_rc = {0, 0, width_clip, height_clip};
 -
 -			int w = width_clip;
 -			int h = height_clip;
 -			DrawAvatarImageWithGDIp(hdc, 0, 0, w, h,ace->hbmPic, 0, 0, ace->bmWidth,ace->bmHeight,ace->dwFlags,255);
 -		}
 -		SelectObject(hdc,oldBmp);
 -		DeleteDC(hdc);
 -		// Add to list
 -		if (old_pos >= 0) {
 -			ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos);
 -			contact->avatar_pos = old_pos;
 -		}
 -		else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1);
 -
 -		if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED)
 -			AniAva_RemoveAvatar(contact->hContact);
 -
 -		DeleteObject(hDrawBmp);
 -	}
 -}
 -
 -void Cache_GetAvatar(ClcData *dat, ClcContact *contact)
 -{
 -	int old_pos = contact->avatar_pos;
 -	// workaround for avatar service and other wich destroys service on OK_TOEXIT
 -	if (g_CluiData.bSTATE != STATE_NORMAL || (dat->use_avatar_service && !ServiceExists(MS_AV_GETAVATARBITMAP))) {
 -		contact->avatar_pos = AVATAR_POS_DONT_HAVE;
 -		contact->avatar_data = NULL;
 -		return;
 -	}
 -
 -	if (dat->use_avatar_service && ServiceExists(MS_AV_GETAVATARBITMAP)) {
 -		if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) {
 -			contact->avatar_data = (struct avatarCacheEntry *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)contact->hContact, 0);
 -			if (contact->avatar_data == NULL || contact->avatar_data->cbSize != sizeof(struct avatarCacheEntry) || contact->avatar_data->dwFlags == AVS_BITMAP_EXPIRED)
 -				contact->avatar_data = NULL;
 -
 -			if (contact->avatar_data != NULL)
 -				contact->avatar_data->t_lastAccess = (DWORD)time(NULL);
 -		}
 -		else contact->avatar_data = NULL;
 -
 -		Cache_ProceedAvatarInList(dat, contact);
 -	}
 -	else {
 -		contact->avatar_pos = AVATAR_POS_DONT_HAVE;
 -		if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) {
 -			DBVARIANT dbv;
 -			if (!db_get_ts(contact->hContact, "ContactPhoto", "File", &dbv)) {
 -				HBITMAP hBmp = (HBITMAP) CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)dbv.ptszVal);
 -				if (hBmp != NULL) {
 -					// Make bounds
 -					BITMAP bm;
 -					if (GetObject(hBmp,sizeof(BITMAP),&bm)) {
 -						// Create data...
 -						HDC hdc;
 -						HBITMAP hDrawBmp,oldBmp;
 -
 -						// Make bounds -> keep aspect radio
 -						LONG width_clip;
 -						LONG height_clip;
 -						RECT rc = {0};
 -
 -						// Clipping width and height
 -						width_clip = dat->avatars_maxheight_size;
 -						height_clip = dat->avatars_maxheight_size;
 -
 -						if (height_clip * bm.bmWidth / bm.bmHeight <= width_clip)
 -							width_clip = height_clip * bm.bmWidth / bm.bmHeight;
 -						else
 -							height_clip = width_clip * bm.bmHeight / bm.bmWidth;
 -
 -						// Create objs
 -						hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
 -						hDrawBmp = ske_CreateDIB32(width_clip, height_clip);
 -						oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
 -						SetBkMode(hdc,TRANSPARENT);
 -
 -						POINT org;
 -						GetBrushOrgEx(hdc, &org);
 -						SetStretchBltMode(hdc, HALFTONE);
 -						SetBrushOrgEx(hdc, org.x, org.y, NULL);
 -
 -						rc.right = width_clip - 1;
 -						rc.bottom = height_clip - 1;
 -
 -						// Draw bitmap             8//8
 -						HDC dcMem = CreateCompatibleDC(hdc);
 -						HBITMAP obmp = (HBITMAP)SelectObject(dcMem, hBmp);
 -						StretchBlt(hdc, 0, 0, width_clip, height_clip,dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
 -						SelectObject(dcMem,obmp);
 -						DeleteDC(dcMem);
 -
 -						RECT rtr = {0};
 -						rtr.right = width_clip+1;
 -						rtr.bottom = height_clip+1;
 -						ske_SetRectOpaque(hdc,&rtr);
 -
 -						hDrawBmp = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
 -						SelectObject(hdc,oldBmp);
 -						DeleteDC(hdc);
 -
 -						// Add to list
 -						if (old_pos >= 0) {
 -							ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos);
 -							contact->avatar_pos = old_pos;
 -						}
 -						else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1);
 -
 -						DeleteObject(hDrawBmp);
 -					} // if (GetObject(hBmp,sizeof(BITMAP),&bm))
 -					DeleteObject(hBmp);
 -				} //if (hBmp != NULL)
 -				db_free(&dbv);
 -			}
 -		}
 -
 -		// Remove avatar if needed
 -		if (old_pos >= 0 && contact->avatar_pos == AVATAR_POS_DONT_HAVE) {
 -			ImageArray_RemoveImage(&dat->avatar_cache, old_pos);
 -			// Update all items
 -			ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos);
 -		}
 -
 -		if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED)
 -			AniAva_RemoveAvatar( contact->hContact );
 -	}
 -}
 +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 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. + +Created by Pescuma +Modified by FYR +*/ + +/************************************************************************/ +/*             Module for working with lines text and avatars           */ +/************************************************************************/ + +#include "hdr/modern_commonheaders.h" +#include "hdr/modern_cache_funcs.h" +#include "newpluginapi.h" +#include "./hdr/modern_gettextasync.h" +#include "hdr/modern_sync.h" + +typedef BOOL (* ExecuteOnAllContactsFuncPtr) (ClcContact *contact, BOOL subcontact, void *param); + + +/***********************************/ +/**   Module static declarations  **/ +/***********************************/ + +/* 	   Module Static Prototypes    */ + +static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size); + +static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param); +static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param); +int CLUI_SyncGetShortData(WPARAM wParam, LPARAM lParam); +void CListSettings_FreeCacheItemData(ClcCacheEntry *pDst); +void CListSettings_FreeCacheItemDataOption( ClcCacheEntry *pDst, DWORD flag ); +/* + *	Get time zone for contact + */ +void Cache_GetTimezone(ClcData *dat, MCONTACT hContact) +{ +	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact); +	if (dat == NULL && pcli->hwndContactTree) +		dat = (ClcData *)GetWindowLongPtr(pcli->hwndContactTree,0); + +	if (dat && dat->hWnd == pcli->hwndContactTree) { +		DWORD flags = dat->contact_time_show_only_if_different ? TZF_DIFONLY : 0; +		pdnce->hTimeZone = tmi.createByContact(hContact, 0, flags); +	} +} + +/* + *	Get all lines of text + */ + +void Cache_GetText(ClcData *dat, ClcContact *contact, BOOL forceRenew) +{ +	Cache_GetFirstLineText(dat, contact); +	if (!dat->force_in_dialog) { +		ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact); +		if ((dat->second_line_show && (forceRenew || pdnce->szSecondLineText == NULL)) || (dat->third_line_show && (forceRenew || pdnce->szThirdLineText == NULL))) +			gtaAddRequest(dat,contact, contact->hContact); +	} +} + +void CSmileyString::AddListeningToIcon(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR *szText, BOOL replace_smileys) +{ +	iMaxSmileyHeight = 0; +	DestroySmileyList(); + +	if (szText == NULL) return; + +	int text_size = (int)_tcslen( szText ); + +	plText = List_Create( 0, 1 ); + +	// Add Icon +	{ +		ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece)); +		piece->type = TEXT_PIECE_TYPE_SMILEY; +		piece->len = 0; +		piece->smiley = g_hListeningToIcon; +		piece->smiley_width = 16; +		piece->smiley_height = 16; + +		ICONINFO icon; +		if ( GetIconInfo(piece->smiley, &icon)) { +			BITMAP bm; +			if (GetObject(icon.hbmColor, sizeof(BITMAP), &bm)) { +				piece->smiley_width = bm.bmWidth; +				piece->smiley_height = bm.bmHeight; +			} + +			DeleteObject(icon.hbmMask); +			DeleteObject(icon.hbmColor); +		} + +		dat->text_smiley_height = max(piece->smiley_height, dat->text_smiley_height); +		iMaxSmileyHeight = max(piece->smiley_height, iMaxSmileyHeight); + +		List_Insert( plText, piece, plText->realCount); +	} + +	// Add text +	{ +		ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece)); + +		piece->type = TEXT_PIECE_TYPE_TEXT; +		piece->start_pos = 0; +		piece->len = text_size; +		List_Insert( plText, piece, plText->realCount); +	} +} + +void CSmileyString::_CopySmileyList( SortedList *plInput ) +{ +	//	ASSERT( plText == NULL ); + +	if (!plInput || plInput->realCount == 0 ) return; +	plText = List_Create( 0, 1 ); +	for ( int i=0; i < plInput->realCount; i++ ) +	{ +		ClcContactTextPiece *pieceFrom = (ClcContactTextPiece *) plInput->items[i]; +		if ( pieceFrom != NULL ) +		{ +			ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc( sizeof(ClcContactTextPiece)); +			*piece = *pieceFrom; +			if ( pieceFrom->type == TEXT_PIECE_TYPE_SMILEY) +				piece->smiley = CopyIcon( pieceFrom->smiley ); +			List_Insert( plText, piece, plText->realCount ); +		} +	} +} + +void CSmileyString::DestroySmileyList() +{ +	//ASSERT( plText == NULL ); + +	if ( plText == NULL ) return; + +	if ( IsBadReadPtr( plText, sizeof(SortedList))) { +		plText = NULL; +		return; +	} + +	if ( plText->realCount != 0 ) { +		for ( int i=0 ; i < plText->realCount ; i++ ) { +			if ( plText->items[i] != NULL ) { +				ClcContactTextPiece *piece = (ClcContactTextPiece *) plText->items[i]; + +				if (!IsBadWritePtr(piece, sizeof(ClcContactTextPiece))) { +					if (piece->type == TEXT_PIECE_TYPE_SMILEY && piece->smiley != g_hListeningToIcon) +						DestroyIcon_protect(piece->smiley); +					mir_free(piece); +				} +			} +		} +		List_Destroy( plText ); +	} +	mir_free(plText); + +	plText = NULL; +} + +/* +* Parsing of text for smiley +*/ + +void CSmileyString::ReplaceSmileys(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR * szText, BOOL replace_smileys) +{ +	SMADD_BATCHPARSE2 sp = {0}; +	SMADD_BATCHPARSERES *spr; + +	int last_pos = 0; +	iMaxSmileyHeight = 0; + +	DestroySmileyList(); + +	if (!dat->text_replace_smileys || !replace_smileys || szText == NULL) +		return; + +	int text_size = (int)_tcslen( szText ); + +	// Call service for the first time to see if needs to be used... +	sp.cbSize = sizeof(sp); + +	if (dat->text_use_protocol_smileys) { +		sp.Protocolname = pdnce->m_cache_cszProto; + +		if (db_get_b(NULL,"CLC","Meta",SETTING_USEMETAICON_DEFAULT) != 1 && pdnce->m_cache_cszProto != NULL && strcmp(pdnce->m_cache_cszProto, META_PROTO) == 0) { +			MCONTACT hContact = db_mc_getMostOnline(pdnce->hContact); +			if (hContact != 0) +				sp.Protocolname = GetContactProto(hContact); +		} +	} +	else sp.Protocolname = "clist"; + +	sp.str = szText; +	sp.flag = SAFL_TCHAR; + +	spr = (SMADD_BATCHPARSERES*)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp); + +	// Did not find a simley +	if (spr == NULL || (INT_PTR)spr == CALLSERVICE_NOTFOUND) +		return; + +	// Lets add smileys +	plText = List_Create( 0, 1 ); + +	for (unsigned i=0; i < sp.numSmileys; ++i) { +		if (spr[i].hIcon != NULL) { // For deffective smileypacks +			// Add text +			if (spr[i].startChar - last_pos > 0) { +				ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece)); + +				piece->type = TEXT_PIECE_TYPE_TEXT; +				piece->start_pos = last_pos ;//sp.str - text; +				piece->len = spr[i].startChar - last_pos; +				List_Insert(plText, piece, plText->realCount); +			} + +			// Add smiley +			{ +				BITMAP bm; +				ICONINFO icon; +				ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece)); + +				piece->type = TEXT_PIECE_TYPE_SMILEY; +				piece->len = spr[i].size; +				piece->smiley = spr[i].hIcon; + +				piece->smiley_width = 16; +				piece->smiley_height = 16; +				if (GetIconInfo(piece->smiley, &icon)) { +					if (GetObject(icon.hbmColor,sizeof(BITMAP),&bm)) { +						piece->smiley_width = bm.bmWidth; +						piece->smiley_height = bm.bmHeight; +					} + +					DeleteObject(icon.hbmMask); +					DeleteObject(icon.hbmColor); +				} + +				dat->text_smiley_height = max( piece->smiley_height, dat->text_smiley_height ); +				iMaxSmileyHeight = max( piece->smiley_height, iMaxSmileyHeight ); + +				List_Insert(plText, piece, plText->realCount); +			} +		} +		// Get next +		last_pos = spr[i].startChar + spr[i].size; +	} +	CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)spr); + +	// Add rest of text +	if (last_pos < text_size) { +		ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece)); + +		piece->type = TEXT_PIECE_TYPE_TEXT; +		piece->start_pos = last_pos; +		piece->len = text_size-last_pos; + +		List_Insert(plText, piece, plText->realCount); +	} +} + +/* +*	Getting Status name +*  -1 for XStatus, 1 for Status +*/ +int GetStatusName(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority) +{ +	BOOL noAwayMsg = FALSE; +	BOOL noXstatus = FALSE; +	// Hide status text if Offline  /// no offline +	WORD nStatus = pdnce___GetStatus(pdnce); +	if ((nStatus == ID_STATUS_OFFLINE || nStatus == 0) && g_CluiData.bRemoveAwayMessageForOffline) noAwayMsg = TRUE; +	if (nStatus == ID_STATUS_OFFLINE || nStatus == 0) noXstatus = TRUE; +	text[0] = '\0'; +	// Get XStatusName +	if (!noAwayMsg && !noXstatus &&  xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) { +		DBVARIANT dbv = { 0 }; +		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) { +			//lstrcpyn(text, dbv.pszVal, text_size); +			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1); +			db_free(&dbv); + +			if (text[0] != '\0') +				return -1; +		} +	} + +	// Get Status name +	TCHAR *tmp = pcli->pfnGetStatusModeDescription(nStatus, 0); +	if (tmp && *tmp) { +		_tcsncpy_s(text, text_size, tmp, _TRUNCATE); +		return 1; +	} + +	// Get XStatusName +	if (!noAwayMsg && !noXstatus && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) { +		DBVARIANT dbv = { 0 }; +		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) { +			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1); +			db_free(&dbv); + +			if (text[0] != '\0') +				return -1; +		} +	} + +	return 1; +} + +/* +* Get Listening to information +*/ + +void GetListeningTo(TCHAR *text, int text_size, ClcCacheEntry *pdnce) +{ +	DBVARIANT dbv = { 0 }; +	WORD wStatus = pdnce___GetStatus(pdnce); +	text[0] = _T('\0'); + +	if (wStatus == ID_STATUS_OFFLINE || wStatus == 0) +		return; + +	if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "ListeningTo", &dbv)) { +		CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1); +		db_free(&dbv); +	} +} + +/* +*	Getting Status message (Away message) +*  -1 for XStatus, 1 for Status +*/ + +int GetStatusMessage(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority) +{ +	DBVARIANT dbv = { 0 }; +	BOOL noAwayMsg = FALSE; +	WORD wStatus = pdnce___GetStatus(pdnce); +	text[0] = '\0'; +	// Hide status text if Offline  /// no offline + +	if (wStatus == ID_STATUS_OFFLINE || wStatus == 0) noAwayMsg = TRUE; +	// Get XStatusMsg +	if (!noAwayMsg  && xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) { +		// Try to get XStatusMsg +		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) { +			//lstrcpyn(text, dbv.pszVal, text_size); +			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1); +			db_free(&dbv); + +			if (text[0] != '\0') +				return -1; +		} +	} + +	// Get StatusMsg +	if (pdnce->hContact && text[0] == '\0') { +		if (!db_get_ts(pdnce->hContact, "CList", "StatusMsg", &dbv)) { +			//lstrcpyn(text, dbv.pszVal, text_size); +			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1); +			db_free(&dbv); + +			if (text[0] != '\0') +				return 1; +		} +	} + +	// Get XStatusMsg +	if (!noAwayMsg && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto && text[0] == '\0') { +		// Try to get XStatusMsg +		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) { +			//lstrcpyn(text, dbv.pszVal, text_size); +			CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1); +			db_free(&dbv); + +			if (text[0] != '\0') +				return -1; +		} +	} + +	return 1; +} + + +/* +*	Get the text for specified lines +*/ +int Cache_GetLineText( +	ClcCacheEntry *pdnce, int type, LPTSTR text, int text_size, TCHAR *variable_text, BOOL xstatus_has_priority, +	BOOL show_status_if_no_away, BOOL show_listening_if_no_away, BOOL use_name_and_message_for_xstatus, +	BOOL pdnce_time_show_only_if_different) +{ + +	if (text == NULL) +		return TEXT_EMPTY; +	text[0] = '\0'; + +	switch(type) { +	case TEXT_STATUS: +		if (GetStatusName(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) { +			DBVARIANT dbv = {0}; + +			// Try to get XStatusMsg +			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) { +				if (dbv.ptszVal != NULL && dbv.ptszVal[0] != 0) { +					TCHAR *tmp = NEWTSTR_ALLOCA(text); +					mir_sntprintf(text, text_size, _T("%s: %s"), tmp, dbv.ptszVal); +					CopySkipUnprintableChars(text, text, text_size-1); +				} +				db_free(&dbv); +			} +		} + +		return TEXT_STATUS; + +	case TEXT_NICKNAME: +		if (pdnce->hContact && pdnce->m_cache_cszProto) { +			DBVARIANT dbv = {0}; +			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) { +				lstrcpyn(text, dbv.ptszVal, text_size); +				db_free(&dbv); +				CopySkipUnprintableChars(text, text, text_size-1); +			} +		} + +		return TEXT_NICKNAME; + +	case TEXT_STATUS_MESSAGE: +		if (GetStatusMessage(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) { +			DBVARIANT dbv = {0}; + +			// Try to get XStatusName +			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) { +				if (dbv.pszVal != NULL && dbv.pszVal[0] != 0) { +					TCHAR *tmp = NEWTSTR_ALLOCA(text); +					mir_sntprintf(text, text_size, _T("%s: %s"), dbv.pszVal, tmp); +				} +				CopySkipUnprintableChars(text, text, text_size-1); +				db_free(&dbv); +			} +		} +		else if (use_name_and_message_for_xstatus && xstatus_has_priority) { +			DBVARIANT dbv = {0}; +			// Try to get XStatusName +			if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) { +				if (dbv.pszVal != NULL && dbv.pszVal[0] != 0) +					mir_sntprintf(text, text_size, _T("%s"), dbv.pszVal); +				CopySkipUnprintableChars(text, text, text_size-1); +				db_free(&dbv); +			} +		} + +		if (text[0] == '\0') { +			if (show_listening_if_no_away) { +				Cache_GetLineText(pdnce, TEXT_LISTENING_TO, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different); +				if (text[0] != '\0') +					return TEXT_LISTENING_TO; +			} + +			if (show_status_if_no_away) { +				//re-request status if no away +				return Cache_GetLineText(pdnce, TEXT_STATUS, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different); +			} +		} +		return TEXT_STATUS_MESSAGE; + +	case TEXT_LISTENING_TO: +		GetListeningTo(text, text_size, pdnce); +		return TEXT_LISTENING_TO; + +	case TEXT_TEXT: +		{ +			TCHAR *tmp = variables_parsedup(variable_text, pdnce->tszName, pdnce->hContact); +			lstrcpyn(text, tmp, text_size); +			mir_free(tmp); +			CopySkipUnprintableChars(text, text, text_size-1); +		} +		return TEXT_TEXT; + +	case TEXT_CONTACT_TIME: +		if (pdnce->hTimeZone) { +			// Get pdnce time +			text[0] = 0; +			tmi.printDateTime( pdnce->hTimeZone, _T("t"), text, text_size, 0); +		} + +		return TEXT_CONTACT_TIME; +	} + +	return TEXT_EMPTY; +} + +/* +*	Get the text for First Line +*/ +void Cache_GetFirstLineText(ClcData *dat, ClcContact *contact) +{ +	if (GetCurrentThreadId() != g_dwMainThreadID) +		return; + +	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact); +	TCHAR *name = pcli->pfnGetContactDisplayName(contact->hContact, 0); +	if (dat->first_line_append_nick && (!dat->force_in_dialog)) { +		DBVARIANT dbv = { 0 }; +		if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) { +			TCHAR nick[SIZEOF(contact->szText)]; +			lstrcpyn(nick, dbv.ptszVal, SIZEOF(contact->szText)); +			db_free(&dbv); + +			// They are the same -> use the name to keep the case +			if (_tcsicmp(name, nick) == 0) +				lstrcpyn(contact->szText, name, SIZEOF(contact->szText)); +			else +				// Append then +				mir_sntprintf(contact->szText, SIZEOF(contact->szText), _T("%s - %s"), name, nick); +		} +		else lstrcpyn(contact->szText, name, SIZEOF(contact->szText)); +	} +	else lstrcpyn(contact->szText, name, SIZEOF(contact->szText)); + +	if (!dat->force_in_dialog) { +		struct SHORTDATA data = { 0 }; +		Sync(CLUI_SyncGetShortData, (WPARAM)pcli->hwndContactTree, (LPARAM)&data); +		contact->ssText.ReplaceSmileys(&data, pdnce, contact->szText, dat->first_line_draw_smileys); +	} +} + +/* +*	Get the text for Second Line +*/ + +void Cache_GetSecondLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce) +{ +	TCHAR Text[240-EXTRA_ICON_COUNT] = {0}; +	int type = TEXT_EMPTY; + +	if (dat->second_line_show) +		type = Cache_GetLineText(pdnce, dat->second_line_type, (TCHAR*)Text, SIZEOF(Text), dat->second_line_text, +		dat->second_line_xstatus_has_priority,dat->second_line_show_status_if_no_away,dat->second_line_show_listening_if_no_away, +		dat->second_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different); +	Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string + +	mir_free(pdnce->szSecondLineText); + +	if (dat->second_line_show)// Text[0] != '\0') +		pdnce->szSecondLineText = mir_tstrdup((TCHAR*)Text); +	else +		pdnce->szSecondLineText = NULL; + +	if (pdnce->szSecondLineText) { +		if (type == TEXT_LISTENING_TO && pdnce->szSecondLineText[0] != _T('\0')) +			pdnce->ssSecondLine.AddListeningToIcon(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys); +		else +			pdnce->ssSecondLine.ReplaceSmileys(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys); +	} +} + +/* +*	Get the text for Third Line +*/ +void Cache_GetThirdLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce) +{ +	TCHAR Text[240-EXTRA_ICON_COUNT] = {0}; +	int type = TEXT_EMPTY; +	if (dat->third_line_show) +		type = Cache_GetLineText(pdnce, dat->third_line_type,(TCHAR*)Text, SIZEOF(Text), dat->third_line_text, +		dat->third_line_xstatus_has_priority,dat->third_line_show_status_if_no_away,dat->third_line_show_listening_if_no_away, +		dat->third_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different); + +	Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string + +	mir_free(pdnce->szThirdLineText); + +	if (dat->third_line_show)//Text[0] != '\0') +		pdnce->szThirdLineText = mir_tstrdup((TCHAR*)Text); +	else +		pdnce->szThirdLineText = NULL; + +	if (pdnce->szThirdLineText) { +		if (type == TEXT_LISTENING_TO && pdnce->szThirdLineText[0] != _T('\0')) +			pdnce->ssThirdLine.AddListeningToIcon(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys); +		else +			pdnce->ssThirdLine.ReplaceSmileys(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys); +	} +} + +void RemoveTag(TCHAR *to, TCHAR *tag) +{ +	TCHAR *st = to; +	int len = (int)_tcslen(tag); +	int lastsize = (int)_tcslen(to)+1; +	while (st = _tcsstr(st,tag)) { +		lastsize -= len; +		memmove((void*)st,(void*)(st+len),(lastsize)*sizeof(TCHAR)); +	} +} + +/* +*	Copy string with removing Escape chars from text +*   And BBcodes +*/ +static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size) +{ +	DWORD i; +	BOOL keep = 0; +	TCHAR * cp = to; +	if (!to) return 0; +	if (!buf) { +		to[0] = '\0'; +		return 0; +	} + +	for (i=0; i < size; i++) { +		if (buf[i] == 0) break; +		if (buf[i] > 0 && buf[i] < ' ') { +			*cp = ' '; +			if (!keep) cp++; +			keep = 1; +		} +		else { +			keep = 0; +			*cp = buf[i]; +			cp++; +		} +	} +	*cp = 0; + +	//remove bbcodes: [b] [i] [u]  <b> <i> <u> +	RemoveTag(to,_T("[b]")); RemoveTag(to,_T("[/b]")); +	RemoveTag(to,_T("[u]")); RemoveTag(to,_T("[/u]")); +	RemoveTag(to,_T("[i]")); RemoveTag(to,_T("[/i]")); + +	RemoveTag(to,_T("<b>")); RemoveTag(to,_T("</b>")); +	RemoveTag(to,_T("<u>")); RemoveTag(to,_T("</u>")); +	RemoveTag(to,_T("<i>")); RemoveTag(to,_T("</i>")); + +	RemoveTag(to,_T("[B]")); RemoveTag(to,_T("[/b]")); +	RemoveTag(to,_T("[U]")); RemoveTag(to,_T("[/u]")); +	RemoveTag(to,_T("[I]")); RemoveTag(to,_T("[/i]")); + +	RemoveTag(to,_T("<B>")); RemoveTag(to,_T("</B>")); +	RemoveTag(to,_T("<U>")); RemoveTag(to,_T("</U>")); +	RemoveTag(to,_T("<I>")); RemoveTag(to,_T("</I>")); +	return i; +} + +// If ExecuteOnAllContactsFuncPtr returns FALSE, stop loop +// Return TRUE if finished, FALSE if was stoped +static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param) +{ +	BOOL res; +	res = ExecuteOnAllContactsOfGroup(&dat->list, func, param); +	return res; +} + +static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param) +{ +	if (!group) +		return TRUE; + +	for (int scanIndex = 0 ; scanIndex < group->cl.count ; scanIndex++) { +		if (group->cl.items[scanIndex]->type == CLCIT_CONTACT) { +			if (!func(group->cl.items[scanIndex], FALSE, param)) +				return FALSE; + +			if (group->cl.items[scanIndex]->SubAllocated > 0) { +				for (int i=0 ; i < group->cl.items[scanIndex]->SubAllocated ; i++) +					if (!func(&group->cl.items[scanIndex]->subcontacts[i], TRUE, param)) +						return FALSE; +		} +		} +		else if (group->cl.items[scanIndex]->type == CLCIT_GROUP) +			if (!ExecuteOnAllContactsOfGroup(group->cl.items[scanIndex]->group, func, param)) +				return FALSE; +	} + +	return TRUE; +} + + +/* +*	Avatar working routines +*/ +BOOL UpdateAllAvatarsProxy(ClcContact *contact, BOOL subcontact, void *param) +{ +	Cache_GetAvatar((ClcData *)param, contact); +	return TRUE; +} + +void UpdateAllAvatars(ClcData *dat) +{ +	ExecuteOnAllContacts(dat,UpdateAllAvatarsProxy,dat); +} + +BOOL ReduceAvatarPosition(ClcContact *contact, BOOL subcontact, void *param) +{ +	if (contact->avatar_pos >= *((int *)param)) +		contact->avatar_pos--; + +	return TRUE; +} + +void Cache_ProceedAvatarInList(ClcData *dat, ClcContact *contact) +{ +	struct avatarCacheEntry * ace = contact->avatar_data; +	int old_pos = contact->avatar_pos; + +	if (ace == NULL || ace->dwFlags == AVS_BITMAP_EXPIRED || ace->hbmPic == NULL) { +		//Avatar was not ready or removed - need to remove it from cache +		if (old_pos >= 0) { +			ImageArray_RemoveImage(&dat->avatar_cache, old_pos); +			// Update all items +			ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos); +			contact->avatar_pos = AVATAR_POS_DONT_HAVE; +			return; +		} +	} +	else if (contact->avatar_data->hbmPic != NULL) //Lets Add it +	{ +		// Make bounds -> keep aspect radio +		LONG width_clip; +		LONG height_clip; +		RECT rc = {0}; + +		// Clipping width and height +		width_clip = dat->avatars_maxwidth_size?dat->avatars_maxwidth_size:dat->avatars_maxheight_size; +		height_clip = dat->avatars_maxheight_size; + +		if (height_clip * ace->bmWidth / ace->bmHeight <= width_clip) +			width_clip = height_clip * ace->bmWidth / ace->bmHeight; +		else +			height_clip = width_clip * ace->bmHeight / ace->bmWidth; + +		if (wildcmpit(contact->avatar_data->szFilename,_T("*.gif"))) { +			if (old_pos == AVATAR_POS_ANIMATED) +				AniAva_RemoveAvatar(contact->hContact); + +			int res = AniAva_AddAvatar(contact->hContact, contact->avatar_data->szFilename, width_clip, height_clip); +			if (res) { +				contact->avatar_pos = AVATAR_POS_ANIMATED; +				contact->avatar_size.cy = HIWORD(res); +				contact->avatar_size.cx = LOWORD(res); +				return; +			} +		} + +		// Create objs +		void * pt; +		HDC hdc = CreateCompatibleDC(dat->avatar_cache.hdc); +		HBITMAP hDrawBmp = ske_CreateDIB32Point(width_clip, height_clip,&pt); +		HBITMAP oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp); +		//need to draw avatar bitmap here +		{ +			RECT real_rc = {0, 0, width_clip, height_clip}; + +			int w = width_clip; +			int h = height_clip; +			DrawAvatarImageWithGDIp(hdc, 0, 0, w, h,ace->hbmPic, 0, 0, ace->bmWidth,ace->bmHeight,ace->dwFlags,255); +		} +		SelectObject(hdc,oldBmp); +		DeleteDC(hdc); +		// Add to list +		if (old_pos >= 0) { +			ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos); +			contact->avatar_pos = old_pos; +		} +		else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1); + +		if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED) +			AniAva_RemoveAvatar(contact->hContact); + +		DeleteObject(hDrawBmp); +	} +} + +void Cache_GetAvatar(ClcData *dat, ClcContact *contact) +{ +	int old_pos = contact->avatar_pos; +	// workaround for avatar service and other wich destroys service on OK_TOEXIT +	if (g_CluiData.bSTATE != STATE_NORMAL || (dat->use_avatar_service && !ServiceExists(MS_AV_GETAVATARBITMAP))) { +		contact->avatar_pos = AVATAR_POS_DONT_HAVE; +		contact->avatar_data = NULL; +		return; +	} + +	if (dat->use_avatar_service && ServiceExists(MS_AV_GETAVATARBITMAP)) { +		if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) { +			contact->avatar_data = (struct avatarCacheEntry *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)contact->hContact, 0); +			if (contact->avatar_data == NULL || contact->avatar_data->cbSize != sizeof(struct avatarCacheEntry) || contact->avatar_data->dwFlags == AVS_BITMAP_EXPIRED) +				contact->avatar_data = NULL; + +			if (contact->avatar_data != NULL) +				contact->avatar_data->t_lastAccess = (DWORD)time(NULL); +		} +		else contact->avatar_data = NULL; + +		Cache_ProceedAvatarInList(dat, contact); +	} +	else { +		contact->avatar_pos = AVATAR_POS_DONT_HAVE; +		if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) { +			DBVARIANT dbv; +			if (!db_get_ts(contact->hContact, "ContactPhoto", "File", &dbv)) { +				HBITMAP hBmp = (HBITMAP) CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)dbv.ptszVal); +				if (hBmp != NULL) { +					// Make bounds +					BITMAP bm; +					if (GetObject(hBmp,sizeof(BITMAP),&bm)) { +						// Create data... +						HDC hdc; +						HBITMAP hDrawBmp,oldBmp; + +						// Make bounds -> keep aspect radio +						LONG width_clip; +						LONG height_clip; +						RECT rc = {0}; + +						// Clipping width and height +						width_clip = dat->avatars_maxheight_size; +						height_clip = dat->avatars_maxheight_size; + +						if (height_clip * bm.bmWidth / bm.bmHeight <= width_clip) +							width_clip = height_clip * bm.bmWidth / bm.bmHeight; +						else +							height_clip = width_clip * bm.bmHeight / bm.bmWidth; + +						// Create objs +						hdc = CreateCompatibleDC(dat->avatar_cache.hdc); +						hDrawBmp = ske_CreateDIB32(width_clip, height_clip); +						oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp); +						SetBkMode(hdc,TRANSPARENT); + +						POINT org; +						GetBrushOrgEx(hdc, &org); +						SetStretchBltMode(hdc, HALFTONE); +						SetBrushOrgEx(hdc, org.x, org.y, NULL); + +						rc.right = width_clip - 1; +						rc.bottom = height_clip - 1; + +						// Draw bitmap             8//8 +						HDC dcMem = CreateCompatibleDC(hdc); +						HBITMAP obmp = (HBITMAP)SelectObject(dcMem, hBmp); +						StretchBlt(hdc, 0, 0, width_clip, height_clip,dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); +						SelectObject(dcMem,obmp); +						DeleteDC(dcMem); + +						RECT rtr = {0}; +						rtr.right = width_clip+1; +						rtr.bottom = height_clip+1; +						ske_SetRectOpaque(hdc,&rtr); + +						hDrawBmp = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP); +						SelectObject(hdc,oldBmp); +						DeleteDC(hdc); + +						// Add to list +						if (old_pos >= 0) { +							ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos); +							contact->avatar_pos = old_pos; +						} +						else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1); + +						DeleteObject(hDrawBmp); +					} // if (GetObject(hBmp,sizeof(BITMAP),&bm)) +					DeleteObject(hBmp); +				} //if (hBmp != NULL) +				db_free(&dbv); +			} +		} + +		// Remove avatar if needed +		if (old_pos >= 0 && contact->avatar_pos == AVATAR_POS_DONT_HAVE) { +			ImageArray_RemoveImage(&dat->avatar_cache, old_pos); +			// Update all items +			ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos); +		} + +		if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED) +			AniAva_RemoveAvatar( contact->hContact ); +	} +} diff --git a/plugins/Clist_modern/src/modern_clc.cpp b/plugins/Clist_modern/src/modern_clc.cpp index 1859e65e0d..3dfe676130 100644 --- a/plugins/Clist_modern/src/modern_clc.cpp +++ b/plugins/Clist_modern/src/modern_clc.cpp @@ -1,1888 +1,1888 @@ -/*
 -
 -Miranda NG: the free IM client for Microsoft* Windows*
 -
 -Copyright (c) 2012-14 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.
 -*/
 -
 -/************************************************************************/
 -/*       Module responsible for working with contact list control       */
 -/************************************************************************/
 -
 -#include "hdr/modern_commonheaders.h"
 -#include "m_skin.h"
 -#include "hdr/modern_commonprototypes.h"
 -
 -#include "hdr/modern_clc.h"
 -#include "hdr/modern_clist.h"
 -#include "hdr/modern_clcpaint.h"
 -
 -#include "m_modernopt.h"
 -
 -int ModernOptInit(WPARAM wParam, LPARAM lParam);
 -int ModernSkinOptInit(WPARAM wParam, LPARAM lParam);
 -
 -/*
 -*	Private module variables
 -*/
 -static HANDLE	hShowInfoTipEvent;
 -static POINT	HitPoint;
 -static BOOL		fMouseUpped;
 -static BYTE		IsDragToScrollMode = 0;
 -static int		StartDragPos = 0;
 -static int		StartScrollPos = 0;
 -HANDLE			hAckHook = NULL;
 -HANDLE			hAvatarChanged = NULL;
 -static BOOL		g_bSortTimerIsSet = FALSE;
 -static ClcContact *hitcontact = NULL;
 -HANDLE hSkinFolder;
 -TCHAR SkinsFolder[MAX_PATH];
 -
 -static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam);
 -static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam);
 -static int clcHookBkgndConfigChanged(WPARAM wParam, LPARAM lParam);
 -static int clcProceedDragToScroll(HWND hwnd, int Y);
 -static int clcExitDragToScroll();
 -
 -
 -int ReloadSkinFolder(WPARAM wParam, LPARAM lParam)
 -{
 -	FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER));
 -	return 0;
 -}
 -
 -static int clcHookModulesLoaded(WPARAM wParam, LPARAM lParam)
 -{
 -	if (MirandaExiting())
 -		return 0;
 -
 -	HookEvent(ME_MODERNOPT_INITIALIZE, ModernOptInit);
 -	HookEvent(ME_MODERNOPT_INITIALIZE, ModernSkinOptInit);
 -
 -	HookEvent(ME_FOLDERS_PATH_CHANGED, ReloadSkinFolder);
 -	hSkinFolder = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("Modern contact list"), MIRANDA_PATHT _T("\\") _T(DEFAULT_SKIN_FOLDER));
 -	FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER));
 -
 -	// Get icons
 -	TCHAR szMyPath[MAX_PATH];
 -	GetModuleFileName(g_hInst, szMyPath, SIZEOF(szMyPath));
 -
 -	SKINICONDESC sid = { sizeof(sid) };
 -	sid.cx = sid.cy = 16;
 -	sid.ptszDefaultFile = szMyPath;
 -	sid.flags = SIDF_PATH_TCHAR;
 -
 -	sid.pszSection = LPGEN("Contact list");
 -	sid.pszDescription = LPGEN("Listening to");
 -	sid.pszName = "LISTENING_TO_ICON";
 -	sid.iDefaultIndex = -IDI_LISTENING_TO;
 -	Skin_AddIcon(&sid);
 -
 -	sid.pszSection = LPGEN("Contact list") "/" LPGEN("Avatar overlay");
 -	for (int i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
 -		sid.pszDescription = g_pAvatarOverlayIcons[i].description;
 -		sid.pszName = g_pAvatarOverlayIcons[i].name;
 -		sid.iDefaultIndex = -g_pAvatarOverlayIcons[i].id;
 -		Skin_AddIcon(&sid);
 -	}
 -
 -	sid.pszSection = LPGEN("Contact list") "/" LPGEN("Status overlay");
 -	for (int i = 0; i < SIZEOF(g_pStatusOverlayIcons); i++) {
 -		sid.pszDescription = g_pStatusOverlayIcons[i].description;
 -		sid.pszName = g_pStatusOverlayIcons[i].name;
 -		sid.iDefaultIndex = -g_pStatusOverlayIcons[i].id;
 -		Skin_AddIcon(&sid);
 -	}
 -
 -	clcHookIconsChanged(0, 0);
 -
 -	HookEvent(ME_SKIN2_ICONSCHANGED, clcHookIconsChanged);
 -
 -	// Register smiley category
 -	if (ServiceExists(MS_SMILEYADD_REGISTERCATEGORY)) {
 -		SMADD_REGCAT rc;
 -		rc.cbSize = sizeof(rc);
 -		rc.name = "clist";
 -		rc.dispname = Translate("Contact list smileys");
 -
 -		CallService(MS_SMILEYADD_REGISTERCATEGORY, 0, (LPARAM)&rc);
 -
 -		HookEvent(ME_SMILEYADD_OPTIONSCHANGED, clcHookSmileyAddOptionsChanged);
 -	}
 -
 -	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("List background")"/CLC"), 0);
 -	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Menu background")"/Menu"), 0);
 -	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Status bar background")"/StatusBar"), 0);
 -	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Frames title bar background")"/FrameTitleBar"), 0);
 -
 -	HookEvent(ME_BACKGROUNDCONFIG_CHANGED, clcHookBkgndConfigChanged);
 -	HookEvent(ME_BACKGROUNDCONFIG_CHANGED, BgStatusBarChange);
 -	HookEvent(ME_BACKGROUNDCONFIG_CHANGED, OnFrameTitleBarBackgroundChange);
 -	HookEvent(ME_COLOUR_RELOAD, OnFrameTitleBarBackgroundChange);
 -
 -	AniAva_UpdateOptions();
 -	return 0;
 -}
 -
 -static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam)
 -{
 -	if (MirandaExiting()) return 0;
 -	pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
 -	pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0);
 -	return 0;
 -}
 -
 -static int clcHookProtoAck(WPARAM wParam, LPARAM lParam)
 -{
 -	return ClcDoProtoAck(wParam, (ACKDATA*)lParam);
 -}
 -
 -static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam)
 -{
 -	int i;
 -	if (MirandaExiting()) return 0;
 -	for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
 -		g_pAvatarOverlayIcons[i].listID = -1;
 -		g_pStatusOverlayIcons[i].listID = -1;
 -	}
 -
 -	if (hAvatarOverlays)
 -		ImageList_Destroy(hAvatarOverlays);
 -	hAvatarOverlays = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, SIZEOF(g_pAvatarOverlayIcons) * 2, 1);
 -
 -	for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
 -		HICON hIcon = Skin_GetIcon(g_pAvatarOverlayIcons[i].name);
 -		g_pAvatarOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon);
 -		Skin_ReleaseIcon(g_pAvatarOverlayIcons[i].name);
 -
 -		hIcon = Skin_GetIcon(g_pStatusOverlayIcons[i].name);
 -		g_pStatusOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon);
 -		Skin_ReleaseIcon(g_pStatusOverlayIcons[i].name);
 -	}
 -
 -	g_hListeningToIcon = Skin_GetIcon("LISTENING_TO_ICON");
 -
 -	pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0);
 -	AniAva_UpdateOptions();
 -	return 0;
 -}
 -
 -static int clcMetaModeChanged(WPARAM, LPARAM)
 -{
 -	pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0);
 -	return 0;
 -}
 -
 -static int clcMetacontactChanged(WPARAM hMeta, LPARAM)
 -{
 -	pcli->pfnClcBroadcast(INTM_NAMEORDERCHANGED, 0, 0);
 -	return 0;
 -}
 -
 -static int clcHookSettingChanged(WPARAM hContact, LPARAM lParam)
 -{
 -	if (MirandaExiting())
 -		return 0;
 -
 -	DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam;
 -	if (hContact == NULL) {
 -		if (!mir_strcmp(cws->szModule, "CListGroups"))
 -			pcli->pfnClcBroadcast(INTM_GROUPSCHANGED, hContact, lParam);
 -		else if (!strcmp(cws->szSetting, "XStatusId") || !strcmp(cws->szSetting, "XStatusName"))
 -			cliCluiProtocolStatusChanged(0, cws->szModule);
 -	}
 -	else // hContact != NULL
 -	{
 -		if (!strcmp(cws->szSetting, "TickTS"))
 -			pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0);
 -		else if (!strcmp(cws->szModule, "UserInfo")) {
 -			if (!strcmp(cws->szSetting, "Timezone"))
 -				pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0);
 -		}
 -		else if (!strcmp(cws->szModule, "CList")) {
 -			if (!strcmp(cws->szSetting, "StatusMsg"))
 -				pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
 -
 -		}
 -		else if (!strcmp(cws->szModule, "ContactPhoto")) {
 -			if (!strcmp(cws->szSetting, "File"))
 -				pcli->pfnClcBroadcast(INTM_AVATARCHANGED, hContact, 0);
 -		}
 -		else {
 -			if ((!strcmp(cws->szSetting, "XStatusName") || !strcmp(cws->szSetting, "XStatusMsg")))
 -				pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
 -			else if (!strcmp(cws->szSetting, "XStatusId"))
 -				pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0);
 -			else if (!strcmp(cws->szSetting, "Timezone"))
 -				pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0);
 -			else if (!strcmp(cws->szSetting, "ListeningTo"))
 -				pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
 -			else if (!strcmp(cws->szSetting, "Transport") || !strcmp(cws->szSetting, "IsTransported")) {
 -				pcli->pfnInvalidateDisplayNameCacheEntry(hContact);
 -				pcli->pfnClcBroadcast(CLM_AUTOREBUILD, hContact, 0);
 -			}
 -		}
 -	}
 -	return 0;
 -}
 -
 -static int clcHookDbEventAdded(WPARAM hContact, LPARAM lParam)
 -{
 -	g_CluiData.t_now = time(NULL);
 -	if (hContact && lParam) {
 -		DBEVENTINFO dbei = { sizeof(dbei) };
 -		db_event_get((HANDLE)lParam, &dbei);
 -		if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
 -			db_set_dw(hContact, "CList", "mf_lastmsg", dbei.timestamp);
 -			ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
 -			if (pdnce)
 -				pdnce->dwLastMsgTime = dbei.timestamp;
 -		}
 -	}
 -	return 0;
 -}
 -
 -static int clcHookBkgndConfigChanged(WPARAM, LPARAM)
 -{
 -	pcli->pfnClcOptionsChanged();
 -	return 0;
 -}
 -
 -static int clcHookAvatarChanged(WPARAM wParam, LPARAM lParam)
 -{
 -	if (MirandaExiting()) return 0;
 -	pcli->pfnClcBroadcast(INTM_AVATARCHANGED, wParam, lParam);
 -	return 0;
 -}
 -
 -static int clcExitDragToScroll()
 -{
 -	if (!IsDragToScrollMode) return 0;
 -	IsDragToScrollMode = 0;
 -	ReleaseCapture();
 -	return 1;
 -}
 -
 -static int clcProceedDragToScroll(HWND hwnd, int Y)
 -{
 -	int pos, dy;
 -	if (!IsDragToScrollMode) return 0;
 -	if (GetCapture() != hwnd) clcExitDragToScroll();
 -	dy = StartDragPos - Y;
 -	pos = StartScrollPos + dy;
 -	if (pos < 0)
 -		pos = 0;
 -	SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, pos), 0);
 -	return 1;
 -}
 -
 -
 -
 -static int clcSearchNextContact(HWND hwnd, ClcData *dat, int index, const TCHAR *text, int prefixOk, BOOL fSearchUp)
 -{
 -	ClcGroup *group = &dat->list;
 -	int testlen = lstrlen(text);
 -	BOOL fReturnAsFound = FALSE;
 -	int	 nLastFound = -1;
 -	if (index == -1) fReturnAsFound = TRUE;
 -	group->scanIndex = 0;
 -	for (;;) {
 -		if (group->scanIndex == group->cl.count) {
 -			group = group->parent;
 -			if (group == NULL)
 -				break;
 -			group->scanIndex++;
 -			continue;
 -		}
 -		if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) {
 -			bool found;
 -			if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
 -				found = true;
 -			}
 -			else if (dat->filterSearch) {
 -				TCHAR *lowered_szText = CharLowerW(NEWTSTR_ALLOCA(group->cl.items[group->scanIndex]->szText));
 -				TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch));
 -				found = _tcsstr(lowered_szText, lowered_search) != NULL;
 -			}
 -			else {
 -				found = ((prefixOk && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, text, -1, group->cl.items[group->scanIndex]->szText, testlen)) || (!prefixOk && !lstrcmpi(text, group->cl.items[group->scanIndex]->szText)));
 -			}
 -			if (found) {
 -				ClcGroup *contactGroup = group;
 -				int contactScanIndex = group->scanIndex;
 -				int foundindex;
 -				for (; group; group = group->parent)
 -					pcli->pfnSetGroupExpand(hwnd, dat, group, 1);
 -				foundindex = pcli->pfnGetRowsPriorTo(&dat->list, contactGroup, contactScanIndex);
 -				if (fReturnAsFound)
 -					return foundindex;
 -				else if (nLastFound != -1 && fSearchUp && foundindex == index)
 -					return nLastFound;
 -				else if (!fSearchUp && foundindex == index)
 -					fReturnAsFound = TRUE;
 -				else
 -					nLastFound = foundindex;
 -				group = contactGroup;
 -				group->scanIndex = contactScanIndex;
 -			}
 -			if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
 -				if (!(dat->exStyle & CLS_EX_QUICKSEARCHVISONLY) || group->cl.items[group->scanIndex]->group->expanded) {
 -					group = group->cl.items[group->scanIndex]->group;
 -					group->scanIndex = 0;
 -					continue;
 -				}
 -			}
 -		}
 -		group->scanIndex++;
 -	}
 -	return -1;
 -}
 -
 -static BOOL clcItemNotHiddenOffline(ClcData *dat, ClcGroup* group, ClcContact *contact)
 -{
 -	if (g_CluiData.bFilterEffective) return FALSE;
 -
 -	if (!contact) return FALSE;
 -	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
 -	if (!pdnce) return FALSE;
 -	if (pdnce->m_cache_nNoHiddenOffline) return TRUE;
 -
 -	if (!group) return FALSE;
 -	if (group->hideOffline) return FALSE;
 -
 -	if (CLCItems_IsShowOfflineGroup(group)) return TRUE;
 -
 -	return FALSE;
 -}
 -
 -static LRESULT clcOnCreate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	dat = (ClcData*)mir_calloc(sizeof(ClcData));
 -	SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat);
 -	dat->hCheckBoxTheme = xpt_AddThemeHandle(hwnd, L"BUTTON");
 -	dat->m_paintCouter = 0;
 -	dat->hWnd = hwnd;
 -	dat->use_avatar_service = ServiceExists(MS_AV_GETAVATARBITMAP);
 -	if (dat->use_avatar_service)
 -		if (!hAvatarChanged)
 -			hAvatarChanged = HookEvent(ME_AV_AVATARCHANGED, clcHookAvatarChanged);
 -
 -	ImageArray_Initialize(&dat->avatar_cache, FALSE, 20); //this array will be used to keep small avatars too
 -
 -	RowHeights_Initialize(dat);
 -
 -	dat->needsResort = 1;
 -	dat->MetaIgnoreEmptyExtra = db_get_b(NULL, "CLC", "MetaIgnoreEmptyExtra", SETTING_METAIGNOREEMPTYEXTRA_DEFAULT);
 -
 -	dat->IsMetaContactsEnabled = (!(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_MANUALUPDATE)) && db_mc_isEnabled();
 -
 -	dat->expandMeta = db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT);
 -	dat->useMetaIcon = db_get_b(NULL, "CLC", "Meta", SETTING_USEMETAICON_DEFAULT);
 -	dat->drawOverlayedStatus = db_get_b(NULL, "CLC", "DrawOverlayedStatus", SETTING_DRAWOVERLAYEDSTATUS_DEFAULT);
 -	g_CluiData.bSortByOrder[0] = db_get_b(NULL, "CList", "SortBy1", SETTING_SORTBY1_DEFAULT);
 -	g_CluiData.bSortByOrder[1] = db_get_b(NULL, "CList", "SortBy2", SETTING_SORTBY2_DEFAULT);
 -	g_CluiData.bSortByOrder[2] = db_get_b(NULL, "CList", "SortBy3", SETTING_SORTBY3_DEFAULT);
 -	g_CluiData.fSortNoOfflineBottom = db_get_b(NULL, "CList", "NoOfflineBottom", SETTING_NOOFFLINEBOTTOM_DEFAULT);
 -	dat->menuOwnerID = -1;
 -	dat->menuOwnerType = CLCIT_INVALID;
 -
 -	corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -	LoadCLCOptions(hwnd, dat, TRUE);
 -	if (dat->contact_time_show || dat->second_line_type == TEXT_CONTACT_TIME || dat->third_line_type == TEXT_CONTACT_TIME)
 -		CLUI_SafeSetTimer(hwnd, TIMERID_INVALIDATE, 5000, NULL);
 -	else
 -		KillTimer(hwnd, TIMERID_INVALIDATE);
 -
 -	TRACE("Create New ClistControl TO END\r\n");
 -	return 0;
 -}
 -
 -static LRESULT clcOnHitTest(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	return DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
 -}
 -
 -static LRESULT clcOnCommand(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	ClcContact *contact;
 -	int hit = pcli->pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
 -	if (hit == -1)	return 0;
 -	if (contact->type == CLCIT_CONTACT && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), contact->hContact))	return 0;
 -
 -	switch (LOWORD(wParam)) {
 -	case POPUP_NEWSUBGROUP:
 -		if (contact->type != CLCIT_GROUP)
 -			return 0;
 -		SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
 -		SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | CLS_USEGROUPS);
 -		CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0);
 -		return 0;
 -	case POPUP_RENAMEGROUP:
 -		pcli->pfnBeginRenameSelection(hwnd, dat);
 -		return 0;
 -	case POPUP_DELETEGROUP:
 -		if (contact->type == CLCIT_GROUP)
 -			CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0);
 -		return 0;
 -	case POPUP_GROUPSHOWOFFLINE:
 -		if (contact->type == CLCIT_GROUP) {
 -			CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(CLCItems_IsShowOfflineGroup(contact->group) ? 0 : GROUPF_SHOWOFFLINE, GROUPF_SHOWOFFLINE));
 -			pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
 -		}
 -		return 0;
 -	case POPUP_GROUPHIDEOFFLINE:
 -		if (contact->type == CLCIT_GROUP)
 -			CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE));
 -		return 0;
 -	}
 -
 -	if (contact->type == CLCIT_GROUP)
 -		if (CallService(MO_PROCESSCOMMANDBYMENUIDENT, LOWORD(wParam), (LPARAM)hwnd))
 -			return 0;
 -
 -	return 0;
 -}
 -
 -static LRESULT clcOnSize(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	pcli->pfnEndRename(hwnd, dat, 1);
 -	KillTimer(hwnd, TIMERID_INFOTIP);
 -	KillTimer(hwnd, TIMERID_RENAME);
 -	cliRecalcScrollBar(hwnd, dat);
 -	if (g_CluiData.fDisableSkinEngine || dat->force_in_dialog) {
 -		RECT rc = { 0 };
 -		GetClientRect(hwnd, &rc);
 -		if (rc.right == 0)
 -			return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -		rc.bottom = max(dat->row_min_heigh, 1);
 -
 -		HDC hdc = GetDC(hwnd);
 -		int depth = GetDeviceCaps(hdc, BITSPIXEL);
 -		if (depth < 16)
 -			depth = 16;
 -		HBITMAP hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL);
 -		HBITMAP hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL);
 -		HDC hdcMem = CreateCompatibleDC(hdc);
 -		HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp);
 -		HBRUSH hBrush = CreateSolidBrush((dat->useWindowsColours || dat->force_in_dialog) ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour);
 -		FillRect(hdcMem, &rc, hBrush);
 -		DeleteObject(hBrush);
 -
 -		HBITMAP hoMaskBmp = (HBITMAP)SelectObject(hdcMem, hBmpMask);
 -		FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
 -		SelectObject(hdcMem, hoMaskBmp);
 -		SelectObject(hdcMem, hoBmp);
 -		DeleteDC(hdcMem);
 -		ReleaseDC(hwnd, hdc);
 -		if (dat->himlHighlight)
 -			ImageList_Destroy(dat->himlHighlight);
 -		dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, ILC_COLOR32 | ILC_MASK, 1, 1);
 -		ImageList_Add(dat->himlHighlight, hBmp, hBmpMask);
 -		DeleteObject(hBmpMask);
 -		DeleteObject(hBmp);
 -	}
 -	else if (dat->himlHighlight) {
 -		ImageList_Destroy(dat->himlHighlight);
 -		dat->himlHighlight = NULL;
 -	}
 -	return 0;
 -}
 -
 -static LRESULT clcOnChar(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	if (wParam == 27 && dat->szQuickSearch[0] == '\0') { //escape and not quick search
 -		// minimize clist
 -		CListMod_HideWindow(pcli->hwndContactList, SW_HIDE);
 -	}
 -	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -}
 -static LRESULT clcOnPaint(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	if (IsWindowVisible(hwnd)) {
 -		if (!g_CluiData.fLayered || GetParent(hwnd) != pcli->hwndContactList) {
 -			PAINTSTRUCT ps;
 -			HDC hdc = BeginPaint(hwnd, &ps);
 -			g_clcPainter.cliPaintClc(hwnd, dat, hdc, &ps.rcPaint);
 -			EndPaint(hwnd, &ps);
 -		}
 -		else CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, (WPARAM)hwnd, 0);
 -	}
 -	return DefWindowProc(hwnd, msg, wParam, lParam);
 -}
 -
 -static LRESULT clcOnEraseBkGround(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	return 1;
 -}
 -
 -static LRESULT clcOnKeyDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	if (wParam == VK_CONTROL)
 -		return 0;
 -
 -	pcli->pfnHideInfoTip(hwnd, dat);
 -	KillTimer(hwnd, TIMERID_INFOTIP);
 -	KillTimer(hwnd, TIMERID_RENAME);
 -
 -	if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU))
 -		return 0;
 -
 -	RECT clRect;
 -	GetClientRect(hwnd, &clRect);
 -	int pageSize = (dat->rowHeight) ? clRect.bottom / dat->rowHeight : 0;
 -	int selMoved = 0;
 -	int changeGroupExpand = 0;
 -
 -	switch (wParam) {
 -	case VK_DOWN:
 -	case VK_UP:
 -		if (dat->szQuickSearch[0] != '\0' && dat->selection != -1) { //get next contact
 -			//get next contact
 -			int index = clcSearchNextContact(hwnd, dat, dat->selection, dat->szQuickSearch, 1, (wParam == VK_UP));
 -			if (index == -1) {
 -				MessageBeep(MB_OK);
 -				return 0;
 -			}
 -
 -			dat->selection = index;
 -			pcli->pfnInvalidateRect(hwnd, NULL, FALSE);
 -			pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
 -			return 0;
 -		}
 -
 -		if (wParam == VK_DOWN) dat->selection++;
 -		if (wParam == VK_UP) dat->selection--;
 -		selMoved = 1;
 -		break;
 -
 -	case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break;
 -	case VK_NEXT: dat->selection += pageSize; selMoved = 1; break;
 -	case VK_HOME: dat->selection = 0; selMoved = 1; break;
 -	case VK_END: dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break;
 -	case VK_LEFT: changeGroupExpand = 1; break;
 -	case VK_RIGHT: changeGroupExpand = 2; break;
 -	case VK_RETURN:
 -		pcli->pfnDoSelectionDefaultAction(hwnd, dat);
 -		SetCapture(hwnd);
 -		dat->szQuickSearch[0] = 0;
 -		if (dat->filterSearch)
 -			pcli->pfnSaveStateAndRebuildList(hwnd, dat);
 -		return 0;
 -
 -	case VK_F2: cliBeginRenameSelection(hwnd, dat); /*SetCapture(hwnd);*/ return 0;
 -	case VK_DELETE: pcli->pfnDeleteFromContactList(hwnd, dat); SetCapture(hwnd); return 0;
 -	case VK_ESCAPE:
 -		if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
 -			dat->iDragItem = -1;
 -			dat->iInsertionMark = -1;
 -			dat->dragStage = 0;
 -			ReleaseCapture();
 -		}
 -		return 0;
 -
 -	default:
 -		NMKEY nmkey;
 -		nmkey.hdr.hwndFrom = hwnd;
 -		nmkey.hdr.idFrom = GetDlgCtrlID(hwnd);
 -		nmkey.hdr.code = NM_KEYDOWN;
 -		nmkey.nVKey = wParam;
 -		nmkey.uFlags = HIWORD(lParam);
 -
 -		if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nmkey)) {
 -			SetCapture(hwnd);
 -			return 0;
 -		}
 -	}
 -
 -	if (changeGroupExpand) {
 -		ClcContact *contact;
 -		ClcGroup *group;
 -		int hit = cliGetRowByIndex(dat, dat->selection, &contact, &group);
 -		if (hit == -1) {
 -			SetCapture(hwnd);
 -			return 0;
 -		}
 -
 -		if (contact->type == CLCIT_CONTACT && (contact->isSubcontact || contact->SubAllocated > 0)) {
 -			if (contact->isSubcontact && changeGroupExpand == 1) {
 -				dat->selection -= contact->isSubcontact;
 -				selMoved = 1;
 -			}
 -			else if (!contact->isSubcontact && contact->SubAllocated > 0) {
 -				if (changeGroupExpand == 1 && !contact->SubExpanded) {
 -					dat->selection = cliGetRowsPriorTo(&dat->list, group, -1);
 -					selMoved = 1;
 -				}
 -				else if (changeGroupExpand == 1 && contact->SubExpanded) {
 -					//Contract
 -					ClcContact *ht = NULL;
 -					KillTimer(hwnd, TIMERID_SUBEXPAND);
 -					contact->SubExpanded = 0;
 -					db_set_b(contact->hContact, "CList", "Expanded", 0);
 -					ht = contact;
 -					dat->needsResort = 1;
 -					pcli->pfnSortCLC(hwnd, dat, 1);
 -					cliRecalcScrollBar(hwnd, dat);
 -					hitcontact = NULL;
 -				}
 -				else if (changeGroupExpand == 2 && contact->SubExpanded) {
 -					dat->selection++;
 -					selMoved = 1;
 -				}
 -				else if (changeGroupExpand == 2 && !contact->SubExpanded && dat->expandMeta) {
 -					ClcContact *ht = NULL;
 -					KillTimer(hwnd, TIMERID_SUBEXPAND);
 -					contact->SubExpanded = 1;
 -					db_set_b(contact->hContact, "CList", "Expanded", 1);
 -					ht = contact;
 -					dat->needsResort = 1;
 -					pcli->pfnSortCLC(hwnd, dat, 1);
 -					cliRecalcScrollBar(hwnd, dat);
 -					if (ht) {
 -						ClcContact *contact2;
 -						ClcGroup *group2;
 -						if (FindItem(hwnd, dat, contact->hContact, &contact2, &group2, NULL, FALSE)) {
 -							int i = cliGetRowsPriorTo(&dat->list, group2, GetContactIndex(group2, contact2));
 -							pcli->pfnEnsureVisible(hwnd, dat, i + contact->SubAllocated, 0);
 -						}
 -					}
 -					hitcontact = NULL;
 -				}
 -			}
 -		}
 -		else {
 -			if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) {
 -				if (group == &dat->list) { SetCapture(hwnd); return 0; }
 -				dat->selection = cliGetRowsPriorTo(&dat->list, group, -1);
 -				selMoved = 1;
 -			}
 -			else {
 -				if (contact->type == CLCIT_GROUP) {
 -					if (changeGroupExpand == 1) {
 -						if (!contact->group->expanded) {
 -							dat->selection--;
 -							selMoved = 1;
 -						}
 -						else pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 0);
 -					}
 -					else if (changeGroupExpand == 2) {
 -						pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 1);
 -						dat->selection++;
 -						selMoved = 1;
 -					}
 -					else { SetCapture(hwnd); return 0; }
 -				}
 -			}
 -		}
 -	}
 -	if (selMoved) {
 -		if (dat->selection >= pcli->pfnGetGroupContentsCount(&dat->list, 1))
 -			dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1;
 -		if (dat->selection < 0) dat->selection = 0;
 -		if (dat->bCompactMode)
 -			SendMessage(hwnd, WM_SIZE, 0, 0);
 -		CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -		pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
 -		UpdateWindow(hwnd);
 -		SetCapture(hwnd);
 -		return 0;
 -	}
 -	SetCapture(hwnd);
 -	return 0;
 -}
 -
 -void clcSetDelayTimer(UINT_PTR uIDEvent, HWND hwnd, int nDelay)
 -{
 -	KillTimer(hwnd, uIDEvent);
 -	int delay = nDelay;
 -	if (delay == -1) {
 -		switch (uIDEvent) {
 -			case TIMERID_DELAYEDRESORTCLC: delay = 10;  break;
 -			case TIMERID_RECALCSCROLLBAR:  delay = 10;  break;
 -			case TIMERID_REBUILDAFTER:     delay = 50;  break;
 -			default:                       delay = 100; break;
 -		}
 -	}
 -	CLUI_SafeSetTimer(hwnd, uIDEvent, delay, NULL);
 -}
 -
 -static LRESULT clcOnTimer(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	switch (wParam) {
 -	case TIMERID_INVALIDATE_FULL:
 -		KillTimer(hwnd, TIMERID_INVALIDATE_FULL);
 -		pcli->pfnRecalcScrollBar(hwnd, dat);
 -		pcli->pfnInvalidateRect(hwnd, NULL, 0);
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -	case TIMERID_INVALIDATE:
 -		{
 -			time_t cur_time = (time(NULL) / 60);
 -			if (cur_time != dat->last_tick_time) {
 -				CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -				dat->last_tick_time = cur_time;
 -			}
 -		}
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -	case TIMERID_SUBEXPAND:
 -		KillTimer(hwnd, TIMERID_SUBEXPAND);
 -		{
 -			ClcContact *ht = NULL;
 -			if (hitcontact && dat->expandMeta) {
 -				if (hitcontact->SubExpanded) hitcontact->SubExpanded = 0; else hitcontact->SubExpanded = 1;
 -				db_set_b(hitcontact->hContact, "CList", "Expanded", hitcontact->SubExpanded);
 -				if (hitcontact->SubExpanded)
 -					ht = &(hitcontact->subcontacts[hitcontact->SubAllocated - 1]);
 -			}
 -
 -			dat->needsResort = 1;
 -			pcli->pfnSortCLC(hwnd, dat, 1);
 -			cliRecalcScrollBar(hwnd, dat);
 -			if (ht) {
 -				int i = 0;
 -				ClcContact *contact;
 -				ClcGroup *group;
 -				if (FindItem(hwnd, dat, hitcontact->hContact, &contact, &group, NULL, FALSE)) {
 -					i = cliGetRowsPriorTo(&dat->list, group, GetContactIndex(group, contact));
 -					pcli->pfnEnsureVisible(hwnd, dat, i + hitcontact->SubAllocated, 0);
 -				}
 -			}
 -			hitcontact = NULL;
 -		}
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -	case TIMERID_DELAYEDRESORTCLC:
 -		TRACE("Do sort on Timer\n");
 -		KillTimer(hwnd, TIMERID_DELAYEDRESORTCLC);
 -		pcli->pfnSortCLC(hwnd, dat, 1);
 -		pcli->pfnInvalidateRect(hwnd, NULL, FALSE);
 -		return 0;
 -
 -	case TIMERID_RECALCSCROLLBAR:
 -		KillTimer(hwnd, TIMERID_RECALCSCROLLBAR);
 -		pcli->pfnRecalcScrollBar(hwnd, dat);
 -		return 0;
 -
 -	default:
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -	}
 -	return 0;
 -}
 -
 -
 -static LRESULT clcOnActivate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	TRACE("clcOnActivate\n");
 -	if (dat->bCompactMode) {
 -		cliRecalcScrollBar(hwnd, dat);
 -		if (dat->hwndRenameEdit == NULL)
 -			PostMessage(hwnd, WM_SIZE, 0, 0);
 -	}
 -	dat->dragStage |= DRAGSTAGEF_SKIPRENAME;
 -	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -}
 -
 -static LRESULT clcOnSetCursor(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	if (!CLUI_IsInMainWindow(hwnd))
 -		return DefWindowProc(hwnd, msg, wParam, lParam);
 -
 -	if (g_CluiData.nBehindEdgeState > 0)
 -		CLUI_ShowFromBehindEdge();
 -
 -	if (g_CluiData.bBehindEdgeSettings)
 -		CLUI_UpdateTimer(0);
 -
 -	int lResult = CLUI_TestCursorOnBorders();
 -	return lResult ? lResult : DefWindowProc(hwnd, msg, wParam, lParam);
 -}
 -
 -static LRESULT clcOnLButtonDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	POINT pt = { LOWORD(lParam), HIWORD(lParam) };
 -	ClientToScreen(hwnd, &pt);
 -	int k = CLUI_SizingOnBorder(pt, 0);
 -	if (k) {
 -		int io = dat->iHotTrack;
 -		dat->iHotTrack = 0;
 -		if (dat->exStyle & CLS_EX_TRACKSELECT)
 -			pcli->pfnInvalidateItem(hwnd, dat, io);
 -
 -		if (k && GetCapture() == hwnd)
 -			SendMessage(GetParent(hwnd), WM_PARENTNOTIFY, WM_LBUTTONDOWN, lParam);
 -		return FALSE;
 -	}
 -
 -	fMouseUpped = FALSE;
 -	pcli->pfnHideInfoTip(hwnd, dat);
 -	KillTimer(hwnd, TIMERID_INFOTIP);
 -	KillTimer(hwnd, TIMERID_RENAME);
 -	KillTimer(hwnd, TIMERID_SUBEXPAND);
 -
 -	pcli->pfnEndRename(hwnd, dat, 1);
 -	dat->ptDragStart.x = (short)LOWORD(lParam);
 -	dat->ptDragStart.y = (short)HIWORD(lParam);
 -
 -	ClcContact *contact;
 -	ClcGroup *group;
 -	DWORD hitFlags;
 -	int hit = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), &contact, &group, &hitFlags);
 -	if (GetFocus() != hwnd)
 -		SetFocus(hwnd);
 -	if (hit != -1 && !(hitFlags & CLCHT_NOWHERE)) {
 -		if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) {
 -			if (!(dat->dragStage & DRAGSTAGEF_SKIPRENAME)) {
 -				SetCapture(hwnd);
 -				dat->iDragItem = dat->selection;
 -				dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME;
 -				dat->dragAutoScrolling = 0;
 -				return TRUE;
 -			}
 -			else {
 -				dat->dragStage &= ~DRAGSTAGEF_SKIPRENAME;
 -				return TRUE;
 -			}
 -		}
 -	}
 -
 -	if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_CONTACT && contact->SubAllocated && !contact->isSubcontact)
 -		if (hitFlags & CLCHT_ONITEMICON && dat->expandMeta) {
 -			BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT);
 -
 -			hitcontact = contact;
 -			HitPoint.x = (short)LOWORD(lParam);
 -			HitPoint.y = (short)HIWORD(lParam);
 -			fMouseUpped = FALSE;
 -			if ((GetKeyState(VK_SHIFT) & 0x8000) || (GetKeyState(VK_CONTROL) & 0x8000) || (GetKeyState(VK_MENU) & 0x8000)) {
 -				fMouseUpped = TRUE;
 -				hitcontact = contact;
 -				KillTimer(hwnd, TIMERID_SUBEXPAND);
 -				CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL);
 -			}
 -		}
 -		else hitcontact = NULL;
 -
 -		if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_GROUP && (hitFlags & CLCHT_ONITEMICON)) {
 -			ClcGroup *selgroup;
 -			ClcContact *selcontact;
 -			dat->selection = cliGetRowByIndex(dat, dat->selection, &selcontact, &selgroup);
 -			pcli->pfnSetGroupExpand(hwnd, dat, contact->group, -1);
 -			if (dat->selection != -1) {
 -				dat->selection = cliGetRowsPriorTo(&dat->list, selgroup, GetContactIndex(selgroup, selcontact));
 -				if (dat->selection == -1)
 -					dat->selection = cliGetRowsPriorTo(&dat->list, contact->group, -1);
 -			}
 -
 -			if (dat->bCompactMode)
 -				SendMessage(hwnd, WM_SIZE, 0, 0);
 -			else {
 -				CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -				UpdateWindow(hwnd);
 -			}
 -			return TRUE;
 -		}
 -
 -		if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && (hitFlags & CLCHT_ONITEMCHECK)) {
 -			int bNewState = (contact->flags & CONTACTF_CHECKED) == 0; // inversion
 -
 -			if (contact->type == CLCIT_GROUP)
 -				pcli->pfnSetGroupChildCheckboxes(contact->group, bNewState);
 -			else
 -				pcli->pfnSetContactCheckboxes(contact, bNewState);
 -			pcli->pfnRecalculateGroupCheckboxes(hwnd, dat);
 -			CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -
 -			NMCLISTCONTROL nm;
 -			nm.hdr.code = CLN_CHECKCHANGED;
 -			nm.hdr.hwndFrom = hwnd;
 -			nm.hdr.idFrom = GetDlgCtrlID(hwnd);
 -			nm.flags = 0;
 -			nm.hItem = ContactToItemHandle(contact, &nm.flags);
 -			SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
 -		}
 -
 -		if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) {
 -			NMCLISTCONTROL nm;
 -			nm.hdr.code = NM_CLICK;
 -			nm.hdr.hwndFrom = hwnd;
 -			nm.hdr.idFrom = GetDlgCtrlID(hwnd);
 -			nm.flags = 0;
 -			nm.hItem = (hit == -1 || hitFlags & CLCHT_NOWHERE) ? NULL : ContactToItemHandle(contact, &nm.flags);
 -			nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1;
 -			nm.pt = dat->ptDragStart;
 -			SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
 -		}
 -
 -		if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA))
 -			return FALSE;
 -
 -		dat->selection = (hitFlags & CLCHT_NOWHERE) ? -1 : hit;
 -		CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -
 -		UpdateWindow(hwnd);
 -		if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP) && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK | CLCHT_NOWHERE))) {
 -			SetCapture(hwnd);
 -			dat->iDragItem = dat->selection;
 -			dat->dragStage = DRAGSTAGE_NOTMOVED;
 -			dat->dragAutoScrolling = 0;
 -		}
 -
 -		if (dat->bCompactMode)
 -			SendMessage(hwnd, WM_SIZE, 0, 0);
 -
 -		if (dat->selection != -1)
 -			pcli->pfnEnsureVisible(hwnd, dat, hit, 0);
 -		return TRUE;
 -}
 -
 -static LRESULT clcOnCaptureChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	if ((HWND)lParam != hwnd) {
 -		if (dat->iHotTrack != -1) {
 -			int i;
 -			i = dat->iHotTrack;
 -			dat->iHotTrack = -1;
 -			pcli->pfnInvalidateItem(hwnd, dat, i);
 -			pcli->pfnHideInfoTip(hwnd, dat);
 -		}
 -	}
 -	return 0;
 -}
 -
 -static LRESULT clcOnMouseMove(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	BOOL isOutside = FALSE;
 -	if (CLUI_IsInMainWindow(hwnd)) {
 -		if (g_CluiData.bBehindEdgeSettings)
 -			CLUI_UpdateTimer(0);
 -		CLUI_TestCursorOnBorders();
 -	}
 -
 -	if (clcProceedDragToScroll(hwnd, (short)HIWORD(lParam)))
 -		return 0;
 -
 -	if (dat->dragStage & DRAGSTAGEF_MAYBERENAME) {
 -		POINT pt = UNPACK_POINT(lParam);
 -		if (abs(pt.x - dat->ptDragStart.x) > GetSystemMetrics(SM_CXDOUBLECLK) || abs(pt.y - dat->ptDragStart.y) > GetSystemMetrics(SM_CYDOUBLECLK)) {
 -			KillTimer(hwnd, TIMERID_RENAME);
 -			dat->dragStage &= (~DRAGSTAGEF_MAYBERENAME);
 -		}
 -	}
 -
 -	if (dat->iDragItem == -1) {
 -		POINT pt = UNPACK_POINT(lParam);
 -		ClientToScreen(hwnd, &pt);
 -		HWND window = WindowFromPoint(pt);
 -		if (window != hwnd)
 -			isOutside = TRUE;
 -	}
 -
 -	if (hitcontact != NULL) {
 -		int x = (short)LOWORD(lParam);
 -		int y = (short)HIWORD(lParam);
 -		int xm = GetSystemMetrics(SM_CXDOUBLECLK);
 -		int ym = GetSystemMetrics(SM_CYDOUBLECLK);
 -		if (abs(HitPoint.x - x) > xm || abs(HitPoint.y - y) > ym) {
 -			if (fMouseUpped) {
 -				KillTimer(hwnd, TIMERID_SUBEXPAND);
 -				CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL);
 -				fMouseUpped = FALSE;
 -			}
 -			else {
 -				KillTimer(hwnd, TIMERID_SUBEXPAND);
 -				hitcontact = NULL;
 -				fMouseUpped = FALSE;
 -			}
 -		}
 -	}
 -
 -	if (dat->iDragItem == -1) {
 -		DWORD flag = 0;
 -		int iOldHotTrack = dat->iHotTrack;
 -
 -		if (dat->hwndRenameEdit != NULL || GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000)
 -			return 0;
 -
 -		dat->iHotTrack = isOutside ? -1 : cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flag);
 -
 -		if (flag & CLCHT_NOWHERE)
 -			dat->iHotTrack = -1;
 -
 -		if (iOldHotTrack != dat->iHotTrack || isOutside) {
 -			if (iOldHotTrack == -1 && !isOutside)
 -				SetCapture(hwnd);
 -
 -			if (dat->iHotTrack == -1 || isOutside)
 -				ReleaseCapture();
 -
 -			if (dat->exStyle & CLS_EX_TRACKSELECT) {
 -				pcli->pfnInvalidateItem(hwnd, dat, iOldHotTrack);
 -				pcli->pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
 -			}
 -
 -			pcli->pfnHideInfoTip(hwnd, dat);
 -		}
 -
 -		KillTimer(hwnd, TIMERID_INFOTIP);
 -
 -		if (wParam == 0 && dat->hInfoTipItem == NULL) {
 -			dat->ptInfoTip.x = (short)LOWORD(lParam);
 -			dat->ptInfoTip.y = (short)HIWORD(lParam);
 -			CLUI_SafeSetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL);
 -		}
 -		return 0;
 -	}
 -
 -	if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP))
 -		if (abs((short)LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG) || abs((short)HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG))
 -			dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE;
 -
 -	if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
 -		RECT clRect;
 -		GetClientRect(hwnd, &clRect);
 -
 -		POINT pt = UNPACK_POINT(lParam);
 -		HCURSOR hNewCursor = LoadCursor(NULL, IDC_NO);
 -		CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -		if (dat->dragAutoScrolling) {
 -			KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
 -			dat->dragAutoScrolling = 0;
 -		}
 -		int target = GetDropTargetInformation(hwnd, dat, pt);
 -		if ((dat->dragStage & DRAGSTAGEF_OUTSIDE) && target != DROPTARGET_OUTSIDE) {
 -			ClcContact *contact;
 -			cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
 -
 -			NMCLISTCONTROL nm;
 -			nm.hdr.code = CLN_DRAGSTOP;
 -			nm.hdr.hwndFrom = hwnd;
 -			nm.hdr.idFrom = GetDlgCtrlID(hwnd);
 -			nm.flags = 0;
 -			nm.hItem = ContactToItemHandle(contact, &nm.flags);
 -			SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
 -			dat->dragStage &= ~DRAGSTAGEF_OUTSIDE;
 -		}
 -
 -		ClcContact *contSour, *contDest;
 -
 -		switch (target) {
 -		case DROPTARGET_ONSELF:
 -			break;
 -
 -		case DROPTARGET_ONCONTACT:
 -			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
 -			if (contSour->isChat())
 -				break;
 -			if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
 -				if (!contSour->isSubcontact)
 -					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));  /// Add to meta
 -				else
 -					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DROPMETA));
 -			}
 -			break;
 -
 -		case DROPTARGET_ONMETACONTACT:
 -			cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
 -			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
 -			if (contSour->isChat() || contDest->isChat())
 -				break;
 -			if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
 -				if (!contSour->isSubcontact)
 -					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));  /// Add to meta
 -				else if (contSour->subcontacts == contDest)
 -					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DEFAULTSUB)); ///MakeDefault
 -				else
 -					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP));
 -			}
 -			break;
 -
 -		case DROPTARGET_ONSUBCONTACT:
 -			cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
 -			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
 -			if (contSour->isChat() || contDest->isChat())
 -				break;
 -			if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
 -				if (!contSour->isSubcontact)
 -					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));  /// Add to meta
 -				else if (contDest->subcontacts == contSour->subcontacts)
 -					break;
 -				else
 -					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP));
 -			}
 -			break;
 -
 -		case DROPTARGET_ONGROUP:
 -			hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));
 -			break;
 -
 -		case DROPTARGET_INSERTION:
 -			hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROP));
 -			break;
 -
 -		case DROPTARGET_OUTSIDE:
 -			if (pt.x >= 0 && pt.x < clRect.right && ((pt.y < 0 && pt.y>-dat->dragAutoScrollHeight) || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) {
 -				if (!dat->dragAutoScrolling) {
 -					dat->dragAutoScrolling = (pt.y < 0) ? -1 : 1;
 -					CLUI_SafeSetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL);
 -				}
 -				SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0);
 -			}
 -
 -			dat->dragStage |= DRAGSTAGEF_OUTSIDE;
 -			{
 -				ClcContact *contact;
 -				cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
 -
 -				NMCLISTCONTROL nm;
 -				nm.hdr.code = CLN_DRAGGING;
 -				nm.hdr.hwndFrom = hwnd;
 -				nm.hdr.idFrom = GetDlgCtrlID(hwnd);
 -				nm.flags = 0;
 -				nm.hItem = ContactToItemHandle(contact, &nm.flags);
 -				nm.pt = pt;
 -				if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm))
 -					return 0;
 -			}
 -			break;
 -
 -		default:
 -			ClcGroup *group = NULL;
 -			cliGetRowByIndex(dat, dat->iDragItem, NULL, &group);
 -			if (group && group->parent) {
 -				ClcContact *contSour;
 -				cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
 -				if (!contSour->isSubcontact)
 -					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));
 -			}
 -			break;
 -		}
 -		SetCursor(hNewCursor);
 -	}
 -	return 0;
 -}
 -
 -static LRESULT clcOnLButtonUp(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	if (clcExitDragToScroll())
 -		return 0;
 -
 -	fMouseUpped = TRUE;
 -
 -	if (hitcontact != NULL && dat->expandMeta) {
 -		BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT);
 -		CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, GetDoubleClickTime()*doubleClickExpand, NULL);
 -	}
 -	else if (dat->iHotTrack == -1 && dat->iDragItem == -1)
 -		ReleaseCapture();
 -
 -	if (dat->iDragItem == -1)
 -		return 0;
 -
 -	SetCursor((HCURSOR)GetClassLongPtr(hwnd, GCLP_HCURSOR));
 -	if (dat->exStyle & CLS_EX_TRACKSELECT) {
 -		DWORD flags;
 -		dat->iHotTrack = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flags);
 -		if (dat->iHotTrack == -1)
 -			ReleaseCapture();
 -	}
 -	else if (hitcontact == NULL)
 -		ReleaseCapture();
 -	KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
 -	if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME))
 -		CLUI_SafeSetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL);
 -	else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
 -		TCHAR Wording[500];
 -		ClcContact *contDest, *contSour;
 -		POINT pt = UNPACK_POINT(lParam);
 -		int target = GetDropTargetInformation(hwnd, dat, pt);
 -		switch (target) {
 -		case DROPTARGET_ONSELF:
 -			break;
 -
 -		case DROPTARGET_ONCONTACT:
 -			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
 -			cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
 -			if (contSour->isChat() || contDest->isChat())
 -				break;
 -			if (contSour->type == CLCIT_CONTACT) {
 -				MCONTACT hcontact = contSour->hContact;
 -				if (mir_strcmp(contSour->proto, META_PROTO)) {
 -					if (!contSour->isSubcontact) {
 -						MCONTACT hDest = contDest->hContact;
 -						mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it?"), contDest->szText, contSour->szText);
 -						int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact"), MB_OKCANCEL | MB_ICONQUESTION);
 -						if (res == 1) {
 -							MCONTACT handle = CallService(MS_MC_CONVERTTOMETA, hDest, 0);
 -							if (!handle)
 -								return 0;
 -
 -							CallService(MS_MC_ADDTOMETA, hcontact, handle);
 -						}
 -					}
 -					else {
 -						hcontact = contSour->hContact;
 -						MCONTACT hfrom = contSour->subcontacts->hContact;
 -						MCONTACT hdest = contDest->hContact;
 -						mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it (remove it from '%s')?"), contDest->szText, contSour->szText, contSour->subcontacts->szText);
 -						int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
 -						if (res == 1) {
 -							MCONTACT handle = (MCONTACT)CallService(MS_MC_CONVERTTOMETA, (WPARAM)hdest, 0);
 -							if (!handle)
 -								return 0;
 -
 -							CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
 -							CallService(MS_MC_ADDTOMETA, hcontact, handle);
 -						}
 -					}
 -				}
 -			}
 -			break;
 -
 -		case DROPTARGET_ONMETACONTACT:
 -			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
 -			cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
 -			if (contSour->isChat() || contDest->isChat())
 -				break;
 -			if (contSour->type == CLCIT_CONTACT) {
 -				if (!strcmp(contSour->proto, META_PROTO))
 -					break;
 -				if (!contSour->isSubcontact) {
 -					MCONTACT hcontact = contSour->hContact;
 -					MCONTACT handle = contDest->hContact;
 -					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->szText);
 -					int res = MessageBox(hwnd, Wording, TranslateT("Adding contact to metacontact"), MB_OKCANCEL | MB_ICONQUESTION);
 -					if (res == 1) {
 -						if (!handle)
 -							return 0;
 -						CallService(MS_MC_ADDTOMETA, hcontact, handle);
 -					}
 -				}
 -				else if (contSour->subcontacts == contDest) {
 -					MCONTACT hsour = contSour->hContact;
 -					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be default?"), contSour->szText);
 -					int res = MessageBox(hwnd, Wording, TranslateT("Set default contact"), MB_OKCANCEL | MB_ICONQUESTION);
 -					if (res == 1)
 -						db_mc_setDefault(contDest->hContact, hsour, true);
 -				}
 -				else {
 -					MCONTACT hcontact = contSour->hContact;
 -					MCONTACT hfrom = contSour->subcontacts->hContact;
 -					MCONTACT handle = contDest->hContact;
 -					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->szText);
 -					int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
 -					if (res == 1) {
 -						if (!handle)
 -							return 0;
 -
 -						CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
 -						CallService(MS_MC_ADDTOMETA, hcontact, handle);
 -					}
 -				}
 -			}
 -			break;
 -
 -		case DROPTARGET_ONSUBCONTACT:
 -			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
 -			cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
 -			if (contSour->isChat() || contDest->isChat())
 -				break;
 -			if (contSour->type == CLCIT_CONTACT) {
 -				if (!strcmp(contSour->proto, META_PROTO))
 -					break;
 -				if (!contSour->isSubcontact) {
 -					MCONTACT hcontact = contSour->hContact;
 -					MCONTACT handle = contDest->subcontacts->hContact;
 -					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->subcontacts->szText);
 -					int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
 -					if (res == 1) {
 -						if (!handle)
 -							return 0;
 -						
 -						CallService(MS_MC_ADDTOMETA, hcontact, handle);
 -					}
 -				}
 -				else if (contSour->subcontacts != contDest->subcontacts) {
 -					MCONTACT hcontact = contSour->hContact;
 -					MCONTACT hfrom = contSour->subcontacts->hContact;
 -					MCONTACT handle = contDest->subcontacts->hContact;
 -					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->subcontacts->szText);
 -					int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
 -					if (res == 1) {
 -						if (!handle)
 -							return 0;
 -
 -						CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
 -						CallService(MS_MC_ADDTOMETA, hcontact, handle);
 -					}
 -				}
 -			}
 -			break;
 -
 -		case DROPTARGET_ONGROUP:
 -			corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -			break;
 -
 -		case DROPTARGET_INSERTION:
 -			{
 -				ClcContact *contact, *destcontact;
 -				ClcGroup *group, *destgroup;
 -				BOOL NeedRename = FALSE;
 -				TCHAR newName[128] = { 0 };
 -				pcli->pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group);
 -				int i = pcli->pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup);
 -				if (i != -1 && group->groupId != destgroup->groupId) {
 -					TCHAR *groupName = mir_tstrdup(pcli->pfnGetGroupName(contact->groupId, 0));
 -					TCHAR *shortGroup = NULL;
 -					TCHAR *sourceGrName = mir_tstrdup(pcli->pfnGetGroupName(destgroup->groupId, 0));
 -					if (groupName) {
 -						int len = (int)_tcslen(groupName);
 -						do { len--; }
 -						while (len >= 0 && groupName[len] != '\\');
 -						if (len >= 0) shortGroup = groupName + len + 1;
 -						else shortGroup = groupName;
 -					}
 -					if (shortGroup) {
 -						NeedRename = TRUE;
 -						if (sourceGrName)
 -							mir_sntprintf(newName, SIZEOF(newName), _T("%s\\%s"), sourceGrName, shortGroup);
 -						else
 -							mir_sntprintf(newName, SIZEOF(newName), _T("%s"), shortGroup);
 -					}
 -					mir_free(groupName);
 -					mir_free(sourceGrName);
 -				}
 -				int newIndex = CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, (destcontact && i != -1) ? destcontact->groupId : 0);
 -				newIndex = newIndex ? newIndex : contact->groupId;
 -				if (NeedRename) pcli->pfnRenameGroup(newIndex, newName);
 -			}
 -			break;
 -
 -		case DROPTARGET_OUTSIDE:
 -			corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -			break;
 -
 -		default:
 -			corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -			break;
 -		}
 -	}
 -
 -	CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -	dat->iDragItem = -1;
 -	dat->iInsertionMark = -1;
 -	return 0;
 -}
 -
 -static LRESULT clcOnLButtonDblClick(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	KillTimer(hwnd, TIMERID_SUBEXPAND);
 -	hitcontact = NULL;
 -	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -}
 -
 -static LRESULT clcOnDestroy(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	for (int i = 0; i <= FONTID_MODERN_MAX; i++) {
 -		if (dat->fontModernInfo[i].hFont)
 -			DeleteObject(dat->fontModernInfo[i].hFont);
 -		dat->fontModernInfo[i].hFont = NULL;
 -	}
 -	if (dat->hMenuBackground) {
 -		DeleteObject(dat->hMenuBackground);
 -		dat->hMenuBackground = NULL;
 -	}
 -	if (dat->hBmpBackground) {
 -		DeleteObject(dat->hBmpBackground);
 -		dat->hBmpBackground = NULL;
 -	}
 -
 -	ImageArray_Clear(&dat->avatar_cache);
 -	DeleteDC(dat->avatar_cache.hdc);
 -	ImageArray_Free(&dat->avatar_cache, FALSE);
 -	if (dat->himlHighlight)
 -		ImageList_Destroy(dat->himlHighlight);
 -
 -	RowHeights_Free(dat);
 -	corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -	xpt_FreeThemeForWindow(hwnd);
 -	return 0;
 -}
 -
 -static LRESULT clcOnIntmGroupChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	WORD iExtraImage[EXTRA_ICON_COUNT];
 -	BYTE flags = 0;
 -
 -	ClcContact *contact;
 -	if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL))
 -		memset(iExtraImage, 0xFF, sizeof(iExtraImage));
 -	else {
 -		memcpy(iExtraImage, contact->iExtraImage, sizeof(iExtraImage));
 -		flags = contact->flags;
 -	}
 -	pcli->pfnDeleteItemFromTree(hwnd, wParam);
 -	if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !db_get_b(wParam, "CList", "Hidden", 0)) {
 -		NMCLISTCONTROL nm;
 -		pcli->pfnAddContactToTree(hwnd, dat, wParam, 1, 1);
 -		if (pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) {
 -			memcpy(contact->iExtraImage, iExtraImage, sizeof(iExtraImage));
 -			if (flags & CONTACTF_CHECKED)
 -				contact->flags |= CONTACTF_CHECKED;
 -		}
 -		nm.hdr.code = CLN_CONTACTMOVED;
 -		nm.hdr.hwndFrom = hwnd;
 -		nm.hdr.idFrom = GetDlgCtrlID(hwnd);
 -		nm.flags = 0;
 -		nm.hItem = (HANDLE)wParam;
 -		SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
 -		dat->needsResort = 1;
 -	}
 -	SetTimer(hwnd, TIMERID_REBUILDAFTER, 1, NULL);
 -	return 0;
 -}
 -
 -static LRESULT clcOnIntmIconChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	ClcContact *contact = NULL;
 -	ClcGroup *group = NULL;
 -	int recalcScrollBar = 0, shouldShow;
 -	BOOL needRepaint = FALSE;
 -	RECT iconRect = { 0 };
 -	int contacticon = corecli.pfnGetContactIcon(wParam);
 -	MCONTACT hSelItem = NULL;
 -	ClcContact *selcontact = NULL;
 -
 -	char *szProto = GetContactProto(wParam);
 -	WORD status = (szProto == NULL) ? ID_STATUS_OFFLINE : GetContactCachedStatus(wParam);
 -	BOOL image_is_special = (LOWORD(contacticon) != (LOWORD(lParam))); //check only base icons
 -
 -	int nHiddenStatus = CLVM_GetContactHiddenStatus(wParam, szProto, dat);
 -
 -	DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
 -	bool isVisiblebyFilter = (((style & CLS_SHOWHIDDEN) && nHiddenStatus != -1) || !nHiddenStatus);
 -	bool ifVisibleByClui = !pcli->pfnIsHiddenMode(dat, status);
 -	bool isVisible = g_CluiData.bFilterEffective&CLVM_FILTER_STATUS ? TRUE : ifVisibleByClui;
 -	bool isIconChanged = cli_GetContactIcon(wParam) != LOWORD(lParam);
 -
 -	shouldShow = isVisiblebyFilter && (isVisible || isIconChanged);
 -
 -	// XXX CLVM changed - this means an offline msg is flashing, so the contact should be shown
 -
 -	if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, &group, NULL)) {
 -		if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) {
 -			if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
 -				hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
 -			pcli->pfnAddContactToTree(hwnd, dat, wParam, (style & CLS_CONTACTLIST) == 0, 0);
 -			recalcScrollBar = 1;
 -			needRepaint = TRUE;
 -			pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL);
 -			if (contact) {
 -				contact->iImage = lParam;
 -				contact->image_is_special = image_is_special;
 -				pcli->pfnNotifyNewContact(hwnd, wParam);
 -				dat->needsResort = 1;
 -			}
 -		}
 -	}
 -	else {
 -		//item in list already
 -		if (contact->iImage == lParam)
 -			return 0;
 -
 -		if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline) && clcItemNotHiddenOffline(dat, group, contact))
 -			shouldShow = TRUE;
 -
 -		if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && ((style & CLS_HIDEOFFLINE) || group->hideOffline || g_CluiData.bFilterEffective)) { // CLVM changed
 -			if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
 -				hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
 -			pcli->pfnRemoveItemFromGroup(hwnd, group, contact, (style & CLS_CONTACTLIST) == 0);
 -			needRepaint = TRUE;
 -			recalcScrollBar = 1;
 -			dat->needsResort = 1;
 -		}
 -		else if (contact) {
 -			contact->iImage = lParam;
 -			if (!pcli->pfnIsHiddenMode(dat, status))
 -				contact->flags |= CONTACTF_ONLINE;
 -			else
 -				contact->flags &= ~CONTACTF_ONLINE;
 -			contact->image_is_special = image_is_special;
 -			if (!image_is_special) { //Only if it is status changing
 -				dat->needsResort = 1;
 -				needRepaint = TRUE;
 -			}
 -			else if (dat->m_paintCouter == contact->lastPaintCounter) //if contacts is visible
 -				needRepaint = TRUE;
 -		}
 -	}
 -
 -	if (hSelItem) {
 -		ClcGroup *selgroup;
 -		if (pcli->pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
 -			dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact));
 -		else
 -			dat->selection = -1;
 -	}
 -
 -	if (dat->needsResort) {
 -		TRACE("Sort required\n");
 -		clcSetDelayTimer(TIMERID_DELAYEDRESORTCLC, hwnd);
 -	}
 -	else if (needRepaint) {
 -		if (contact && contact->pos_icon.bottom != 0 && contact->pos_icon.right != 0)
 -			CLUI__cliInvalidateRect(hwnd, &(contact->pos_icon), FALSE);
 -		else
 -			CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -		//try only needed rectangle
 -	}
 -
 -	return 0;
 -}
 -
 -static LRESULT clcOnIntmAvatarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	ClcContact *contact;
 -	if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
 -		Cache_GetAvatar(dat, contact);
 -	else if (dat->use_avatar_service && !wParam)
 -		UpdateAllAvatars(dat);
 -
 -	CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -	return 0;
 -}
 -
 -static LRESULT clcOnIntmTimeZoneChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	ClcContact *contact;
 -	if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -	if (contact) {
 -		Cache_GetTimezone(dat, contact->hContact);
 -		Cache_GetText(dat, contact, 1);
 -		cliRecalcScrollBar(hwnd, dat);
 -	}
 -	return 0;
 -}
 -
 -static LRESULT clcOnIntmNameChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -	pcli->pfnInvalidateDisplayNameCacheEntry(wParam);
 -
 -	ClcContact *contact;
 -	if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
 -		return ret;
 -
 -	lstrcpyn(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), SIZEOF(contact->szText));
 -	if (contact) {
 -		Cache_GetText(dat, contact, 1);
 -		cliRecalcScrollBar(hwnd, dat);
 -	}
 -	dat->needsResort = 1;
 -	pcli->pfnSortContacts();
 -
 -	return ret;
 -}
 -
 -static LRESULT clcOnIntmApparentModeChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -}
 -
 -static LRESULT clcOnIntmStatusMsgChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM hContact, LPARAM lParam)
 -{
 -	if (hContact == NULL || IsHContactInfo(hContact) || IsHContactGroup(hContact))
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
 -
 -	ClcContact *contact;
 -	if (!FindItem(hwnd, dat, hContact, &contact, NULL, NULL, FALSE))
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
 -
 -	if (contact) {
 -		Cache_GetText(dat, contact, 1);
 -		cliRecalcScrollBar(hwnd, dat);
 -		PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
 -	}
 -	return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
 -}
 -
 -static LRESULT clcOnIntmNotOnListChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING*)lParam;
 -
 -	ClcContact *contact;
 -	if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE))
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -	if (contact->type != CLCIT_CONTACT)
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -
 -	if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0)
 -		contact->flags &= ~CONTACTF_NOTONLIST;
 -	else
 -		contact->flags |= CONTACTF_NOTONLIST;
 -
 -	CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
 -	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -}
 -
 -static LRESULT clcOnIntmScrollBarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
 -		if (dat->noVScrollbar)
 -			ShowScrollBar(hwnd, SB_VERT, FALSE);
 -		else
 -			pcli->pfnRecalcScrollBar(hwnd, dat);
 -	}
 -	return 0;
 -}
 -
 -static LRESULT clcOnIntmStatusChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -	if (wParam != 0) {
 -		ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(wParam);
 -		if (pdnce && pdnce->m_cache_cszProto) {
 -			pdnce->m_cache_nStatus = GetStatusForContact(pdnce->hContact, pdnce->m_cache_cszProto);
 -			if (!dat->force_in_dialog && (dat->second_line_show || dat->third_line_show))
 -				gtaRenewText(pdnce->hContact);
 -			SendMessage(hwnd, INTM_ICONCHANGED, wParam, corecli.pfnGetContactIcon(wParam));
 -
 -			ClcContact *contact;
 -			if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE)) {
 -				if (contact && contact->type == CLCIT_CONTACT) {
 -					if (!contact->image_is_special && pdnce___GetStatus(pdnce) > ID_STATUS_OFFLINE)
 -						contact->iImage = corecli.pfnGetContactIcon(wParam);
 -					if (contact->isSubcontact && contact->subcontacts && contact->subcontacts->type == CLCIT_CONTACT)
 -						pcli->pfnClcBroadcast(INTM_STATUSCHANGED, contact->subcontacts->hContact, 0); //forward status changing to host meta contact
 -				}
 -			}
 -		}
 -	}
 -
 -	if (db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOOFLINETOROOT_DEFAULT))
 -		pcli->pfnInitAutoRebuild(hwnd);
 -	else {
 -		pcli->pfnSortContacts();
 -		PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
 -	}
 -	return ret;
 -}
 -
 -static LRESULT clcOnIntmReloadOptions(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -	pcli->pfnLoadClcOptions(hwnd, dat, FALSE);
 -	LoadCLCOptions(hwnd, dat, FALSE);
 -	pcli->pfnSaveStateAndRebuildList(hwnd, dat);
 -	pcli->pfnSortCLC(hwnd, dat, 1);
 -	if (IsWindowVisible(hwnd))
 -		pcli->pfnInvalidateRect(GetParent(hwnd), NULL, FALSE);
 -	return TRUE;
 -}
 -
 -HRESULT ClcLoadModule()
 -{
 -	g_himlCListClc = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0);
 -
 -	HookEvent(ME_MC_SUBCONTACTSCHANGED, clcMetacontactChanged);
 -	HookEvent(ME_MC_ENABLED, clcMetaModeChanged);
 -	HookEvent(ME_DB_CONTACT_SETTINGCHANGED, clcHookSettingChanged);
 -	HookEvent(ME_OPT_INITIALISE, ClcOptInit);
 -	hAckHook = (HANDLE)HookEvent(ME_PROTO_ACK, clcHookProtoAck);
 -	HookEvent(ME_SYSTEM_MODULESLOADED, clcHookModulesLoaded);
 -	HookEvent(ME_DB_EVENT_ADDED, clcHookDbEventAdded);
 -	return S_OK;
 -}
 -
 -int ClcUnloadModule()
 -{
 -	if (g_CluiData.bOldUseGroups != (BYTE)-1)
 -		db_set_b(NULL, "CList", "UseGroups", (BYTE)g_CluiData.bOldUseGroups);
 -	if (g_CluiData.boldHideOffline != (BYTE)-1)
 -		db_set_b(NULL, "CList", "HideOffline", (BYTE)g_CluiData.boldHideOffline);
 -
 -	return 0;
 -}
 -
 -int ClcDoProtoAck(MCONTACT wParam, ACKDATA * ack)
 -{
 -	if (MirandaExiting()) return 0;
 -	if (ack->type == ACKTYPE_STATUS) {
 -		if (ack->result == ACKRESULT_SUCCESS) {
 -			for (int i = 0; i < pcli->hClcProtoCount; i++) {
 -				if (!lstrcmpA(pcli->clcProto[i].szProto, ack->szModule)) {
 -					pcli->clcProto[i].dwStatus = (WORD)ack->lParam;
 -					if (pcli->clcProto[i].dwStatus >= ID_STATUS_OFFLINE)
 -						pcli->pfnTrayIconUpdateBase(pcli->clcProto[i].szProto);
 -					return 0;
 -				}
 -			}
 -		}
 -	}
 -	else if (ack->type == ACKTYPE_AWAYMSG) {
 -		if (ack->result == ACKRESULT_SUCCESS && ack->lParam) {
 -			//Do not change DB if it is IRC protocol
 -			if (ack->szModule != NULL)
 -				if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0)
 -					return 0;
 -
 -			db_set_ws(ack->hContact, "CList", "StatusMsg", (const TCHAR *)ack->lParam);
 -			gtaRenewText(ack->hContact);
 -		}
 -		else {
 -			//db_unset(ack->hContact,"CList","StatusMsg");
 -			//char a = '\0';
 -			//Do not change DB if it is IRC protocol
 -			if (ack->szModule != NULL)
 -				if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0)
 -					return 0;
 -
 -			if (ack->hContact) {
 -				char *val = db_get_sa(ack->hContact, "CList", "StatusMsg");
 -				if (val) {
 -					if (!mir_bool_strcmpi(val, ""))
 -						db_set_s(ack->hContact, "CList", "StatusMsg", "");
 -					else
 -						gtaRenewText(ack->hContact);
 -					mir_free(val);
 -				}
 -			}
 -			//pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED,(WPARAM)ack->hContact,&a);
 -		}
 -	}
 -	else if (ack->type == ACKTYPE_AVATAR) {
 -		if (ack->result == ACKRESULT_SUCCESS) {
 -			PROTO_AVATAR_INFORMATIONT *pai = (PROTO_AVATAR_INFORMATIONT*)ack->hProcess;
 -			if (pai != NULL && pai->hContact != NULL)
 -				pcli->pfnClcBroadcast(INTM_AVATARCHANGED, (WPARAM)pai->hContact, 0);
 -		}
 -	}
 -	else if (ack->type == ACKTYPE_EMAIL) {
 -		CLUIUnreadEmailCountChanged(0, 0);
 -	}
 -	return 0;
 -}
 -
 -int ClcGetShortData(ClcData* pData, struct SHORTDATA *pShortData)
 -{
 -	if (!pData || !pShortData)
 -		return -1;
 -	
 -	pShortData->hWnd = pData->hWnd;
 -	pShortData->text_replace_smileys = pData->text_replace_smileys;
 -	pShortData->text_smiley_height = pData->text_smiley_height;
 -	pShortData->text_use_protocol_smileys = pData->text_use_protocol_smileys;
 -	pShortData->contact_time_show_only_if_different = pData->contact_time_show_only_if_different;
 -	// Second line
 -	pShortData->second_line_show = pData->second_line_show;
 -	pShortData->second_line_draw_smileys = pData->second_line_draw_smileys;
 -	pShortData->second_line_type = pData->second_line_type;
 -
 -	_tcsncpy(pShortData->second_line_text, pData->second_line_text, TEXT_TEXT_MAX_LENGTH);
 -
 -	pShortData->second_line_xstatus_has_priority = pData->second_line_xstatus_has_priority;
 -	pShortData->second_line_show_status_if_no_away = pData->second_line_show_status_if_no_away;
 -	pShortData->second_line_show_listening_if_no_away = pData->second_line_show_listening_if_no_away;
 -	pShortData->second_line_use_name_and_message_for_xstatus = pData->second_line_use_name_and_message_for_xstatus;
 -
 -	pShortData->third_line_show = pData->third_line_show;
 -	pShortData->third_line_draw_smileys = pData->third_line_draw_smileys;
 -	pShortData->third_line_type = pData->third_line_type;
 -
 -	_tcsncpy(pShortData->third_line_text, pData->third_line_text, TEXT_TEXT_MAX_LENGTH);
 -
 -	pShortData->third_line_xstatus_has_priority = pData->third_line_xstatus_has_priority;
 -	pShortData->third_line_show_status_if_no_away = pData->third_line_show_status_if_no_away;
 -	pShortData->third_line_show_listening_if_no_away = pData->third_line_show_listening_if_no_away;
 -	pShortData->third_line_use_name_and_message_for_xstatus = pData->third_line_use_name_and_message_for_xstatus;
 -	return 0;
 -}
 -
 -int ClcEnterDragToScroll(HWND hwnd, int Y)
 -{
 -	if (IsDragToScrollMode)
 -		return 0;
 -
 -	ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0);
 -	if (!dat)
 -		return 0;
 -
 -	StartDragPos = Y;
 -	StartScrollPos = dat->yScroll;
 -	IsDragToScrollMode = 1;
 -	SetCapture(hwnd);
 -	return 1;
 -}
 -
 -
 -/*
 -*	Contact list control window procedure
 -*/
 -LRESULT CALLBACK cli_ContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -
 -#define CASE_MSG_RET(msg, handler) case msg: return handler(dat, hwnd, msg, wParam, lParam);
 -
 -	ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0);
 -
 -	if (msg >= CLM_FIRST && msg < CLM_LAST)
 -		return cli_ProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
 -
 -	switch (msg) {
 -		CASE_MSG_RET(INTM_GROUPCHANGED, clcOnIntmGroupChanged);
 -		CASE_MSG_RET(INTM_ICONCHANGED, clcOnIntmIconChanged);
 -		CASE_MSG_RET(INTM_AVATARCHANGED, clcOnIntmAvatarChanged);
 -		CASE_MSG_RET(INTM_TIMEZONECHANGED, clcOnIntmTimeZoneChanged);
 -		CASE_MSG_RET(INTM_NAMECHANGED, clcOnIntmNameChanged);
 -		CASE_MSG_RET(INTM_APPARENTMODECHANGED, clcOnIntmApparentModeChanged);
 -		CASE_MSG_RET(INTM_STATUSMSGCHANGED, clcOnIntmStatusMsgChanged);
 -		CASE_MSG_RET(INTM_NOTONLISTCHANGED, clcOnIntmNotOnListChanged);
 -		CASE_MSG_RET(INTM_SCROLLBARCHANGED, clcOnIntmScrollBarChanged);
 -		CASE_MSG_RET(INTM_STATUSCHANGED, clcOnIntmStatusChanged);
 -		CASE_MSG_RET(INTM_RELOADOPTIONS, clcOnIntmReloadOptions);
 -
 -		CASE_MSG_RET(WM_CREATE, clcOnCreate);
 -		CASE_MSG_RET(WM_NCHITTEST, clcOnHitTest);
 -		CASE_MSG_RET(WM_COMMAND, clcOnCommand);
 -		CASE_MSG_RET(WM_SIZE, clcOnSize);
 -		CASE_MSG_RET(WM_CHAR, clcOnChar);
 -		CASE_MSG_RET(WM_PAINT, clcOnPaint);
 -		CASE_MSG_RET(WM_ERASEBKGND, clcOnEraseBkGround);
 -		CASE_MSG_RET(WM_KEYDOWN, clcOnKeyDown);
 -		CASE_MSG_RET(WM_TIMER, clcOnTimer);
 -		CASE_MSG_RET(WM_ACTIVATE, clcOnActivate);
 -		CASE_MSG_RET(WM_SETCURSOR, clcOnSetCursor);
 -		CASE_MSG_RET(WM_LBUTTONDOWN, clcOnLButtonDown);
 -		CASE_MSG_RET(WM_CAPTURECHANGED, clcOnCaptureChanged);
 -		CASE_MSG_RET(WM_MOUSEMOVE, clcOnMouseMove);
 -		CASE_MSG_RET(WM_LBUTTONUP, clcOnLButtonUp);
 -		CASE_MSG_RET(WM_LBUTTONDBLCLK, clcOnLButtonDblClick);
 -		CASE_MSG_RET(WM_DESTROY, clcOnDestroy);
 -
 -	default:
 -		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
 -	}
 -	return TRUE;
 -}
 +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 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. +*/ + +/************************************************************************/ +/*       Module responsible for working with contact list control       */ +/************************************************************************/ + +#include "hdr/modern_commonheaders.h" +#include "m_skin.h" +#include "hdr/modern_commonprototypes.h" + +#include "hdr/modern_clc.h" +#include "hdr/modern_clist.h" +#include "hdr/modern_clcpaint.h" + +#include "m_modernopt.h" + +int ModernOptInit(WPARAM wParam, LPARAM lParam); +int ModernSkinOptInit(WPARAM wParam, LPARAM lParam); + +/* +*	Private module variables +*/ +static HANDLE	hShowInfoTipEvent; +static POINT	HitPoint; +static BOOL		fMouseUpped; +static BYTE		IsDragToScrollMode = 0; +static int		StartDragPos = 0; +static int		StartScrollPos = 0; +HANDLE			hAckHook = NULL; +HANDLE			hAvatarChanged = NULL; +static BOOL		g_bSortTimerIsSet = FALSE; +static ClcContact *hitcontact = NULL; +HANDLE hSkinFolder; +TCHAR SkinsFolder[MAX_PATH]; + +static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam); +static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam); +static int clcHookBkgndConfigChanged(WPARAM wParam, LPARAM lParam); +static int clcProceedDragToScroll(HWND hwnd, int Y); +static int clcExitDragToScroll(); + + +int ReloadSkinFolder(WPARAM wParam, LPARAM lParam) +{ +	FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER)); +	return 0; +} + +static int clcHookModulesLoaded(WPARAM wParam, LPARAM lParam) +{ +	if (MirandaExiting()) +		return 0; + +	HookEvent(ME_MODERNOPT_INITIALIZE, ModernOptInit); +	HookEvent(ME_MODERNOPT_INITIALIZE, ModernSkinOptInit); + +	HookEvent(ME_FOLDERS_PATH_CHANGED, ReloadSkinFolder); +	hSkinFolder = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("Modern contact list"), MIRANDA_PATHT _T("\\") _T(DEFAULT_SKIN_FOLDER)); +	FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER)); + +	// Get icons +	TCHAR szMyPath[MAX_PATH]; +	GetModuleFileName(g_hInst, szMyPath, SIZEOF(szMyPath)); + +	SKINICONDESC sid = { sizeof(sid) }; +	sid.cx = sid.cy = 16; +	sid.ptszDefaultFile = szMyPath; +	sid.flags = SIDF_PATH_TCHAR; + +	sid.pszSection = LPGEN("Contact list"); +	sid.pszDescription = LPGEN("Listening to"); +	sid.pszName = "LISTENING_TO_ICON"; +	sid.iDefaultIndex = -IDI_LISTENING_TO; +	Skin_AddIcon(&sid); + +	sid.pszSection = LPGEN("Contact list") "/" LPGEN("Avatar overlay"); +	for (int i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) { +		sid.pszDescription = g_pAvatarOverlayIcons[i].description; +		sid.pszName = g_pAvatarOverlayIcons[i].name; +		sid.iDefaultIndex = -g_pAvatarOverlayIcons[i].id; +		Skin_AddIcon(&sid); +	} + +	sid.pszSection = LPGEN("Contact list") "/" LPGEN("Status overlay"); +	for (int i = 0; i < SIZEOF(g_pStatusOverlayIcons); i++) { +		sid.pszDescription = g_pStatusOverlayIcons[i].description; +		sid.pszName = g_pStatusOverlayIcons[i].name; +		sid.iDefaultIndex = -g_pStatusOverlayIcons[i].id; +		Skin_AddIcon(&sid); +	} + +	clcHookIconsChanged(0, 0); + +	HookEvent(ME_SKIN2_ICONSCHANGED, clcHookIconsChanged); + +	// Register smiley category +	if (ServiceExists(MS_SMILEYADD_REGISTERCATEGORY)) { +		SMADD_REGCAT rc; +		rc.cbSize = sizeof(rc); +		rc.name = "clist"; +		rc.dispname = Translate("Contact list smileys"); + +		CallService(MS_SMILEYADD_REGISTERCATEGORY, 0, (LPARAM)&rc); + +		HookEvent(ME_SMILEYADD_OPTIONSCHANGED, clcHookSmileyAddOptionsChanged); +	} + +	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("List background")"/CLC"), 0); +	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Menu background")"/Menu"), 0); +	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Status bar background")"/StatusBar"), 0); +	CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Frames title bar background")"/FrameTitleBar"), 0); + +	HookEvent(ME_BACKGROUNDCONFIG_CHANGED, clcHookBkgndConfigChanged); +	HookEvent(ME_BACKGROUNDCONFIG_CHANGED, BgStatusBarChange); +	HookEvent(ME_BACKGROUNDCONFIG_CHANGED, OnFrameTitleBarBackgroundChange); +	HookEvent(ME_COLOUR_RELOAD, OnFrameTitleBarBackgroundChange); + +	AniAva_UpdateOptions(); +	return 0; +} + +static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam) +{ +	if (MirandaExiting()) return 0; +	pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0); +	pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0); +	return 0; +} + +static int clcHookProtoAck(WPARAM wParam, LPARAM lParam) +{ +	return ClcDoProtoAck(wParam, (ACKDATA*)lParam); +} + +static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam) +{ +	int i; +	if (MirandaExiting()) return 0; +	for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) { +		g_pAvatarOverlayIcons[i].listID = -1; +		g_pStatusOverlayIcons[i].listID = -1; +	} + +	if (hAvatarOverlays) +		ImageList_Destroy(hAvatarOverlays); +	hAvatarOverlays = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, SIZEOF(g_pAvatarOverlayIcons) * 2, 1); + +	for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) { +		HICON hIcon = Skin_GetIcon(g_pAvatarOverlayIcons[i].name); +		g_pAvatarOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon); +		Skin_ReleaseIcon(g_pAvatarOverlayIcons[i].name); + +		hIcon = Skin_GetIcon(g_pStatusOverlayIcons[i].name); +		g_pStatusOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon); +		Skin_ReleaseIcon(g_pStatusOverlayIcons[i].name); +	} + +	g_hListeningToIcon = Skin_GetIcon("LISTENING_TO_ICON"); + +	pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0); +	AniAva_UpdateOptions(); +	return 0; +} + +static int clcMetaModeChanged(WPARAM, LPARAM) +{ +	pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0); +	return 0; +} + +static int clcMetacontactChanged(WPARAM hMeta, LPARAM) +{ +	pcli->pfnClcBroadcast(INTM_NAMEORDERCHANGED, 0, 0); +	return 0; +} + +static int clcHookSettingChanged(WPARAM hContact, LPARAM lParam) +{ +	if (MirandaExiting()) +		return 0; + +	DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; +	if (hContact == NULL) { +		if (!mir_strcmp(cws->szModule, "CListGroups")) +			pcli->pfnClcBroadcast(INTM_GROUPSCHANGED, hContact, lParam); +		else if (!strcmp(cws->szSetting, "XStatusId") || !strcmp(cws->szSetting, "XStatusName")) +			cliCluiProtocolStatusChanged(0, cws->szModule); +	} +	else // hContact != NULL +	{ +		if (!strcmp(cws->szSetting, "TickTS")) +			pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0); +		else if (!strcmp(cws->szModule, "UserInfo")) { +			if (!strcmp(cws->szSetting, "Timezone")) +				pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0); +		} +		else if (!strcmp(cws->szModule, "CList")) { +			if (!strcmp(cws->szSetting, "StatusMsg")) +				pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0); + +		} +		else if (!strcmp(cws->szModule, "ContactPhoto")) { +			if (!strcmp(cws->szSetting, "File")) +				pcli->pfnClcBroadcast(INTM_AVATARCHANGED, hContact, 0); +		} +		else { +			if ((!strcmp(cws->szSetting, "XStatusName") || !strcmp(cws->szSetting, "XStatusMsg"))) +				pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0); +			else if (!strcmp(cws->szSetting, "XStatusId")) +				pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0); +			else if (!strcmp(cws->szSetting, "Timezone")) +				pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0); +			else if (!strcmp(cws->szSetting, "ListeningTo")) +				pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0); +			else if (!strcmp(cws->szSetting, "Transport") || !strcmp(cws->szSetting, "IsTransported")) { +				pcli->pfnInvalidateDisplayNameCacheEntry(hContact); +				pcli->pfnClcBroadcast(CLM_AUTOREBUILD, hContact, 0); +			} +		} +	} +	return 0; +} + +static int clcHookDbEventAdded(WPARAM hContact, LPARAM lParam) +{ +	g_CluiData.t_now = time(NULL); +	if (hContact && lParam) { +		DBEVENTINFO dbei = { sizeof(dbei) }; +		db_event_get((HANDLE)lParam, &dbei); +		if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) { +			db_set_dw(hContact, "CList", "mf_lastmsg", dbei.timestamp); +			ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact); +			if (pdnce) +				pdnce->dwLastMsgTime = dbei.timestamp; +		} +	} +	return 0; +} + +static int clcHookBkgndConfigChanged(WPARAM, LPARAM) +{ +	pcli->pfnClcOptionsChanged(); +	return 0; +} + +static int clcHookAvatarChanged(WPARAM wParam, LPARAM lParam) +{ +	if (MirandaExiting()) return 0; +	pcli->pfnClcBroadcast(INTM_AVATARCHANGED, wParam, lParam); +	return 0; +} + +static int clcExitDragToScroll() +{ +	if (!IsDragToScrollMode) return 0; +	IsDragToScrollMode = 0; +	ReleaseCapture(); +	return 1; +} + +static int clcProceedDragToScroll(HWND hwnd, int Y) +{ +	int pos, dy; +	if (!IsDragToScrollMode) return 0; +	if (GetCapture() != hwnd) clcExitDragToScroll(); +	dy = StartDragPos - Y; +	pos = StartScrollPos + dy; +	if (pos < 0) +		pos = 0; +	SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, pos), 0); +	return 1; +} + + + +static int clcSearchNextContact(HWND hwnd, ClcData *dat, int index, const TCHAR *text, int prefixOk, BOOL fSearchUp) +{ +	ClcGroup *group = &dat->list; +	int testlen = lstrlen(text); +	BOOL fReturnAsFound = FALSE; +	int	 nLastFound = -1; +	if (index == -1) fReturnAsFound = TRUE; +	group->scanIndex = 0; +	for (;;) { +		if (group->scanIndex == group->cl.count) { +			group = group->parent; +			if (group == NULL) +				break; +			group->scanIndex++; +			continue; +		} +		if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) { +			bool found; +			if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) { +				found = true; +			} +			else if (dat->filterSearch) { +				TCHAR *lowered_szText = CharLowerW(NEWTSTR_ALLOCA(group->cl.items[group->scanIndex]->szText)); +				TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch)); +				found = _tcsstr(lowered_szText, lowered_search) != NULL; +			} +			else { +				found = ((prefixOk && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, text, -1, group->cl.items[group->scanIndex]->szText, testlen)) || (!prefixOk && !lstrcmpi(text, group->cl.items[group->scanIndex]->szText))); +			} +			if (found) { +				ClcGroup *contactGroup = group; +				int contactScanIndex = group->scanIndex; +				int foundindex; +				for (; group; group = group->parent) +					pcli->pfnSetGroupExpand(hwnd, dat, group, 1); +				foundindex = pcli->pfnGetRowsPriorTo(&dat->list, contactGroup, contactScanIndex); +				if (fReturnAsFound) +					return foundindex; +				else if (nLastFound != -1 && fSearchUp && foundindex == index) +					return nLastFound; +				else if (!fSearchUp && foundindex == index) +					fReturnAsFound = TRUE; +				else +					nLastFound = foundindex; +				group = contactGroup; +				group->scanIndex = contactScanIndex; +			} +			if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) { +				if (!(dat->exStyle & CLS_EX_QUICKSEARCHVISONLY) || group->cl.items[group->scanIndex]->group->expanded) { +					group = group->cl.items[group->scanIndex]->group; +					group->scanIndex = 0; +					continue; +				} +			} +		} +		group->scanIndex++; +	} +	return -1; +} + +static BOOL clcItemNotHiddenOffline(ClcData *dat, ClcGroup* group, ClcContact *contact) +{ +	if (g_CluiData.bFilterEffective) return FALSE; + +	if (!contact) return FALSE; +	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact); +	if (!pdnce) return FALSE; +	if (pdnce->m_cache_nNoHiddenOffline) return TRUE; + +	if (!group) return FALSE; +	if (group->hideOffline) return FALSE; + +	if (CLCItems_IsShowOfflineGroup(group)) return TRUE; + +	return FALSE; +} + +static LRESULT clcOnCreate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	dat = (ClcData*)mir_calloc(sizeof(ClcData)); +	SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat); +	dat->hCheckBoxTheme = xpt_AddThemeHandle(hwnd, L"BUTTON"); +	dat->m_paintCouter = 0; +	dat->hWnd = hwnd; +	dat->use_avatar_service = ServiceExists(MS_AV_GETAVATARBITMAP); +	if (dat->use_avatar_service) +		if (!hAvatarChanged) +			hAvatarChanged = HookEvent(ME_AV_AVATARCHANGED, clcHookAvatarChanged); + +	ImageArray_Initialize(&dat->avatar_cache, FALSE, 20); //this array will be used to keep small avatars too + +	RowHeights_Initialize(dat); + +	dat->needsResort = 1; +	dat->MetaIgnoreEmptyExtra = db_get_b(NULL, "CLC", "MetaIgnoreEmptyExtra", SETTING_METAIGNOREEMPTYEXTRA_DEFAULT); + +	dat->IsMetaContactsEnabled = (!(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_MANUALUPDATE)) && db_mc_isEnabled(); + +	dat->expandMeta = db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT); +	dat->useMetaIcon = db_get_b(NULL, "CLC", "Meta", SETTING_USEMETAICON_DEFAULT); +	dat->drawOverlayedStatus = db_get_b(NULL, "CLC", "DrawOverlayedStatus", SETTING_DRAWOVERLAYEDSTATUS_DEFAULT); +	g_CluiData.bSortByOrder[0] = db_get_b(NULL, "CList", "SortBy1", SETTING_SORTBY1_DEFAULT); +	g_CluiData.bSortByOrder[1] = db_get_b(NULL, "CList", "SortBy2", SETTING_SORTBY2_DEFAULT); +	g_CluiData.bSortByOrder[2] = db_get_b(NULL, "CList", "SortBy3", SETTING_SORTBY3_DEFAULT); +	g_CluiData.fSortNoOfflineBottom = db_get_b(NULL, "CList", "NoOfflineBottom", SETTING_NOOFFLINEBOTTOM_DEFAULT); +	dat->menuOwnerID = -1; +	dat->menuOwnerType = CLCIT_INVALID; + +	corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +	LoadCLCOptions(hwnd, dat, TRUE); +	if (dat->contact_time_show || dat->second_line_type == TEXT_CONTACT_TIME || dat->third_line_type == TEXT_CONTACT_TIME) +		CLUI_SafeSetTimer(hwnd, TIMERID_INVALIDATE, 5000, NULL); +	else +		KillTimer(hwnd, TIMERID_INVALIDATE); + +	TRACE("Create New ClistControl TO END\r\n"); +	return 0; +} + +static LRESULT clcOnHitTest(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	return DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam); +} + +static LRESULT clcOnCommand(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	ClcContact *contact; +	int hit = pcli->pfnGetRowByIndex(dat, dat->selection, &contact, NULL); +	if (hit == -1)	return 0; +	if (contact->type == CLCIT_CONTACT && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), contact->hContact))	return 0; + +	switch (LOWORD(wParam)) { +	case POPUP_NEWSUBGROUP: +		if (contact->type != CLCIT_GROUP) +			return 0; +		SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS); +		SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | CLS_USEGROUPS); +		CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0); +		return 0; +	case POPUP_RENAMEGROUP: +		pcli->pfnBeginRenameSelection(hwnd, dat); +		return 0; +	case POPUP_DELETEGROUP: +		if (contact->type == CLCIT_GROUP) +			CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0); +		return 0; +	case POPUP_GROUPSHOWOFFLINE: +		if (contact->type == CLCIT_GROUP) { +			CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(CLCItems_IsShowOfflineGroup(contact->group) ? 0 : GROUPF_SHOWOFFLINE, GROUPF_SHOWOFFLINE)); +			pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0); +		} +		return 0; +	case POPUP_GROUPHIDEOFFLINE: +		if (contact->type == CLCIT_GROUP) +			CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE)); +		return 0; +	} + +	if (contact->type == CLCIT_GROUP) +		if (CallService(MO_PROCESSCOMMANDBYMENUIDENT, LOWORD(wParam), (LPARAM)hwnd)) +			return 0; + +	return 0; +} + +static LRESULT clcOnSize(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	pcli->pfnEndRename(hwnd, dat, 1); +	KillTimer(hwnd, TIMERID_INFOTIP); +	KillTimer(hwnd, TIMERID_RENAME); +	cliRecalcScrollBar(hwnd, dat); +	if (g_CluiData.fDisableSkinEngine || dat->force_in_dialog) { +		RECT rc = { 0 }; +		GetClientRect(hwnd, &rc); +		if (rc.right == 0) +			return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +		rc.bottom = max(dat->row_min_heigh, 1); + +		HDC hdc = GetDC(hwnd); +		int depth = GetDeviceCaps(hdc, BITSPIXEL); +		if (depth < 16) +			depth = 16; +		HBITMAP hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL); +		HBITMAP hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL); +		HDC hdcMem = CreateCompatibleDC(hdc); +		HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); +		HBRUSH hBrush = CreateSolidBrush((dat->useWindowsColours || dat->force_in_dialog) ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour); +		FillRect(hdcMem, &rc, hBrush); +		DeleteObject(hBrush); + +		HBITMAP hoMaskBmp = (HBITMAP)SelectObject(hdcMem, hBmpMask); +		FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); +		SelectObject(hdcMem, hoMaskBmp); +		SelectObject(hdcMem, hoBmp); +		DeleteDC(hdcMem); +		ReleaseDC(hwnd, hdc); +		if (dat->himlHighlight) +			ImageList_Destroy(dat->himlHighlight); +		dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, ILC_COLOR32 | ILC_MASK, 1, 1); +		ImageList_Add(dat->himlHighlight, hBmp, hBmpMask); +		DeleteObject(hBmpMask); +		DeleteObject(hBmp); +	} +	else if (dat->himlHighlight) { +		ImageList_Destroy(dat->himlHighlight); +		dat->himlHighlight = NULL; +	} +	return 0; +} + +static LRESULT clcOnChar(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	if (wParam == 27 && dat->szQuickSearch[0] == '\0') { //escape and not quick search +		// minimize clist +		CListMod_HideWindow(pcli->hwndContactList, SW_HIDE); +	} +	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +} +static LRESULT clcOnPaint(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	if (IsWindowVisible(hwnd)) { +		if (!g_CluiData.fLayered || GetParent(hwnd) != pcli->hwndContactList) { +			PAINTSTRUCT ps; +			HDC hdc = BeginPaint(hwnd, &ps); +			g_clcPainter.cliPaintClc(hwnd, dat, hdc, &ps.rcPaint); +			EndPaint(hwnd, &ps); +		} +		else CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, (WPARAM)hwnd, 0); +	} +	return DefWindowProc(hwnd, msg, wParam, lParam); +} + +static LRESULT clcOnEraseBkGround(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	return 1; +} + +static LRESULT clcOnKeyDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	if (wParam == VK_CONTROL) +		return 0; + +	pcli->pfnHideInfoTip(hwnd, dat); +	KillTimer(hwnd, TIMERID_INFOTIP); +	KillTimer(hwnd, TIMERID_RENAME); + +	if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU)) +		return 0; + +	RECT clRect; +	GetClientRect(hwnd, &clRect); +	int pageSize = (dat->rowHeight) ? clRect.bottom / dat->rowHeight : 0; +	int selMoved = 0; +	int changeGroupExpand = 0; + +	switch (wParam) { +	case VK_DOWN: +	case VK_UP: +		if (dat->szQuickSearch[0] != '\0' && dat->selection != -1) { //get next contact +			//get next contact +			int index = clcSearchNextContact(hwnd, dat, dat->selection, dat->szQuickSearch, 1, (wParam == VK_UP)); +			if (index == -1) { +				MessageBeep(MB_OK); +				return 0; +			} + +			dat->selection = index; +			pcli->pfnInvalidateRect(hwnd, NULL, FALSE); +			pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0); +			return 0; +		} + +		if (wParam == VK_DOWN) dat->selection++; +		if (wParam == VK_UP) dat->selection--; +		selMoved = 1; +		break; + +	case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break; +	case VK_NEXT: dat->selection += pageSize; selMoved = 1; break; +	case VK_HOME: dat->selection = 0; selMoved = 1; break; +	case VK_END: dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break; +	case VK_LEFT: changeGroupExpand = 1; break; +	case VK_RIGHT: changeGroupExpand = 2; break; +	case VK_RETURN: +		pcli->pfnDoSelectionDefaultAction(hwnd, dat); +		SetCapture(hwnd); +		dat->szQuickSearch[0] = 0; +		if (dat->filterSearch) +			pcli->pfnSaveStateAndRebuildList(hwnd, dat); +		return 0; + +	case VK_F2: cliBeginRenameSelection(hwnd, dat); /*SetCapture(hwnd);*/ return 0; +	case VK_DELETE: pcli->pfnDeleteFromContactList(hwnd, dat); SetCapture(hwnd); return 0; +	case VK_ESCAPE: +		if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) { +			dat->iDragItem = -1; +			dat->iInsertionMark = -1; +			dat->dragStage = 0; +			ReleaseCapture(); +		} +		return 0; + +	default: +		NMKEY nmkey; +		nmkey.hdr.hwndFrom = hwnd; +		nmkey.hdr.idFrom = GetDlgCtrlID(hwnd); +		nmkey.hdr.code = NM_KEYDOWN; +		nmkey.nVKey = wParam; +		nmkey.uFlags = HIWORD(lParam); + +		if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nmkey)) { +			SetCapture(hwnd); +			return 0; +		} +	} + +	if (changeGroupExpand) { +		ClcContact *contact; +		ClcGroup *group; +		int hit = cliGetRowByIndex(dat, dat->selection, &contact, &group); +		if (hit == -1) { +			SetCapture(hwnd); +			return 0; +		} + +		if (contact->type == CLCIT_CONTACT && (contact->isSubcontact || contact->SubAllocated > 0)) { +			if (contact->isSubcontact && changeGroupExpand == 1) { +				dat->selection -= contact->isSubcontact; +				selMoved = 1; +			} +			else if (!contact->isSubcontact && contact->SubAllocated > 0) { +				if (changeGroupExpand == 1 && !contact->SubExpanded) { +					dat->selection = cliGetRowsPriorTo(&dat->list, group, -1); +					selMoved = 1; +				} +				else if (changeGroupExpand == 1 && contact->SubExpanded) { +					//Contract +					ClcContact *ht = NULL; +					KillTimer(hwnd, TIMERID_SUBEXPAND); +					contact->SubExpanded = 0; +					db_set_b(contact->hContact, "CList", "Expanded", 0); +					ht = contact; +					dat->needsResort = 1; +					pcli->pfnSortCLC(hwnd, dat, 1); +					cliRecalcScrollBar(hwnd, dat); +					hitcontact = NULL; +				} +				else if (changeGroupExpand == 2 && contact->SubExpanded) { +					dat->selection++; +					selMoved = 1; +				} +				else if (changeGroupExpand == 2 && !contact->SubExpanded && dat->expandMeta) { +					ClcContact *ht = NULL; +					KillTimer(hwnd, TIMERID_SUBEXPAND); +					contact->SubExpanded = 1; +					db_set_b(contact->hContact, "CList", "Expanded", 1); +					ht = contact; +					dat->needsResort = 1; +					pcli->pfnSortCLC(hwnd, dat, 1); +					cliRecalcScrollBar(hwnd, dat); +					if (ht) { +						ClcContact *contact2; +						ClcGroup *group2; +						if (FindItem(hwnd, dat, contact->hContact, &contact2, &group2, NULL, FALSE)) { +							int i = cliGetRowsPriorTo(&dat->list, group2, GetContactIndex(group2, contact2)); +							pcli->pfnEnsureVisible(hwnd, dat, i + contact->SubAllocated, 0); +						} +					} +					hitcontact = NULL; +				} +			} +		} +		else { +			if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) { +				if (group == &dat->list) { SetCapture(hwnd); return 0; } +				dat->selection = cliGetRowsPriorTo(&dat->list, group, -1); +				selMoved = 1; +			} +			else { +				if (contact->type == CLCIT_GROUP) { +					if (changeGroupExpand == 1) { +						if (!contact->group->expanded) { +							dat->selection--; +							selMoved = 1; +						} +						else pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 0); +					} +					else if (changeGroupExpand == 2) { +						pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 1); +						dat->selection++; +						selMoved = 1; +					} +					else { SetCapture(hwnd); return 0; } +				} +			} +		} +	} +	if (selMoved) { +		if (dat->selection >= pcli->pfnGetGroupContentsCount(&dat->list, 1)) +			dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1; +		if (dat->selection < 0) dat->selection = 0; +		if (dat->bCompactMode) +			SendMessage(hwnd, WM_SIZE, 0, 0); +		CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +		pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0); +		UpdateWindow(hwnd); +		SetCapture(hwnd); +		return 0; +	} +	SetCapture(hwnd); +	return 0; +} + +void clcSetDelayTimer(UINT_PTR uIDEvent, HWND hwnd, int nDelay) +{ +	KillTimer(hwnd, uIDEvent); +	int delay = nDelay; +	if (delay == -1) { +		switch (uIDEvent) { +			case TIMERID_DELAYEDRESORTCLC: delay = 10;  break; +			case TIMERID_RECALCSCROLLBAR:  delay = 10;  break; +			case TIMERID_REBUILDAFTER:     delay = 50;  break; +			default:                       delay = 100; break; +		} +	} +	CLUI_SafeSetTimer(hwnd, uIDEvent, delay, NULL); +} + +static LRESULT clcOnTimer(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	switch (wParam) { +	case TIMERID_INVALIDATE_FULL: +		KillTimer(hwnd, TIMERID_INVALIDATE_FULL); +		pcli->pfnRecalcScrollBar(hwnd, dat); +		pcli->pfnInvalidateRect(hwnd, NULL, 0); +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +	case TIMERID_INVALIDATE: +		{ +			time_t cur_time = (time(NULL) / 60); +			if (cur_time != dat->last_tick_time) { +				CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +				dat->last_tick_time = cur_time; +			} +		} +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +	case TIMERID_SUBEXPAND: +		KillTimer(hwnd, TIMERID_SUBEXPAND); +		{ +			ClcContact *ht = NULL; +			if (hitcontact && dat->expandMeta) { +				if (hitcontact->SubExpanded) hitcontact->SubExpanded = 0; else hitcontact->SubExpanded = 1; +				db_set_b(hitcontact->hContact, "CList", "Expanded", hitcontact->SubExpanded); +				if (hitcontact->SubExpanded) +					ht = &(hitcontact->subcontacts[hitcontact->SubAllocated - 1]); +			} + +			dat->needsResort = 1; +			pcli->pfnSortCLC(hwnd, dat, 1); +			cliRecalcScrollBar(hwnd, dat); +			if (ht) { +				int i = 0; +				ClcContact *contact; +				ClcGroup *group; +				if (FindItem(hwnd, dat, hitcontact->hContact, &contact, &group, NULL, FALSE)) { +					i = cliGetRowsPriorTo(&dat->list, group, GetContactIndex(group, contact)); +					pcli->pfnEnsureVisible(hwnd, dat, i + hitcontact->SubAllocated, 0); +				} +			} +			hitcontact = NULL; +		} +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +	case TIMERID_DELAYEDRESORTCLC: +		TRACE("Do sort on Timer\n"); +		KillTimer(hwnd, TIMERID_DELAYEDRESORTCLC); +		pcli->pfnSortCLC(hwnd, dat, 1); +		pcli->pfnInvalidateRect(hwnd, NULL, FALSE); +		return 0; + +	case TIMERID_RECALCSCROLLBAR: +		KillTimer(hwnd, TIMERID_RECALCSCROLLBAR); +		pcli->pfnRecalcScrollBar(hwnd, dat); +		return 0; + +	default: +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +	} +	return 0; +} + + +static LRESULT clcOnActivate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	TRACE("clcOnActivate\n"); +	if (dat->bCompactMode) { +		cliRecalcScrollBar(hwnd, dat); +		if (dat->hwndRenameEdit == NULL) +			PostMessage(hwnd, WM_SIZE, 0, 0); +	} +	dat->dragStage |= DRAGSTAGEF_SKIPRENAME; +	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +} + +static LRESULT clcOnSetCursor(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	if (!CLUI_IsInMainWindow(hwnd)) +		return DefWindowProc(hwnd, msg, wParam, lParam); + +	if (g_CluiData.nBehindEdgeState > 0) +		CLUI_ShowFromBehindEdge(); + +	if (g_CluiData.bBehindEdgeSettings) +		CLUI_UpdateTimer(0); + +	int lResult = CLUI_TestCursorOnBorders(); +	return lResult ? lResult : DefWindowProc(hwnd, msg, wParam, lParam); +} + +static LRESULT clcOnLButtonDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	POINT pt = { LOWORD(lParam), HIWORD(lParam) }; +	ClientToScreen(hwnd, &pt); +	int k = CLUI_SizingOnBorder(pt, 0); +	if (k) { +		int io = dat->iHotTrack; +		dat->iHotTrack = 0; +		if (dat->exStyle & CLS_EX_TRACKSELECT) +			pcli->pfnInvalidateItem(hwnd, dat, io); + +		if (k && GetCapture() == hwnd) +			SendMessage(GetParent(hwnd), WM_PARENTNOTIFY, WM_LBUTTONDOWN, lParam); +		return FALSE; +	} + +	fMouseUpped = FALSE; +	pcli->pfnHideInfoTip(hwnd, dat); +	KillTimer(hwnd, TIMERID_INFOTIP); +	KillTimer(hwnd, TIMERID_RENAME); +	KillTimer(hwnd, TIMERID_SUBEXPAND); + +	pcli->pfnEndRename(hwnd, dat, 1); +	dat->ptDragStart.x = (short)LOWORD(lParam); +	dat->ptDragStart.y = (short)HIWORD(lParam); + +	ClcContact *contact; +	ClcGroup *group; +	DWORD hitFlags; +	int hit = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), &contact, &group, &hitFlags); +	if (GetFocus() != hwnd) +		SetFocus(hwnd); +	if (hit != -1 && !(hitFlags & CLCHT_NOWHERE)) { +		if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) { +			if (!(dat->dragStage & DRAGSTAGEF_SKIPRENAME)) { +				SetCapture(hwnd); +				dat->iDragItem = dat->selection; +				dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME; +				dat->dragAutoScrolling = 0; +				return TRUE; +			} +			else { +				dat->dragStage &= ~DRAGSTAGEF_SKIPRENAME; +				return TRUE; +			} +		} +	} + +	if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_CONTACT && contact->SubAllocated && !contact->isSubcontact) +		if (hitFlags & CLCHT_ONITEMICON && dat->expandMeta) { +			BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT); + +			hitcontact = contact; +			HitPoint.x = (short)LOWORD(lParam); +			HitPoint.y = (short)HIWORD(lParam); +			fMouseUpped = FALSE; +			if ((GetKeyState(VK_SHIFT) & 0x8000) || (GetKeyState(VK_CONTROL) & 0x8000) || (GetKeyState(VK_MENU) & 0x8000)) { +				fMouseUpped = TRUE; +				hitcontact = contact; +				KillTimer(hwnd, TIMERID_SUBEXPAND); +				CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL); +			} +		} +		else hitcontact = NULL; + +		if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_GROUP && (hitFlags & CLCHT_ONITEMICON)) { +			ClcGroup *selgroup; +			ClcContact *selcontact; +			dat->selection = cliGetRowByIndex(dat, dat->selection, &selcontact, &selgroup); +			pcli->pfnSetGroupExpand(hwnd, dat, contact->group, -1); +			if (dat->selection != -1) { +				dat->selection = cliGetRowsPriorTo(&dat->list, selgroup, GetContactIndex(selgroup, selcontact)); +				if (dat->selection == -1) +					dat->selection = cliGetRowsPriorTo(&dat->list, contact->group, -1); +			} + +			if (dat->bCompactMode) +				SendMessage(hwnd, WM_SIZE, 0, 0); +			else { +				CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +				UpdateWindow(hwnd); +			} +			return TRUE; +		} + +		if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && (hitFlags & CLCHT_ONITEMCHECK)) { +			int bNewState = (contact->flags & CONTACTF_CHECKED) == 0; // inversion + +			if (contact->type == CLCIT_GROUP) +				pcli->pfnSetGroupChildCheckboxes(contact->group, bNewState); +			else +				pcli->pfnSetContactCheckboxes(contact, bNewState); +			pcli->pfnRecalculateGroupCheckboxes(hwnd, dat); +			CLUI__cliInvalidateRect(hwnd, NULL, FALSE); + +			NMCLISTCONTROL nm; +			nm.hdr.code = CLN_CHECKCHANGED; +			nm.hdr.hwndFrom = hwnd; +			nm.hdr.idFrom = GetDlgCtrlID(hwnd); +			nm.flags = 0; +			nm.hItem = ContactToItemHandle(contact, &nm.flags); +			SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm); +		} + +		if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) { +			NMCLISTCONTROL nm; +			nm.hdr.code = NM_CLICK; +			nm.hdr.hwndFrom = hwnd; +			nm.hdr.idFrom = GetDlgCtrlID(hwnd); +			nm.flags = 0; +			nm.hItem = (hit == -1 || hitFlags & CLCHT_NOWHERE) ? NULL : ContactToItemHandle(contact, &nm.flags); +			nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1; +			nm.pt = dat->ptDragStart; +			SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm); +		} + +		if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA)) +			return FALSE; + +		dat->selection = (hitFlags & CLCHT_NOWHERE) ? -1 : hit; +		CLUI__cliInvalidateRect(hwnd, NULL, FALSE); + +		UpdateWindow(hwnd); +		if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP) && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK | CLCHT_NOWHERE))) { +			SetCapture(hwnd); +			dat->iDragItem = dat->selection; +			dat->dragStage = DRAGSTAGE_NOTMOVED; +			dat->dragAutoScrolling = 0; +		} + +		if (dat->bCompactMode) +			SendMessage(hwnd, WM_SIZE, 0, 0); + +		if (dat->selection != -1) +			pcli->pfnEnsureVisible(hwnd, dat, hit, 0); +		return TRUE; +} + +static LRESULT clcOnCaptureChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	if ((HWND)lParam != hwnd) { +		if (dat->iHotTrack != -1) { +			int i; +			i = dat->iHotTrack; +			dat->iHotTrack = -1; +			pcli->pfnInvalidateItem(hwnd, dat, i); +			pcli->pfnHideInfoTip(hwnd, dat); +		} +	} +	return 0; +} + +static LRESULT clcOnMouseMove(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	BOOL isOutside = FALSE; +	if (CLUI_IsInMainWindow(hwnd)) { +		if (g_CluiData.bBehindEdgeSettings) +			CLUI_UpdateTimer(0); +		CLUI_TestCursorOnBorders(); +	} + +	if (clcProceedDragToScroll(hwnd, (short)HIWORD(lParam))) +		return 0; + +	if (dat->dragStage & DRAGSTAGEF_MAYBERENAME) { +		POINT pt = UNPACK_POINT(lParam); +		if (abs(pt.x - dat->ptDragStart.x) > GetSystemMetrics(SM_CXDOUBLECLK) || abs(pt.y - dat->ptDragStart.y) > GetSystemMetrics(SM_CYDOUBLECLK)) { +			KillTimer(hwnd, TIMERID_RENAME); +			dat->dragStage &= (~DRAGSTAGEF_MAYBERENAME); +		} +	} + +	if (dat->iDragItem == -1) { +		POINT pt = UNPACK_POINT(lParam); +		ClientToScreen(hwnd, &pt); +		HWND window = WindowFromPoint(pt); +		if (window != hwnd) +			isOutside = TRUE; +	} + +	if (hitcontact != NULL) { +		int x = (short)LOWORD(lParam); +		int y = (short)HIWORD(lParam); +		int xm = GetSystemMetrics(SM_CXDOUBLECLK); +		int ym = GetSystemMetrics(SM_CYDOUBLECLK); +		if (abs(HitPoint.x - x) > xm || abs(HitPoint.y - y) > ym) { +			if (fMouseUpped) { +				KillTimer(hwnd, TIMERID_SUBEXPAND); +				CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL); +				fMouseUpped = FALSE; +			} +			else { +				KillTimer(hwnd, TIMERID_SUBEXPAND); +				hitcontact = NULL; +				fMouseUpped = FALSE; +			} +		} +	} + +	if (dat->iDragItem == -1) { +		DWORD flag = 0; +		int iOldHotTrack = dat->iHotTrack; + +		if (dat->hwndRenameEdit != NULL || GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000) +			return 0; + +		dat->iHotTrack = isOutside ? -1 : cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flag); + +		if (flag & CLCHT_NOWHERE) +			dat->iHotTrack = -1; + +		if (iOldHotTrack != dat->iHotTrack || isOutside) { +			if (iOldHotTrack == -1 && !isOutside) +				SetCapture(hwnd); + +			if (dat->iHotTrack == -1 || isOutside) +				ReleaseCapture(); + +			if (dat->exStyle & CLS_EX_TRACKSELECT) { +				pcli->pfnInvalidateItem(hwnd, dat, iOldHotTrack); +				pcli->pfnInvalidateItem(hwnd, dat, dat->iHotTrack); +			} + +			pcli->pfnHideInfoTip(hwnd, dat); +		} + +		KillTimer(hwnd, TIMERID_INFOTIP); + +		if (wParam == 0 && dat->hInfoTipItem == NULL) { +			dat->ptInfoTip.x = (short)LOWORD(lParam); +			dat->ptInfoTip.y = (short)HIWORD(lParam); +			CLUI_SafeSetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL); +		} +		return 0; +	} + +	if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP)) +		if (abs((short)LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG) || abs((short)HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG)) +			dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE; + +	if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) { +		RECT clRect; +		GetClientRect(hwnd, &clRect); + +		POINT pt = UNPACK_POINT(lParam); +		HCURSOR hNewCursor = LoadCursor(NULL, IDC_NO); +		CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +		if (dat->dragAutoScrolling) { +			KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL); +			dat->dragAutoScrolling = 0; +		} +		int target = GetDropTargetInformation(hwnd, dat, pt); +		if ((dat->dragStage & DRAGSTAGEF_OUTSIDE) && target != DROPTARGET_OUTSIDE) { +			ClcContact *contact; +			cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL); + +			NMCLISTCONTROL nm; +			nm.hdr.code = CLN_DRAGSTOP; +			nm.hdr.hwndFrom = hwnd; +			nm.hdr.idFrom = GetDlgCtrlID(hwnd); +			nm.flags = 0; +			nm.hItem = ContactToItemHandle(contact, &nm.flags); +			SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm); +			dat->dragStage &= ~DRAGSTAGEF_OUTSIDE; +		} + +		ClcContact *contSour, *contDest; + +		switch (target) { +		case DROPTARGET_ONSELF: +			break; + +		case DROPTARGET_ONCONTACT: +			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL); +			if (contSour->isChat()) +				break; +			if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) { +				if (!contSour->isSubcontact) +					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));  /// Add to meta +				else +					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DROPMETA)); +			} +			break; + +		case DROPTARGET_ONMETACONTACT: +			cliGetRowByIndex(dat, dat->selection, &contDest, NULL); +			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL); +			if (contSour->isChat() || contDest->isChat()) +				break; +			if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) { +				if (!contSour->isSubcontact) +					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));  /// Add to meta +				else if (contSour->subcontacts == contDest) +					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DEFAULTSUB)); ///MakeDefault +				else +					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP)); +			} +			break; + +		case DROPTARGET_ONSUBCONTACT: +			cliGetRowByIndex(dat, dat->selection, &contDest, NULL); +			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL); +			if (contSour->isChat() || contDest->isChat()) +				break; +			if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) { +				if (!contSour->isSubcontact) +					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));  /// Add to meta +				else if (contDest->subcontacts == contSour->subcontacts) +					break; +				else +					hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP)); +			} +			break; + +		case DROPTARGET_ONGROUP: +			hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); +			break; + +		case DROPTARGET_INSERTION: +			hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROP)); +			break; + +		case DROPTARGET_OUTSIDE: +			if (pt.x >= 0 && pt.x < clRect.right && ((pt.y < 0 && pt.y>-dat->dragAutoScrollHeight) || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) { +				if (!dat->dragAutoScrolling) { +					dat->dragAutoScrolling = (pt.y < 0) ? -1 : 1; +					CLUI_SafeSetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL); +				} +				SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0); +			} + +			dat->dragStage |= DRAGSTAGEF_OUTSIDE; +			{ +				ClcContact *contact; +				cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL); + +				NMCLISTCONTROL nm; +				nm.hdr.code = CLN_DRAGGING; +				nm.hdr.hwndFrom = hwnd; +				nm.hdr.idFrom = GetDlgCtrlID(hwnd); +				nm.flags = 0; +				nm.hItem = ContactToItemHandle(contact, &nm.flags); +				nm.pt = pt; +				if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm)) +					return 0; +			} +			break; + +		default: +			ClcGroup *group = NULL; +			cliGetRowByIndex(dat, dat->iDragItem, NULL, &group); +			if (group && group->parent) { +				ClcContact *contSour; +				cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL); +				if (!contSour->isSubcontact) +					hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); +			} +			break; +		} +		SetCursor(hNewCursor); +	} +	return 0; +} + +static LRESULT clcOnLButtonUp(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	if (clcExitDragToScroll()) +		return 0; + +	fMouseUpped = TRUE; + +	if (hitcontact != NULL && dat->expandMeta) { +		BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT); +		CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, GetDoubleClickTime()*doubleClickExpand, NULL); +	} +	else if (dat->iHotTrack == -1 && dat->iDragItem == -1) +		ReleaseCapture(); + +	if (dat->iDragItem == -1) +		return 0; + +	SetCursor((HCURSOR)GetClassLongPtr(hwnd, GCLP_HCURSOR)); +	if (dat->exStyle & CLS_EX_TRACKSELECT) { +		DWORD flags; +		dat->iHotTrack = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flags); +		if (dat->iHotTrack == -1) +			ReleaseCapture(); +	} +	else if (hitcontact == NULL) +		ReleaseCapture(); +	KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL); +	if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME)) +		CLUI_SafeSetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL); +	else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) { +		TCHAR Wording[500]; +		ClcContact *contDest, *contSour; +		POINT pt = UNPACK_POINT(lParam); +		int target = GetDropTargetInformation(hwnd, dat, pt); +		switch (target) { +		case DROPTARGET_ONSELF: +			break; + +		case DROPTARGET_ONCONTACT: +			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL); +			cliGetRowByIndex(dat, dat->selection, &contDest, NULL); +			if (contSour->isChat() || contDest->isChat()) +				break; +			if (contSour->type == CLCIT_CONTACT) { +				MCONTACT hcontact = contSour->hContact; +				if (mir_strcmp(contSour->proto, META_PROTO)) { +					if (!contSour->isSubcontact) { +						MCONTACT hDest = contDest->hContact; +						mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it?"), contDest->szText, contSour->szText); +						int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact"), MB_OKCANCEL | MB_ICONQUESTION); +						if (res == 1) { +							MCONTACT handle = CallService(MS_MC_CONVERTTOMETA, hDest, 0); +							if (!handle) +								return 0; + +							CallService(MS_MC_ADDTOMETA, hcontact, handle); +						} +					} +					else { +						hcontact = contSour->hContact; +						MCONTACT hfrom = contSour->subcontacts->hContact; +						MCONTACT hdest = contDest->hContact; +						mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it (remove it from '%s')?"), contDest->szText, contSour->szText, contSour->subcontacts->szText); +						int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact (moving)"), MB_OKCANCEL | MB_ICONQUESTION); +						if (res == 1) { +							MCONTACT handle = (MCONTACT)CallService(MS_MC_CONVERTTOMETA, (WPARAM)hdest, 0); +							if (!handle) +								return 0; + +							CallService(MS_MC_REMOVEFROMMETA, 0, hcontact); +							CallService(MS_MC_ADDTOMETA, hcontact, handle); +						} +					} +				} +			} +			break; + +		case DROPTARGET_ONMETACONTACT: +			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL); +			cliGetRowByIndex(dat, dat->selection, &contDest, NULL); +			if (contSour->isChat() || contDest->isChat()) +				break; +			if (contSour->type == CLCIT_CONTACT) { +				if (!strcmp(contSour->proto, META_PROTO)) +					break; +				if (!contSour->isSubcontact) { +					MCONTACT hcontact = contSour->hContact; +					MCONTACT handle = contDest->hContact; +					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->szText); +					int res = MessageBox(hwnd, Wording, TranslateT("Adding contact to metacontact"), MB_OKCANCEL | MB_ICONQUESTION); +					if (res == 1) { +						if (!handle) +							return 0; +						CallService(MS_MC_ADDTOMETA, hcontact, handle); +					} +				} +				else if (contSour->subcontacts == contDest) { +					MCONTACT hsour = contSour->hContact; +					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be default?"), contSour->szText); +					int res = MessageBox(hwnd, Wording, TranslateT("Set default contact"), MB_OKCANCEL | MB_ICONQUESTION); +					if (res == 1) +						db_mc_setDefault(contDest->hContact, hsour, true); +				} +				else { +					MCONTACT hcontact = contSour->hContact; +					MCONTACT hfrom = contSour->subcontacts->hContact; +					MCONTACT handle = contDest->hContact; +					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->szText); +					int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION); +					if (res == 1) { +						if (!handle) +							return 0; + +						CallService(MS_MC_REMOVEFROMMETA, 0, hcontact); +						CallService(MS_MC_ADDTOMETA, hcontact, handle); +					} +				} +			} +			break; + +		case DROPTARGET_ONSUBCONTACT: +			cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL); +			cliGetRowByIndex(dat, dat->selection, &contDest, NULL); +			if (contSour->isChat() || contDest->isChat()) +				break; +			if (contSour->type == CLCIT_CONTACT) { +				if (!strcmp(contSour->proto, META_PROTO)) +					break; +				if (!contSour->isSubcontact) { +					MCONTACT hcontact = contSour->hContact; +					MCONTACT handle = contDest->subcontacts->hContact; +					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->subcontacts->szText); +					int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION); +					if (res == 1) { +						if (!handle) +							return 0; +						 +						CallService(MS_MC_ADDTOMETA, hcontact, handle); +					} +				} +				else if (contSour->subcontacts != contDest->subcontacts) { +					MCONTACT hcontact = contSour->hContact; +					MCONTACT hfrom = contSour->subcontacts->hContact; +					MCONTACT handle = contDest->subcontacts->hContact; +					mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->subcontacts->szText); +					int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION); +					if (res == 1) { +						if (!handle) +							return 0; + +						CallService(MS_MC_REMOVEFROMMETA, 0, hcontact); +						CallService(MS_MC_ADDTOMETA, hcontact, handle); +					} +				} +			} +			break; + +		case DROPTARGET_ONGROUP: +			corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +			break; + +		case DROPTARGET_INSERTION: +			{ +				ClcContact *contact, *destcontact; +				ClcGroup *group, *destgroup; +				BOOL NeedRename = FALSE; +				TCHAR newName[128] = { 0 }; +				pcli->pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group); +				int i = pcli->pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup); +				if (i != -1 && group->groupId != destgroup->groupId) { +					TCHAR *groupName = mir_tstrdup(pcli->pfnGetGroupName(contact->groupId, 0)); +					TCHAR *shortGroup = NULL; +					TCHAR *sourceGrName = mir_tstrdup(pcli->pfnGetGroupName(destgroup->groupId, 0)); +					if (groupName) { +						int len = (int)_tcslen(groupName); +						do { len--; } +						while (len >= 0 && groupName[len] != '\\'); +						if (len >= 0) shortGroup = groupName + len + 1; +						else shortGroup = groupName; +					} +					if (shortGroup) { +						NeedRename = TRUE; +						if (sourceGrName) +							mir_sntprintf(newName, SIZEOF(newName), _T("%s\\%s"), sourceGrName, shortGroup); +						else +							mir_sntprintf(newName, SIZEOF(newName), _T("%s"), shortGroup); +					} +					mir_free(groupName); +					mir_free(sourceGrName); +				} +				int newIndex = CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, (destcontact && i != -1) ? destcontact->groupId : 0); +				newIndex = newIndex ? newIndex : contact->groupId; +				if (NeedRename) pcli->pfnRenameGroup(newIndex, newName); +			} +			break; + +		case DROPTARGET_OUTSIDE: +			corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +			break; + +		default: +			corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +			break; +		} +	} + +	CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +	dat->iDragItem = -1; +	dat->iInsertionMark = -1; +	return 0; +} + +static LRESULT clcOnLButtonDblClick(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	KillTimer(hwnd, TIMERID_SUBEXPAND); +	hitcontact = NULL; +	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +} + +static LRESULT clcOnDestroy(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	for (int i = 0; i <= FONTID_MODERN_MAX; i++) { +		if (dat->fontModernInfo[i].hFont) +			DeleteObject(dat->fontModernInfo[i].hFont); +		dat->fontModernInfo[i].hFont = NULL; +	} +	if (dat->hMenuBackground) { +		DeleteObject(dat->hMenuBackground); +		dat->hMenuBackground = NULL; +	} +	if (dat->hBmpBackground) { +		DeleteObject(dat->hBmpBackground); +		dat->hBmpBackground = NULL; +	} + +	ImageArray_Clear(&dat->avatar_cache); +	DeleteDC(dat->avatar_cache.hdc); +	ImageArray_Free(&dat->avatar_cache, FALSE); +	if (dat->himlHighlight) +		ImageList_Destroy(dat->himlHighlight); + +	RowHeights_Free(dat); +	corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +	xpt_FreeThemeForWindow(hwnd); +	return 0; +} + +static LRESULT clcOnIntmGroupChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	WORD iExtraImage[EXTRA_ICON_COUNT]; +	BYTE flags = 0; + +	ClcContact *contact; +	if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) +		memset(iExtraImage, 0xFF, sizeof(iExtraImage)); +	else { +		memcpy(iExtraImage, contact->iExtraImage, sizeof(iExtraImage)); +		flags = contact->flags; +	} +	pcli->pfnDeleteItemFromTree(hwnd, wParam); +	if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !db_get_b(wParam, "CList", "Hidden", 0)) { +		NMCLISTCONTROL nm; +		pcli->pfnAddContactToTree(hwnd, dat, wParam, 1, 1); +		if (pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) { +			memcpy(contact->iExtraImage, iExtraImage, sizeof(iExtraImage)); +			if (flags & CONTACTF_CHECKED) +				contact->flags |= CONTACTF_CHECKED; +		} +		nm.hdr.code = CLN_CONTACTMOVED; +		nm.hdr.hwndFrom = hwnd; +		nm.hdr.idFrom = GetDlgCtrlID(hwnd); +		nm.flags = 0; +		nm.hItem = (HANDLE)wParam; +		SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm); +		dat->needsResort = 1; +	} +	SetTimer(hwnd, TIMERID_REBUILDAFTER, 1, NULL); +	return 0; +} + +static LRESULT clcOnIntmIconChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	ClcContact *contact = NULL; +	ClcGroup *group = NULL; +	int recalcScrollBar = 0, shouldShow; +	BOOL needRepaint = FALSE; +	RECT iconRect = { 0 }; +	int contacticon = corecli.pfnGetContactIcon(wParam); +	MCONTACT hSelItem = NULL; +	ClcContact *selcontact = NULL; + +	char *szProto = GetContactProto(wParam); +	WORD status = (szProto == NULL) ? ID_STATUS_OFFLINE : GetContactCachedStatus(wParam); +	BOOL image_is_special = (LOWORD(contacticon) != (LOWORD(lParam))); //check only base icons + +	int nHiddenStatus = CLVM_GetContactHiddenStatus(wParam, szProto, dat); + +	DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE); +	bool isVisiblebyFilter = (((style & CLS_SHOWHIDDEN) && nHiddenStatus != -1) || !nHiddenStatus); +	bool ifVisibleByClui = !pcli->pfnIsHiddenMode(dat, status); +	bool isVisible = g_CluiData.bFilterEffective&CLVM_FILTER_STATUS ? TRUE : ifVisibleByClui; +	bool isIconChanged = cli_GetContactIcon(wParam) != LOWORD(lParam); + +	shouldShow = isVisiblebyFilter && (isVisible || isIconChanged); + +	// XXX CLVM changed - this means an offline msg is flashing, so the contact should be shown + +	if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, &group, NULL)) { +		if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) { +			if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1) +				hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact); +			pcli->pfnAddContactToTree(hwnd, dat, wParam, (style & CLS_CONTACTLIST) == 0, 0); +			recalcScrollBar = 1; +			needRepaint = TRUE; +			pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL); +			if (contact) { +				contact->iImage = lParam; +				contact->image_is_special = image_is_special; +				pcli->pfnNotifyNewContact(hwnd, wParam); +				dat->needsResort = 1; +			} +		} +	} +	else { +		//item in list already +		if (contact && contact->iImage == lParam) +			return 0; + +		if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline) && clcItemNotHiddenOffline(dat, group, contact)) +			shouldShow = TRUE; + +		if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && ((style & CLS_HIDEOFFLINE) || group->hideOffline || g_CluiData.bFilterEffective)) { // CLVM changed +			if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1) +				hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact); +			pcli->pfnRemoveItemFromGroup(hwnd, group, contact, (style & CLS_CONTACTLIST) == 0); +			needRepaint = TRUE; +			recalcScrollBar = 1; +			dat->needsResort = 1; +		} +		else if (contact) { +			contact->iImage = lParam; +			if (!pcli->pfnIsHiddenMode(dat, status)) +				contact->flags |= CONTACTF_ONLINE; +			else +				contact->flags &= ~CONTACTF_ONLINE; +			contact->image_is_special = image_is_special; +			if (!image_is_special) { //Only if it is status changing +				dat->needsResort = 1; +				needRepaint = TRUE; +			} +			else if (dat->m_paintCouter == contact->lastPaintCounter) //if contacts is visible +				needRepaint = TRUE; +		} +	} + +	if (hSelItem) { +		ClcGroup *selgroup; +		if (pcli->pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL)) +			dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact)); +		else +			dat->selection = -1; +	} + +	if (dat->needsResort) { +		TRACE("Sort required\n"); +		clcSetDelayTimer(TIMERID_DELAYEDRESORTCLC, hwnd); +	} +	else if (needRepaint) { +		if (contact && contact->pos_icon.bottom != 0 && contact->pos_icon.right != 0) +			CLUI__cliInvalidateRect(hwnd, &(contact->pos_icon), FALSE); +		else +			CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +		//try only needed rectangle +	} + +	return 0; +} + +static LRESULT clcOnIntmAvatarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	ClcContact *contact; +	if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE)) +		Cache_GetAvatar(dat, contact); +	else if (dat->use_avatar_service && !wParam) +		UpdateAllAvatars(dat); + +	CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +	return 0; +} + +static LRESULT clcOnIntmTimeZoneChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	ClcContact *contact; +	if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE)) +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +	if (contact) { +		Cache_GetTimezone(dat, contact->hContact); +		Cache_GetText(dat, contact, 1); +		cliRecalcScrollBar(hwnd, dat); +	} +	return 0; +} + +static LRESULT clcOnIntmNameChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +	pcli->pfnInvalidateDisplayNameCacheEntry(wParam); + +	ClcContact *contact; +	if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE)) +		return ret; + +	if (contact) { +		lstrcpyn(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), SIZEOF(contact->szText)); +		Cache_GetText(dat, contact, 1); +		cliRecalcScrollBar(hwnd, dat); +	} +	dat->needsResort = 1; +	pcli->pfnSortContacts(); + +	return ret; +} + +static LRESULT clcOnIntmApparentModeChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +} + +static LRESULT clcOnIntmStatusMsgChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM hContact, LPARAM lParam) +{ +	if (hContact == NULL || IsHContactInfo(hContact) || IsHContactGroup(hContact)) +		return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam); + +	ClcContact *contact; +	if (!FindItem(hwnd, dat, hContact, &contact, NULL, NULL, FALSE)) +		return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam); + +	if (contact) { +		Cache_GetText(dat, contact, 1); +		cliRecalcScrollBar(hwnd, dat); +		PostMessage(hwnd, INTM_INVALIDATE, 0, 0); +	} +	return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam); +} + +static LRESULT clcOnIntmNotOnListChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING*)lParam; + +	ClcContact *contact; +	if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE)) +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +	if (contact->type != CLCIT_CONTACT) +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); + +	if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0) +		contact->flags &= ~CONTACTF_NOTONLIST; +	else +		contact->flags |= CONTACTF_NOTONLIST; + +	CLUI__cliInvalidateRect(hwnd, NULL, FALSE); +	return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +} + +static LRESULT clcOnIntmScrollBarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) { +		if (dat->noVScrollbar) +			ShowScrollBar(hwnd, SB_VERT, FALSE); +		else +			pcli->pfnRecalcScrollBar(hwnd, dat); +	} +	return 0; +} + +static LRESULT clcOnIntmStatusChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +	if (wParam != 0) { +		ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(wParam); +		if (pdnce && pdnce->m_cache_cszProto) { +			pdnce->m_cache_nStatus = GetStatusForContact(pdnce->hContact, pdnce->m_cache_cszProto); +			if (!dat->force_in_dialog && (dat->second_line_show || dat->third_line_show)) +				gtaRenewText(pdnce->hContact); +			SendMessage(hwnd, INTM_ICONCHANGED, wParam, corecli.pfnGetContactIcon(wParam)); + +			ClcContact *contact; +			if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE)) { +				if (contact && contact->type == CLCIT_CONTACT) { +					if (!contact->image_is_special && pdnce___GetStatus(pdnce) > ID_STATUS_OFFLINE) +						contact->iImage = corecli.pfnGetContactIcon(wParam); +					if (contact->isSubcontact && contact->subcontacts && contact->subcontacts->type == CLCIT_CONTACT) +						pcli->pfnClcBroadcast(INTM_STATUSCHANGED, contact->subcontacts->hContact, 0); //forward status changing to host meta contact +				} +			} +		} +	} + +	if (db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOOFLINETOROOT_DEFAULT)) +		pcli->pfnInitAutoRebuild(hwnd); +	else { +		pcli->pfnSortContacts(); +		PostMessage(hwnd, INTM_INVALIDATE, 0, 0); +	} +	return ret; +} + +static LRESULT clcOnIntmReloadOptions(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +	pcli->pfnLoadClcOptions(hwnd, dat, FALSE); +	LoadCLCOptions(hwnd, dat, FALSE); +	pcli->pfnSaveStateAndRebuildList(hwnd, dat); +	pcli->pfnSortCLC(hwnd, dat, 1); +	if (IsWindowVisible(hwnd)) +		pcli->pfnInvalidateRect(GetParent(hwnd), NULL, FALSE); +	return TRUE; +} + +HRESULT ClcLoadModule() +{ +	g_himlCListClc = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0); + +	HookEvent(ME_MC_SUBCONTACTSCHANGED, clcMetacontactChanged); +	HookEvent(ME_MC_ENABLED, clcMetaModeChanged); +	HookEvent(ME_DB_CONTACT_SETTINGCHANGED, clcHookSettingChanged); +	HookEvent(ME_OPT_INITIALISE, ClcOptInit); +	hAckHook = (HANDLE)HookEvent(ME_PROTO_ACK, clcHookProtoAck); +	HookEvent(ME_SYSTEM_MODULESLOADED, clcHookModulesLoaded); +	HookEvent(ME_DB_EVENT_ADDED, clcHookDbEventAdded); +	return S_OK; +} + +int ClcUnloadModule() +{ +	if (g_CluiData.bOldUseGroups != (BYTE)-1) +		db_set_b(NULL, "CList", "UseGroups", (BYTE)g_CluiData.bOldUseGroups); +	if (g_CluiData.boldHideOffline != (BYTE)-1) +		db_set_b(NULL, "CList", "HideOffline", (BYTE)g_CluiData.boldHideOffline); + +	return 0; +} + +int ClcDoProtoAck(MCONTACT wParam, ACKDATA * ack) +{ +	if (MirandaExiting()) return 0; +	if (ack->type == ACKTYPE_STATUS) { +		if (ack->result == ACKRESULT_SUCCESS) { +			for (int i = 0; i < pcli->hClcProtoCount; i++) { +				if (!lstrcmpA(pcli->clcProto[i].szProto, ack->szModule)) { +					pcli->clcProto[i].dwStatus = (WORD)ack->lParam; +					if (pcli->clcProto[i].dwStatus >= ID_STATUS_OFFLINE) +						pcli->pfnTrayIconUpdateBase(pcli->clcProto[i].szProto); +					return 0; +				} +			} +		} +	} +	else if (ack->type == ACKTYPE_AWAYMSG) { +		if (ack->result == ACKRESULT_SUCCESS && ack->lParam) { +			//Do not change DB if it is IRC protocol +			if (ack->szModule != NULL) +				if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0) +					return 0; + +			db_set_ws(ack->hContact, "CList", "StatusMsg", (const TCHAR *)ack->lParam); +			gtaRenewText(ack->hContact); +		} +		else { +			//db_unset(ack->hContact,"CList","StatusMsg"); +			//char a = '\0'; +			//Do not change DB if it is IRC protocol +			if (ack->szModule != NULL) +				if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0) +					return 0; + +			if (ack->hContact) { +				char *val = db_get_sa(ack->hContact, "CList", "StatusMsg"); +				if (val) { +					if (!mir_bool_strcmpi(val, "")) +						db_set_s(ack->hContact, "CList", "StatusMsg", ""); +					else +						gtaRenewText(ack->hContact); +					mir_free(val); +				} +			} +			//pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED,(WPARAM)ack->hContact,&a); +		} +	} +	else if (ack->type == ACKTYPE_AVATAR) { +		if (ack->result == ACKRESULT_SUCCESS) { +			PROTO_AVATAR_INFORMATIONT *pai = (PROTO_AVATAR_INFORMATIONT*)ack->hProcess; +			if (pai != NULL && pai->hContact != NULL) +				pcli->pfnClcBroadcast(INTM_AVATARCHANGED, (WPARAM)pai->hContact, 0); +		} +	} +	else if (ack->type == ACKTYPE_EMAIL) { +		CLUIUnreadEmailCountChanged(0, 0); +	} +	return 0; +} + +int ClcGetShortData(ClcData* pData, struct SHORTDATA *pShortData) +{ +	if (!pData || !pShortData) +		return -1; +	 +	pShortData->hWnd = pData->hWnd; +	pShortData->text_replace_smileys = pData->text_replace_smileys; +	pShortData->text_smiley_height = pData->text_smiley_height; +	pShortData->text_use_protocol_smileys = pData->text_use_protocol_smileys; +	pShortData->contact_time_show_only_if_different = pData->contact_time_show_only_if_different; +	// Second line +	pShortData->second_line_show = pData->second_line_show; +	pShortData->second_line_draw_smileys = pData->second_line_draw_smileys; +	pShortData->second_line_type = pData->second_line_type; + +	_tcsncpy(pShortData->second_line_text, pData->second_line_text, TEXT_TEXT_MAX_LENGTH); + +	pShortData->second_line_xstatus_has_priority = pData->second_line_xstatus_has_priority; +	pShortData->second_line_show_status_if_no_away = pData->second_line_show_status_if_no_away; +	pShortData->second_line_show_listening_if_no_away = pData->second_line_show_listening_if_no_away; +	pShortData->second_line_use_name_and_message_for_xstatus = pData->second_line_use_name_and_message_for_xstatus; + +	pShortData->third_line_show = pData->third_line_show; +	pShortData->third_line_draw_smileys = pData->third_line_draw_smileys; +	pShortData->third_line_type = pData->third_line_type; + +	_tcsncpy(pShortData->third_line_text, pData->third_line_text, TEXT_TEXT_MAX_LENGTH); + +	pShortData->third_line_xstatus_has_priority = pData->third_line_xstatus_has_priority; +	pShortData->third_line_show_status_if_no_away = pData->third_line_show_status_if_no_away; +	pShortData->third_line_show_listening_if_no_away = pData->third_line_show_listening_if_no_away; +	pShortData->third_line_use_name_and_message_for_xstatus = pData->third_line_use_name_and_message_for_xstatus; +	return 0; +} + +int ClcEnterDragToScroll(HWND hwnd, int Y) +{ +	if (IsDragToScrollMode) +		return 0; + +	ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0); +	if (!dat) +		return 0; + +	StartDragPos = Y; +	StartScrollPos = dat->yScroll; +	IsDragToScrollMode = 1; +	SetCapture(hwnd); +	return 1; +} + + +/* +*	Contact list control window procedure +*/ +LRESULT CALLBACK cli_ContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + +#define CASE_MSG_RET(msg, handler) case msg: return handler(dat, hwnd, msg, wParam, lParam); + +	ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0); + +	if (msg >= CLM_FIRST && msg < CLM_LAST) +		return cli_ProcessExternalMessages(hwnd, dat, msg, wParam, lParam); + +	switch (msg) { +		CASE_MSG_RET(INTM_GROUPCHANGED, clcOnIntmGroupChanged); +		CASE_MSG_RET(INTM_ICONCHANGED, clcOnIntmIconChanged); +		CASE_MSG_RET(INTM_AVATARCHANGED, clcOnIntmAvatarChanged); +		CASE_MSG_RET(INTM_TIMEZONECHANGED, clcOnIntmTimeZoneChanged); +		CASE_MSG_RET(INTM_NAMECHANGED, clcOnIntmNameChanged); +		CASE_MSG_RET(INTM_APPARENTMODECHANGED, clcOnIntmApparentModeChanged); +		CASE_MSG_RET(INTM_STATUSMSGCHANGED, clcOnIntmStatusMsgChanged); +		CASE_MSG_RET(INTM_NOTONLISTCHANGED, clcOnIntmNotOnListChanged); +		CASE_MSG_RET(INTM_SCROLLBARCHANGED, clcOnIntmScrollBarChanged); +		CASE_MSG_RET(INTM_STATUSCHANGED, clcOnIntmStatusChanged); +		CASE_MSG_RET(INTM_RELOADOPTIONS, clcOnIntmReloadOptions); + +		CASE_MSG_RET(WM_CREATE, clcOnCreate); +		CASE_MSG_RET(WM_NCHITTEST, clcOnHitTest); +		CASE_MSG_RET(WM_COMMAND, clcOnCommand); +		CASE_MSG_RET(WM_SIZE, clcOnSize); +		CASE_MSG_RET(WM_CHAR, clcOnChar); +		CASE_MSG_RET(WM_PAINT, clcOnPaint); +		CASE_MSG_RET(WM_ERASEBKGND, clcOnEraseBkGround); +		CASE_MSG_RET(WM_KEYDOWN, clcOnKeyDown); +		CASE_MSG_RET(WM_TIMER, clcOnTimer); +		CASE_MSG_RET(WM_ACTIVATE, clcOnActivate); +		CASE_MSG_RET(WM_SETCURSOR, clcOnSetCursor); +		CASE_MSG_RET(WM_LBUTTONDOWN, clcOnLButtonDown); +		CASE_MSG_RET(WM_CAPTURECHANGED, clcOnCaptureChanged); +		CASE_MSG_RET(WM_MOUSEMOVE, clcOnMouseMove); +		CASE_MSG_RET(WM_LBUTTONUP, clcOnLButtonUp); +		CASE_MSG_RET(WM_LBUTTONDBLCLK, clcOnLButtonDblClick); +		CASE_MSG_RET(WM_DESTROY, clcOnDestroy); + +	default: +		return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam); +	} +	return TRUE; +} diff --git a/plugins/Clist_modern/src/modern_clcitems.cpp b/plugins/Clist_modern/src/modern_clcitems.cpp index 402a242098..9c5ecc6c1e 100644 --- a/plugins/Clist_modern/src/modern_clcitems.cpp +++ b/plugins/Clist_modern/src/modern_clcitems.cpp @@ -1,747 +1,746 @@ -/*
 -
 -Miranda NG: the free IM client for Microsoft* Windows*
 -
 -Copyright (c) 2012-14 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 "hdr/modern_commonheaders.h"
 -#include "hdr/modern_clc.h"
 -#include "hdr/modern_clist.h"
 -#include "m_metacontacts.h"
 -#include "hdr/modern_commonprototypes.h"
 -
 -void AddSubcontacts(ClcData *dat, ClcContact *cont, BOOL showOfflineHereGroup)
 -{
 -	ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(cont->hContact);
 -	cont->SubExpanded = (db_get_b(cont->hContact, "CList", "Expanded", 0) && (db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT)));
 -	int subcount = db_mc_getSubCount(cont->hContact);
 -	if (subcount <= 0) {
 -		cont->isSubcontact = 0;
 -		cont->subcontacts = NULL;
 -		cont->SubAllocated = 0;
 -		return;
 -	}
 -
 -	cont->isSubcontact = 0;
 -	mir_free(cont->subcontacts);
 -	cont->subcontacts = (ClcContact *)mir_calloc(sizeof(ClcContact)*subcount);
 -	cont->SubAllocated = subcount;
 -	int i = 0;
 -	int bHideOffline = db_get_b(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
 -	for (int j = 0; j < subcount; j++) {
 -		MCONTACT hsub = db_mc_getSub(cont->hContact, j);
 -		cacheEntry = pcli->pfnGetCacheEntry(hsub);
 -		WORD wStatus = pdnce___GetStatus(cacheEntry);
 -
 -		if (!showOfflineHereGroup && bHideOffline && !cacheEntry->m_cache_nNoHiddenOffline && wStatus == ID_STATUS_OFFLINE)
 -			continue;
 -
 -		ClcContact& p = cont->subcontacts[i];
 -		p.hContact = cacheEntry->hContact;
 -
 -		p.avatar_pos = AVATAR_POS_DONT_HAVE;
 -		Cache_GetAvatar(dat, &p);
 -
 -		p.iImage = corecli.pfnGetContactIcon(cacheEntry->hContact);
 -		memset(p.iExtraImage, 0xFF, sizeof(p.iExtraImage));
 -		p.proto = cacheEntry->m_cache_cszProto;
 -		p.type = CLCIT_CONTACT;
 -		p.flags = 0;//CONTACTF_ONLINE;
 -		p.isSubcontact = i + 1;
 -		p.lastPaintCounter = 0;
 -		p.subcontacts = cont;
 -		p.image_is_special = FALSE;
 -		//p.status = cacheEntry->status;
 -		Cache_GetTimezone(dat, (&p)->hContact);
 -		Cache_GetText(dat, &p, 1);
 -
 -		char *szProto = cacheEntry->m_cache_cszProto;
 -		if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, wStatus))
 -			p.flags |= CONTACTF_ONLINE;
 -		int apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0;
 -		if (apparentMode == ID_STATUS_OFFLINE)	p.flags |= CONTACTF_INVISTO;
 -		else if (apparentMode == ID_STATUS_ONLINE) p.flags |= CONTACTF_VISTO;
 -		else if (apparentMode) p.flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
 -		if (cacheEntry->NotOnList) p.flags |= CONTACTF_NOTONLIST;
 -		int idleMode = szProto != NULL ? cacheEntry->IdleTS : 0;
 -		if (idleMode) p.flags |= CONTACTF_IDLE;
 -		i++;
 -	}
 -
 -	cont->SubAllocated = i;
 -	if (!i && cont->subcontacts != NULL)
 -		mir_free_and_nil(cont->subcontacts);
 -}
 -
 -int cli_AddItemToGroup(ClcGroup *group, int iAboveItem)
 -{
 -	if (group == NULL)
 -		return 0;
 -
 -	iAboveItem = corecli.pfnAddItemToGroup(group, iAboveItem);
 -	ClearRowByIndexCache();
 -	return iAboveItem;
 -}
 -
 -ClcGroup* cli_AddGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
 -{
 -	ClearRowByIndexCache();
 -	if (!dat->force_in_dialog && !(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN))
 -		if (!lstrcmp(_T("-@-HIDDEN-GROUP-@-"), szName)) { //group is hidden
 -			ClearRowByIndexCache();
 -			return NULL;
 -		}
 -
 -	ClcGroup *result = corecli.pfnAddGroup(hwnd, dat, szName, flags, groupId, calcTotalMembers);
 -	ClearRowByIndexCache();
 -	return result;
 -}
 -
 -void cli_FreeContact(ClcContact *p)
 -{
 -	if (p->SubAllocated) {
 -		if (p->subcontacts && !p->isSubcontact) {
 -			for (int i = 0; i < p->SubAllocated; i++) {
 -				p->subcontacts[i].ssText.DestroySmileyList();
 -				if (p->subcontacts[i].avatar_pos == AVATAR_POS_ANIMATED)
 -					AniAva_RemoveAvatar(p->subcontacts[i].hContact);
 -				p->subcontacts[i].avatar_pos = AVATAR_POS_DONT_HAVE;
 -			}
 -			mir_free_and_nil(p->subcontacts);
 -		}
 -	}
 -
 -	p->ssText.DestroySmileyList();
 -	if (p->avatar_pos == AVATAR_POS_ANIMATED)
 -		AniAva_RemoveAvatar(p->hContact);
 -	p->avatar_pos = AVATAR_POS_DONT_HAVE;
 -	corecli.pfnFreeContact(p);
 -}
 -
 -void cli_FreeGroup(ClcGroup* group)
 -{
 -	corecli.pfnFreeGroup(group);
 -	ClearRowByIndexCache();
 -}
 -
 -int cli_AddInfoItemToGroup(ClcGroup *group, int flags, const TCHAR *pszText)
 -{
 -	int i = corecli.pfnAddInfoItemToGroup(group, flags, pszText);
 -	ClearRowByIndexCache();
 -	return i;
 -}
 -
 -static void _LoadDataToContact(ClcContact *cont, ClcGroup *group, ClcData *dat, MCONTACT hContact)
 -{
 -	if (!cont)
 -		return;
 -	
 -	cont->type = CLCIT_CONTACT;
 -	cont->SubAllocated = 0;
 -	cont->isSubcontact = 0;
 -	cont->subcontacts = NULL;
 -	cont->szText[0] = 0;
 -	cont->lastPaintCounter = 0;
 -	cont->image_is_special = FALSE;
 -	cont->hContact = hContact;
 -
 -	pcli->pfnInvalidateDisplayNameCacheEntry(hContact);
 -
 -	ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
 -	char *szProto = cacheEntry->m_cache_cszProto;
 -	cont->proto = szProto;
 -
 -	if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, pdnce___GetStatus(cacheEntry)))
 -		cont->flags |= CONTACTF_ONLINE;
 -
 -	WORD apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0;
 -
 -	if (apparentMode)
 -		switch (apparentMode) {
 -		case ID_STATUS_OFFLINE:
 -			cont->flags |= CONTACTF_INVISTO;
 -			break;
 -		case ID_STATUS_ONLINE:
 -			cont->flags |= CONTACTF_VISTO;
 -			break;
 -		default:
 -			cont->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
 -		}
 -
 -	if (cacheEntry->NotOnList)
 -		cont->flags |= CONTACTF_NOTONLIST;
 -
 -	DWORD idleMode = szProto != NULL ? cacheEntry->IdleTS : 0;
 -	if (idleMode)
 -		cont->flags |= CONTACTF_IDLE;
 -
 -	// Add subcontacts
 -	if (szProto)
 -		if (dat->IsMetaContactsEnabled && mir_strcmp(cont->proto, META_PROTO) == 0)
 -			AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group));
 -
 -	cont->lastPaintCounter = 0;
 -	cont->avatar_pos = AVATAR_POS_DONT_HAVE;
 -	Cache_GetAvatar(dat, cont);
 -	Cache_GetText(dat, cont, 1);
 -	Cache_GetTimezone(dat, cont->hContact);
 -	cont->iImage = corecli.pfnGetContactIcon(hContact);
 -	cont->bContactRate = db_get_b(hContact, "CList", "Rate", 0);
 -}
 -
 -static ClcContact* AddContactToGroup(ClcData *dat, ClcGroup *group, ClcCacheEntry *cacheEntry)
 -{
 -	if (cacheEntry == NULL) return NULL;
 -	if (group == NULL) return NULL;
 -	if (dat == NULL) return NULL;
 -	MCONTACT hContact = cacheEntry->hContact;
 -	dat->needsResort = 1;
 -	int i;
 -	for (i = group->cl.count - 1; i >= 0; i--)
 -		if (group->cl.items[i]->type != CLCIT_INFO || !(group->cl.items[i]->flags&CLCIIF_BELOWCONTACTS)) break;
 -	i = cli_AddItemToGroup(group, i + 1);
 -
 -	_LoadDataToContact(group->cl.items[i], group, dat, hContact);
 -	cacheEntry = pcli->pfnGetCacheEntry(hContact);
 -	ClearRowByIndexCache();
 -	return group->cl.items[i];
 -}
 -
 -void* AddTempGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
 -{
 -	int i = 0;
 -	int f = 0;
 -	DWORD groupFlags;
 -
 -	if (wildcmp(_T2A(szName), "-@-HIDDEN-GROUP-@-"))
 -		return NULL;
 -
 -	for (i = 1;; i++) {
 -		TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags);
 -		if (szGroupName == NULL) break;
 -		if (!mir_tstrcmpi(szGroupName, szName)) f = 1;
 -	}
 -
 -	if (f)
 -		return NULL;
 -	
 -	char buf[20];
 -	_itoa_s(i-1, buf, 10);
 -
 -	TCHAR b2[255];
 -	mir_sntprintf(b2, SIZEOF(b2), _T("#%s"), szName);
 -	b2[0] = 1 | GROUPF_EXPANDED;
 -	db_set_ws(NULL, "CListGroups", buf, b2);
 -	pcli->pfnGetGroupName(i, &groupFlags);
 -	return cli_AddGroup(hwnd, dat, szName, groupFlags, i, 0);
 -}
 -
 -void cli_AddContactToTree(HWND hwnd, ClcData *dat, MCONTACT hContact, int updateTotalCount, int checkHideOffline)
 -{
 -	ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
 -	if (dat->IsMetaContactsEnabled && cacheEntry && cacheEntry->m_bIsSub)
 -		return;		//contact should not be added
 -
 -	if (!dat->IsMetaContactsEnabled && cacheEntry && !mir_strcmp(cacheEntry->m_cache_cszProto, META_PROTO))
 -		return;
 -
 -	corecli.pfnAddContactToTree(hwnd, dat, hContact, updateTotalCount, checkHideOffline);
 -
 -	ClcGroup *group;
 -	ClcContact *cont;
 -	if (FindItem(hwnd, dat, hContact, &cont, &group, NULL, FALSE))
 -		_LoadDataToContact(cont, group, dat, hContact);
 -}
 -
 -void cli_DeleteItemFromTree(HWND hwnd, MCONTACT hItem)
 -{
 -	ClcData *dat = (ClcData *)GetWindowLongPtr(hwnd, 0);
 -	ClearRowByIndexCache();
 -	corecli.pfnDeleteItemFromTree(hwnd, hItem);
 -
 -	// check here contacts are not resorting
 -	if (hwnd == pcli->hwndContactTree)
 -		pcli->pfnFreeCacheItem(pcli->pfnGetCacheEntry(hItem));
 -	dat->needsResort = 1;
 -	ClearRowByIndexCache();
 -}
 -
 -__inline BOOL CLCItems_IsShowOfflineGroup(ClcGroup* group)
 -{
 -	DWORD groupFlags = 0;
 -	if (!group) return FALSE;
 -	if (group->hideOffline) return FALSE;
 -	pcli->pfnGetGroupName(group->groupId, &groupFlags);
 -	return (groupFlags&GROUPF_SHOWOFFLINE) != 0;
 -}
 -
 -MCONTACT SaveSelection(ClcData *dat)
 -{
 -	ClcContact *selcontact = NULL;
 -	if (pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
 -		return NULL;
 -
 -	return (MCONTACT)pcli->pfnContactToHItem(selcontact);
 -}
 -
 -int RestoreSelection(ClcData *dat, MCONTACT hSelected)
 -{
 -	ClcContact *selcontact = NULL;
 -	ClcGroup *selgroup = NULL;
 -
 -	if (!hSelected || !pcli->pfnFindItem(dat->hWnd, dat, hSelected, &selcontact, &selgroup, NULL)) {
 -		dat->selection = -1;
 -		return dat->selection;
 -	}
 -
 -	if (!selcontact->isSubcontact)
 -		dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact));
 -	else {
 -		dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact->subcontacts));
 -
 -		if (dat->selection != -1)
 -			dat->selection += selcontact->isSubcontact;
 -	}
 -	return dat->selection;
 -}
 -
 -void cliRebuildEntireList(HWND hwnd, ClcData *dat)
 -{
 -	DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
 -	ClcGroup *group;
 -	static int rebuildCounter = 0;
 -
 -	BOOL PlaceOfflineToRoot = db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOFFLINETOROOT_DEFAULT);
 -	KillTimer(hwnd, TIMERID_REBUILDAFTER);
 -
 -	ClearRowByIndexCache();
 -	ImageArray_Clear(&dat->avatar_cache);
 -	RowHeights_Clear(dat);
 -	RowHeights_GetMaxRowHeight(dat, hwnd);
 -	TRACEVAR("Rebuild Entire List %d times\n", ++rebuildCounter);
 -
 -	dat->list.expanded = 1;
 -	dat->list.hideOffline = db_get_b(NULL, "CLC", "HideOfflineRoot", SETTING_HIDEOFFLINEATROOT_DEFAULT) && style&CLS_USEGROUPS;
 -	dat->list.cl.count = dat->list.cl.limit = 0;
 -	dat->list.cl.increment = 50;
 -	dat->needsResort = 1;
 -
 -	MCONTACT hSelected = SaveSelection(dat);
 -	dat->selection = -1;
 -	dat->HiLightMode = db_get_b(NULL, "CLC", "HiLightMode", SETTING_HILIGHTMODE_DEFAULT);
 -
 -	for (int i = 1;; i++) {
 -		DWORD groupFlags;
 -		TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags); //UNICODE
 -		if (szGroupName == NULL)
 -			break;
 -		cli_AddGroup(hwnd, dat, szGroupName, groupFlags, i, 0);
 -	}
 -
 -	for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
 -		ClcContact *cont = NULL;
 -		ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
 -
 -		int nHiddenStatus = CLVM_GetContactHiddenStatus(hContact, NULL, dat);
 -		if ((style & CLS_SHOWHIDDEN && nHiddenStatus != -1) || !nHiddenStatus) {
 -			if (lstrlen(cacheEntry->tszGroup) == 0)
 -				group = &dat->list;
 -			else
 -				group = cli_AddGroup(hwnd, dat, cacheEntry->tszGroup, (DWORD)-1, 0, 0);
 -
 -			if (group != NULL) {
 -				WORD wStatus = pdnce___GetStatus(cacheEntry);
 -				if (wStatus == ID_STATUS_OFFLINE && PlaceOfflineToRoot)
 -					group = &dat->list;
 -		
 -				group->totalMembers++;
 -
 -				if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
 -					if (cacheEntry->m_cache_cszProto == NULL) {
 -						if (!pcli->pfnIsHiddenMode(dat, ID_STATUS_OFFLINE) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group))
 -							cont = AddContactToGroup(dat, group, cacheEntry);
 -					}
 -					else if (!pcli->pfnIsHiddenMode(dat, wStatus) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group))
 -						cont = AddContactToGroup(dat, group, cacheEntry);
 -				}
 -				else cont = AddContactToGroup(dat, group, cacheEntry);
 -			}
 -		}
 -		if (cont) {
 -			cont->SubAllocated = 0;
 -			if (cont->proto && dat->IsMetaContactsEnabled  && strcmp(cont->proto, META_PROTO) == 0)
 -				AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group));
 -		}
 -	}
 -
 -	if (style & CLS_HIDEEMPTYGROUPS) {
 -		group = &dat->list;
 -		group->scanIndex = 0;
 -		for (;;) {
 -			if (group->scanIndex == group->cl.count) {
 -				group = group->parent;
 -				if (group == NULL)
 -					break;
 -			}
 -			else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
 -				if (group->cl.items[group->scanIndex]->group->cl.count == 0)
 -					group = pcli->pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0);
 -				else {
 -					group = group->cl.items[group->scanIndex]->group;
 -					group->scanIndex = 0;
 -				}
 -				continue;
 -			}
 -			group->scanIndex++;
 -		}
 -	}
 -
 -	pcli->pfnSortCLC(hwnd, dat, 0);
 -
 -	RestoreSelection(dat, hSelected);
 -}
 -
 -void cli_SortCLC(HWND hwnd, ClcData *dat, int useInsertionSort)
 -{
 -	MCONTACT hSelected = SaveSelection(dat);
 -	corecli.pfnSortCLC(hwnd, dat, useInsertionSort);
 -	RestoreSelection(dat, hSelected);
 -}
 -
 -int GetNewSelection(ClcGroup *group, int selection, int direction)
 -{
 -	if (selection < 0)
 -		return 0;
 -
 -	int lastcount = 0, count = 0;
 -
 -	group->scanIndex = 0;
 -	for (;;) {
 -		if (group->scanIndex == group->cl.count) {
 -			group = group->parent;
 -			if (group == NULL) break;
 -			group->scanIndex++;
 -			continue;
 -		}
 -		
 -		if (count >= selection)
 -			return count;
 -		
 -		lastcount = count;
 -		count++;
 -		if (!direction && count > selection)
 -			return lastcount;
 -
 -		if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (group->cl.items[group->scanIndex]->group->expanded)) {
 -			group = group->cl.items[group->scanIndex]->group;
 -			group->scanIndex = 0;
 -			continue;
 -		}
 -		group->scanIndex++;
 -	}
 -	return lastcount;
 -}
 -
 -struct SavedContactState_t {
 -	MCONTACT hContact;
 -	WORD iExtraImage[EXTRA_ICON_COUNT];
 -	int checked;
 -};
 -
 -struct SavedGroupState_t {
 -	int groupId, expanded;
 -};
 -
 -struct SavedInfoState_t {
 -	int parentId;
 -	ClcContact contact;
 -};
 -
 -BOOL LOCK_RECALC_SCROLLBAR = FALSE;
 -void cli_SaveStateAndRebuildList(HWND hwnd, ClcData *dat)
 -{
 -	LOCK_RECALC_SCROLLBAR = TRUE;
 -
 -	NMCLISTCONTROL nm;
 -	int i, j;
 -	OBJLIST<SavedGroupState_t> savedGroup(4);
 -	OBJLIST<SavedContactState_t> savedContact(4);
 -	OBJLIST<SavedInfoState_t> savedInfo(4);
 -
 -	ClcGroup *group;
 -	ClcContact *contact;
 -
 -	pcli->pfnHideInfoTip(hwnd, dat);
 -	KillTimer(hwnd, TIMERID_INFOTIP);
 -	KillTimer(hwnd, TIMERID_RENAME);
 -	pcli->pfnEndRename(hwnd, dat, 1);
 -
 -	dat->needsResort = 1;
 -	group = &dat->list;
 -	group->scanIndex = 0;
 -	for (;;) {
 -		if (group->scanIndex == group->cl.count) {
 -			group = group->parent;
 -			if (group == NULL)
 -				break;
 -		}
 -		else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
 -			group = group->cl.items[group->scanIndex]->group;
 -			group->scanIndex = 0;
 -
 -			SavedGroupState_t* p = new SavedGroupState_t;
 -			p->groupId = group->groupId;
 -			p->expanded = group->expanded;
 -			savedGroup.insert(p);
 -			continue;
 -		}
 -		else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
 -			SavedContactState_t* p = new SavedContactState_t;
 -			p->hContact = group->cl.items[group->scanIndex]->hContact;
 -			memcpy(p->iExtraImage, group->cl.items[group->scanIndex]->iExtraImage, sizeof(p->iExtraImage));
 -			p->checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED;
 -			savedContact.insert(p);
 -		}
 -		else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) {
 -			SavedInfoState_t *p = new SavedInfoState_t;
 -			memset(p, 0, sizeof(SavedInfoState_t));
 -			if (group->parent == NULL)
 -				p->parentId = -1;
 -			else
 -				p->parentId = group->groupId;
 -			p->contact = *group->cl.items[group->scanIndex];
 -			savedInfo.insert(p);
 -		}
 -		group->scanIndex++;
 -	}
 -
 -	pcli->pfnFreeGroup(&dat->list);
 -	pcli->pfnRebuildEntireList(hwnd, dat);
 -
 -	group = &dat->list;
 -	group->scanIndex = 0;
 -	for (;;) {
 -		if (group->scanIndex == group->cl.count) {
 -			group = group->parent;
 -			if (group == NULL)
 -				break;
 -		}
 -		else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
 -			group = group->cl.items[group->scanIndex]->group;
 -			group->scanIndex = 0;
 -			for (i = 0; i < savedGroup.getCount(); i++)
 -				if (savedGroup[i].groupId == group->groupId) {
 -					group->expanded = savedGroup[i].expanded;
 -					break;
 -				}
 -			continue;
 -		}
 -		else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
 -			for (i = 0; i < savedContact.getCount(); i++)
 -				if (savedContact[i].hContact == group->cl.items[group->scanIndex]->hContact) {
 -					memcpy(group->cl.items[group->scanIndex]->iExtraImage, savedContact[i].iExtraImage, sizeof(contact->iExtraImage));
 -					if (savedContact[i].checked)
 -						group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED;
 -					break;
 -				}
 -		}
 -		group->scanIndex++;
 -	}
 -
 -	for (i = 0; i < savedInfo.getCount(); i++) {
 -		if (savedInfo[i].parentId == -1)
 -			group = &dat->list;
 -		else {
 -			if (!pcli->pfnFindItem(hwnd, dat, savedInfo[i].parentId | HCONTACT_ISGROUP, &contact, NULL, NULL))
 -				continue;
 -			group = contact->group;
 -		}
 -		j = pcli->pfnAddInfoItemToGroup(group, savedInfo[i].contact.flags, _T(""));
 -		*group->cl.items[j] = savedInfo[i].contact;
 -	}
 -
 -	LOCK_RECALC_SCROLLBAR = FALSE;
 -	pcli->pfnRecalculateGroupCheckboxes(hwnd, dat);
 -
 -	pcli->pfnRecalcScrollBar(hwnd, dat);
 -	nm.hdr.code = CLN_LISTREBUILT;
 -	nm.hdr.hwndFrom = hwnd;
 -	nm.hdr.idFrom = GetDlgCtrlID(hwnd);
 -	SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm);
 -}
 -
 -
 -WORD pdnce___GetStatus(ClcCacheEntry *pdnce)
 -{
 -	return (!pdnce) ? ID_STATUS_OFFLINE : pdnce->m_cache_nStatus;
 -}
 -
 -ClcContact* cliCreateClcContact()
 -{
 -	ClcContact* contact = (ClcContact*)mir_calloc(sizeof(ClcContact));
 -	memset(contact->iExtraImage, 0xFF, sizeof(contact->iExtraImage));
 -	return contact;
 -}
 -
 -ClcCacheEntry* cliCreateCacheItem(MCONTACT hContact)
 -{
 -	ClcCacheEntry *p = (ClcCacheEntry *)mir_calloc(sizeof(ClcCacheEntry));
 -	if (p == NULL)
 -		return NULL;
 -
 -	p->hContact = hContact;
 -	InvalidateDNCEbyPointer(hContact, p, 0);
 -	p->szSecondLineText = NULL;
 -	p->szThirdLineText = NULL;
 -	p->ssSecondLine.plText = NULL;
 -	p->ssThirdLine.plText = NULL;
 -	return p;
 -}
 -
 -void cliInvalidateDisplayNameCacheEntry(MCONTACT hContact)
 -{
 -	if (hContact == INVALID_CONTACT_ID)
 -		corecli.pfnInvalidateDisplayNameCacheEntry(INVALID_CONTACT_ID);
 -	else {
 -		ClcCacheEntry *p = pcli->pfnGetCacheEntry(hContact);
 -		if (p)
 -			InvalidateDNCEbyPointer(hContact, p, 0);
 -	}
 -}
 -
 -void cli_SetContactCheckboxes(ClcContact *cc, int checked)
 -{
 -	corecli.pfnSetContactCheckboxes(cc, checked);
 -
 -	for (int i = 0; i < cc->SubAllocated; i++)
 -		corecli.pfnSetContactCheckboxes(&cc->subcontacts[i], checked);
 -}
 -
 -char* cli_GetGroupCountsText(ClcData *dat, ClcContact *contact)
 -{
 -	return corecli.pfnGetGroupCountsText(dat, contact);
 -}
 -
 -int cliGetGroupContentsCount(ClcGroup *group, int visibleOnly)
 -{
 -	int count = group->cl.count;
 -	ClcGroup *topgroup = group;
 -
 -	group->scanIndex = 0;
 -	for (;;) {
 -		if (group->scanIndex == group->cl.count) {
 -			if (group == topgroup)
 -				break;
 -			group = group->parent;
 -		}
 -		else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (!(visibleOnly & 0x01) || group->cl.items[group->scanIndex]->group->expanded)) {
 -			group = group->cl.items[group->scanIndex]->group;
 -			group->scanIndex = 0;
 -			count += group->cl.count;
 -			continue;
 -		}
 -		else if ((group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) &&
 -			(group->cl.items[group->scanIndex]->subcontacts != NULL) &&
 -			((group->cl.items[group->scanIndex]->SubExpanded || (!visibleOnly)))) {
 -			count += group->cl.items[group->scanIndex]->SubAllocated;
 -		}
 -		group->scanIndex++;
 -	}
 -	return count;
 -}
 -
 -/*
 -* checks the currently active view mode filter and returns true, if the contact should be hidden
 -* if no view mode is active, it returns the CList/Hidden setting
 -* also cares about sub contacts (if meta is active)
 -*/
 -
 -int __fastcall CLVM_GetContactHiddenStatus(MCONTACT hContact, char *szProto, ClcData *dat)
 -{
 -	int dbHidden = db_get_b(hContact, "CList", "Hidden", 0);		// default hidden state, always respect it.
 -	int filterResult = 1;
 -	int searchResult = 0;
 -	DBVARIANT dbv = { 0 };
 -	char szTemp[64];
 -	TCHAR szGroupMask[256];
 -	DWORD dwLocalMask;
 -	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
 -	BOOL fEmbedded = dat->force_in_dialog;
 -	// always hide subcontacts (but show them on embedded contact lists)
 -
 -	if (dat != NULL && dat->IsMetaContactsEnabled && db_mc_isSub(hContact))
 -		return -1; //subcontact
 -	if (pdnce && pdnce->isUnknown && !fEmbedded)
 -		return 1; //'Unknown Contact'
 -	if (dat->filterSearch && dat->szQuickSearch && pdnce->tszName) {
 -		// search filtering
 -		TCHAR *lowered_name = CharLowerW(NEWTSTR_ALLOCA(pdnce->tszName));
 -		TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch));
 -		searchResult = _tcsstr(lowered_name, lowered_search) ? 0 : 1;
 -	}
 -	if (pdnce && g_CluiData.bFilterEffective && !fEmbedded) {
 -		if (szProto == NULL)
 -			szProto = GetContactProto(hContact);
 -		// check stickies first (priority), only if we really have stickies defined (CLVM_STICKY_CONTACTS is set).
 -		if (g_CluiData.bFilterEffective & CLVM_STICKY_CONTACTS) {
 -			if ((dwLocalMask = db_get_dw(hContact, CLVM_MODULE, g_CluiData.current_viewmode, 0)) != 0) {
 -				if (g_CluiData.bFilterEffective & CLVM_FILTER_STICKYSTATUS) {
 -					WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
 -					return !((1 << (wStatus - ID_STATUS_OFFLINE)) & HIWORD(dwLocalMask)) | searchResult;
 -				}
 -				return 0 | searchResult;
 -			}
 -		}
 -		// check the proto, use it as a base filter result for all further checks
 -		if (g_CluiData.bFilterEffective & CLVM_FILTER_PROTOS) {
 -			mir_snprintf(szTemp, SIZEOF(szTemp), "%s|", szProto);
 -			filterResult = strstr(g_CluiData.protoFilter, szTemp) ? 1 : 0;
 -		}
 -		if (g_CluiData.bFilterEffective & CLVM_FILTER_GROUPS) {
 -			if (!db_get_ts(hContact, "CList", "Group", &dbv)) {
 -				mir_sntprintf(szGroupMask, SIZEOF(szGroupMask), _T("%s|"), &dbv.ptszVal[0]);
 -				filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? (filterResult | (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0)) : (filterResult & (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0));
 -				mir_free(dbv.ptszVal);
 -			}
 -			else if (g_CluiData.filterFlags & CLVM_INCLUDED_UNGROUPED)
 -				filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 1;
 -			else
 -				filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 0;
 -		}
 -		if (g_CluiData.bFilterEffective & CLVM_FILTER_STATUS) {
 -			WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
 -			filterResult = (g_CluiData.filterFlags & CLVM_GROUPSTATUS_OP) ? ((filterResult | ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0))) : (filterResult & ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0));
 -		}
 -		if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG) {
 -			if (pdnce && pdnce->dwLastMsgTime != -1) {
 -				DWORD now = g_CluiData.t_now;
 -				now -= g_CluiData.lastMsgFilter;
 -				if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_OLDERTHAN)
 -					filterResult = filterResult & (pdnce->dwLastMsgTime < now);
 -				else if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_NEWERTHAN)
 -					filterResult = filterResult & (pdnce->dwLastMsgTime > now);
 -			}
 -		}
 -		return (dbHidden | !filterResult | searchResult);
 -	}
 -
 -	return dbHidden | searchResult;
 -}
 +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 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 "hdr/modern_commonheaders.h" +#include "hdr/modern_clc.h" +#include "hdr/modern_clist.h" +#include "m_metacontacts.h" +#include "hdr/modern_commonprototypes.h" + +void AddSubcontacts(ClcData *dat, ClcContact *cont, BOOL showOfflineHereGroup) +{ +	ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(cont->hContact); +	cont->SubExpanded = (db_get_b(cont->hContact, "CList", "Expanded", 0) && (db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT))); +	int subcount = db_mc_getSubCount(cont->hContact); +	if (subcount <= 0) { +		cont->isSubcontact = 0; +		cont->subcontacts = NULL; +		cont->SubAllocated = 0; +		return; +	} + +	cont->isSubcontact = 0; +	mir_free(cont->subcontacts); +	cont->subcontacts = (ClcContact *)mir_calloc(sizeof(ClcContact)*subcount); +	cont->SubAllocated = subcount; +	int i = 0; +	int bHideOffline = db_get_b(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT); +	for (int j = 0; j < subcount; j++) { +		MCONTACT hsub = db_mc_getSub(cont->hContact, j); +		cacheEntry = pcli->pfnGetCacheEntry(hsub); +		WORD wStatus = pdnce___GetStatus(cacheEntry); + +		if (!showOfflineHereGroup && bHideOffline && !cacheEntry->m_cache_nNoHiddenOffline && wStatus == ID_STATUS_OFFLINE) +			continue; + +		ClcContact& p = cont->subcontacts[i]; +		p.hContact = cacheEntry->hContact; + +		p.avatar_pos = AVATAR_POS_DONT_HAVE; +		Cache_GetAvatar(dat, &p); + +		p.iImage = corecli.pfnGetContactIcon(cacheEntry->hContact); +		memset(p.iExtraImage, 0xFF, sizeof(p.iExtraImage)); +		p.proto = cacheEntry->m_cache_cszProto; +		p.type = CLCIT_CONTACT; +		p.flags = 0;//CONTACTF_ONLINE; +		p.isSubcontact = i + 1; +		p.lastPaintCounter = 0; +		p.subcontacts = cont; +		p.image_is_special = FALSE; +		//p.status = cacheEntry->status; +		Cache_GetTimezone(dat, (&p)->hContact); +		Cache_GetText(dat, &p, 1); + +		char *szProto = cacheEntry->m_cache_cszProto; +		if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, wStatus)) +			p.flags |= CONTACTF_ONLINE; +		int apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0; +		if (apparentMode == ID_STATUS_OFFLINE)	p.flags |= CONTACTF_INVISTO; +		else if (apparentMode == ID_STATUS_ONLINE) p.flags |= CONTACTF_VISTO; +		else if (apparentMode) p.flags |= CONTACTF_VISTO | CONTACTF_INVISTO; +		if (cacheEntry->NotOnList) p.flags |= CONTACTF_NOTONLIST; +		int idleMode = szProto != NULL ? cacheEntry->IdleTS : 0; +		if (idleMode) p.flags |= CONTACTF_IDLE; +		i++; +	} + +	cont->SubAllocated = i; +	if (!i && cont->subcontacts != NULL) +		mir_free_and_nil(cont->subcontacts); +} + +int cli_AddItemToGroup(ClcGroup *group, int iAboveItem) +{ +	if (group == NULL) +		return 0; + +	iAboveItem = corecli.pfnAddItemToGroup(group, iAboveItem); +	ClearRowByIndexCache(); +	return iAboveItem; +} + +ClcGroup* cli_AddGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers) +{ +	ClearRowByIndexCache(); +	if (!dat->force_in_dialog && !(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN)) +		if (!lstrcmp(_T("-@-HIDDEN-GROUP-@-"), szName)) { //group is hidden +			ClearRowByIndexCache(); +			return NULL; +		} + +	ClcGroup *result = corecli.pfnAddGroup(hwnd, dat, szName, flags, groupId, calcTotalMembers); +	ClearRowByIndexCache(); +	return result; +} + +void cli_FreeContact(ClcContact *p) +{ +	if (p->SubAllocated) { +		if (p->subcontacts && !p->isSubcontact) { +			for (int i = 0; i < p->SubAllocated; i++) { +				p->subcontacts[i].ssText.DestroySmileyList(); +				if (p->subcontacts[i].avatar_pos == AVATAR_POS_ANIMATED) +					AniAva_RemoveAvatar(p->subcontacts[i].hContact); +				p->subcontacts[i].avatar_pos = AVATAR_POS_DONT_HAVE; +			} +			mir_free_and_nil(p->subcontacts); +		} +	} + +	p->ssText.DestroySmileyList(); +	if (p->avatar_pos == AVATAR_POS_ANIMATED) +		AniAva_RemoveAvatar(p->hContact); +	p->avatar_pos = AVATAR_POS_DONT_HAVE; +	corecli.pfnFreeContact(p); +} + +void cli_FreeGroup(ClcGroup* group) +{ +	corecli.pfnFreeGroup(group); +	ClearRowByIndexCache(); +} + +int cli_AddInfoItemToGroup(ClcGroup *group, int flags, const TCHAR *pszText) +{ +	int i = corecli.pfnAddInfoItemToGroup(group, flags, pszText); +	ClearRowByIndexCache(); +	return i; +} + +static void _LoadDataToContact(ClcContact *cont, ClcGroup *group, ClcData *dat, MCONTACT hContact) +{ +	if (!cont) +		return; +	 +	cont->type = CLCIT_CONTACT; +	cont->SubAllocated = 0; +	cont->isSubcontact = 0; +	cont->subcontacts = NULL; +	cont->szText[0] = 0; +	cont->lastPaintCounter = 0; +	cont->image_is_special = FALSE; +	cont->hContact = hContact; + +	pcli->pfnInvalidateDisplayNameCacheEntry(hContact); + +	ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact); +	char *szProto = cacheEntry->m_cache_cszProto; +	cont->proto = szProto; + +	if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, pdnce___GetStatus(cacheEntry))) +		cont->flags |= CONTACTF_ONLINE; + +	WORD apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0; + +	if (apparentMode) +		switch (apparentMode) { +		case ID_STATUS_OFFLINE: +			cont->flags |= CONTACTF_INVISTO; +			break; +		case ID_STATUS_ONLINE: +			cont->flags |= CONTACTF_VISTO; +			break; +		default: +			cont->flags |= CONTACTF_VISTO | CONTACTF_INVISTO; +		} + +	if (cacheEntry->NotOnList) +		cont->flags |= CONTACTF_NOTONLIST; + +	DWORD idleMode = szProto != NULL ? cacheEntry->IdleTS : 0; +	if (idleMode) +		cont->flags |= CONTACTF_IDLE; + +	// Add subcontacts +	if (szProto) +		if (dat->IsMetaContactsEnabled && mir_strcmp(cont->proto, META_PROTO) == 0) +			AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group)); + +	cont->lastPaintCounter = 0; +	cont->avatar_pos = AVATAR_POS_DONT_HAVE; +	Cache_GetAvatar(dat, cont); +	Cache_GetText(dat, cont, 1); +	Cache_GetTimezone(dat, cont->hContact); +	cont->iImage = corecli.pfnGetContactIcon(hContact); +	cont->bContactRate = db_get_b(hContact, "CList", "Rate", 0); +} + +static ClcContact* AddContactToGroup(ClcData *dat, ClcGroup *group, ClcCacheEntry *cacheEntry) +{ +	if (cacheEntry == NULL) return NULL; +	if (group == NULL) return NULL; +	if (dat == NULL) return NULL; +	MCONTACT hContact = cacheEntry->hContact; +	dat->needsResort = 1; +	int i; +	for (i = group->cl.count - 1; i >= 0; i--) +		if (group->cl.items[i]->type != CLCIT_INFO || !(group->cl.items[i]->flags&CLCIIF_BELOWCONTACTS)) break; +	i = cli_AddItemToGroup(group, i + 1); + +	_LoadDataToContact(group->cl.items[i], group, dat, hContact); +	cacheEntry = pcli->pfnGetCacheEntry(hContact); +	ClearRowByIndexCache(); +	return group->cl.items[i]; +} + +void* AddTempGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers) +{ +	int i = 0; +	int f = 0; +	DWORD groupFlags; + +	if (wildcmp(_T2A(szName), "-@-HIDDEN-GROUP-@-")) +		return NULL; + +	for (i = 1;; i++) { +		TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags); +		if (szGroupName == NULL) break; +		if (!mir_tstrcmpi(szGroupName, szName)) f = 1; +	} + +	if (f) +		return NULL; +	 +	char buf[20]; +	_itoa_s(i-1, buf, 10); + +	TCHAR b2[255]; +	mir_sntprintf(b2, SIZEOF(b2), _T("#%s"), szName); +	b2[0] = 1 | GROUPF_EXPANDED; +	db_set_ws(NULL, "CListGroups", buf, b2); +	pcli->pfnGetGroupName(i, &groupFlags); +	return cli_AddGroup(hwnd, dat, szName, groupFlags, i, 0); +} + +void cli_AddContactToTree(HWND hwnd, ClcData *dat, MCONTACT hContact, int updateTotalCount, int checkHideOffline) +{ +	ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact); +	if (dat->IsMetaContactsEnabled && cacheEntry && cacheEntry->m_bIsSub) +		return;		//contact should not be added + +	if (!dat->IsMetaContactsEnabled && cacheEntry && !mir_strcmp(cacheEntry->m_cache_cszProto, META_PROTO)) +		return; + +	corecli.pfnAddContactToTree(hwnd, dat, hContact, updateTotalCount, checkHideOffline); + +	ClcGroup *group; +	ClcContact *cont; +	if (FindItem(hwnd, dat, hContact, &cont, &group, NULL, FALSE)) +		_LoadDataToContact(cont, group, dat, hContact); +} + +void cli_DeleteItemFromTree(HWND hwnd, MCONTACT hItem) +{ +	ClcData *dat = (ClcData *)GetWindowLongPtr(hwnd, 0); +	ClearRowByIndexCache(); +	corecli.pfnDeleteItemFromTree(hwnd, hItem); + +	// check here contacts are not resorting +	if (hwnd == pcli->hwndContactTree) +		pcli->pfnFreeCacheItem(pcli->pfnGetCacheEntry(hItem)); +	dat->needsResort = 1; +	ClearRowByIndexCache(); +} + +__inline BOOL CLCItems_IsShowOfflineGroup(ClcGroup* group) +{ +	DWORD groupFlags = 0; +	if (!group) return FALSE; +	if (group->hideOffline) return FALSE; +	pcli->pfnGetGroupName(group->groupId, &groupFlags); +	return (groupFlags&GROUPF_SHOWOFFLINE) != 0; +} + +MCONTACT SaveSelection(ClcData *dat) +{ +	ClcContact *selcontact = NULL; +	if (pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1) +		return NULL; + +	return (MCONTACT)pcli->pfnContactToHItem(selcontact); +} + +int RestoreSelection(ClcData *dat, MCONTACT hSelected) +{ +	ClcContact *selcontact = NULL; +	ClcGroup *selgroup = NULL; + +	if (!hSelected || !pcli->pfnFindItem(dat->hWnd, dat, hSelected, &selcontact, &selgroup, NULL)) { +		dat->selection = -1; +		return dat->selection; +	} + +	if (!selcontact->isSubcontact) +		dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact)); +	else { +		dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact->subcontacts)); + +		if (dat->selection != -1) +			dat->selection += selcontact->isSubcontact; +	} +	return dat->selection; +} + +void cliRebuildEntireList(HWND hwnd, ClcData *dat) +{ +	DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE); +	ClcGroup *group; +	static int rebuildCounter = 0; + +	BOOL PlaceOfflineToRoot = db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOFFLINETOROOT_DEFAULT); +	KillTimer(hwnd, TIMERID_REBUILDAFTER); + +	ClearRowByIndexCache(); +	ImageArray_Clear(&dat->avatar_cache); +	RowHeights_Clear(dat); +	RowHeights_GetMaxRowHeight(dat, hwnd); +	TRACEVAR("Rebuild Entire List %d times\n", ++rebuildCounter); + +	dat->list.expanded = 1; +	dat->list.hideOffline = db_get_b(NULL, "CLC", "HideOfflineRoot", SETTING_HIDEOFFLINEATROOT_DEFAULT) && style&CLS_USEGROUPS; +	dat->list.cl.count = dat->list.cl.limit = 0; +	dat->list.cl.increment = 50; +	dat->needsResort = 1; + +	MCONTACT hSelected = SaveSelection(dat); +	dat->selection = -1; +	dat->HiLightMode = db_get_b(NULL, "CLC", "HiLightMode", SETTING_HILIGHTMODE_DEFAULT); + +	for (int i = 1;; i++) { +		DWORD groupFlags; +		TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags); //UNICODE +		if (szGroupName == NULL) +			break; +		cli_AddGroup(hwnd, dat, szGroupName, groupFlags, i, 0); +	} + +	for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { +		ClcContact *cont = NULL; +		ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact); + +		int nHiddenStatus = CLVM_GetContactHiddenStatus(hContact, NULL, dat); +		if ((style & CLS_SHOWHIDDEN && nHiddenStatus != -1) || !nHiddenStatus) { +			if (lstrlen(cacheEntry->tszGroup) == 0) +				group = &dat->list; +			else +				group = cli_AddGroup(hwnd, dat, cacheEntry->tszGroup, (DWORD)-1, 0, 0); + +			if (group != NULL) { +				WORD wStatus = pdnce___GetStatus(cacheEntry); +				if (wStatus == ID_STATUS_OFFLINE && PlaceOfflineToRoot) +					group = &dat->list; +		 +				group->totalMembers++; + +				if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) { +					if (cacheEntry->m_cache_cszProto == NULL) { +						if (!pcli->pfnIsHiddenMode(dat, ID_STATUS_OFFLINE) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group)) +							cont = AddContactToGroup(dat, group, cacheEntry); +					} +					else if (!pcli->pfnIsHiddenMode(dat, wStatus) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group)) +						cont = AddContactToGroup(dat, group, cacheEntry); +				} +				else cont = AddContactToGroup(dat, group, cacheEntry); +			} +		} +		if (cont) { +			cont->SubAllocated = 0; +			if (cont->proto && dat->IsMetaContactsEnabled  && strcmp(cont->proto, META_PROTO) == 0) +				AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group)); +		} +	} + +	if (style & CLS_HIDEEMPTYGROUPS) { +		group = &dat->list; +		group->scanIndex = 0; +		for (;;) { +			if (group->scanIndex == group->cl.count) { +				group = group->parent; +				if (group == NULL) +					break; +			} +			else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) { +				if (group->cl.items[group->scanIndex]->group->cl.count == 0) +					group = pcli->pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0); +				else { +					group = group->cl.items[group->scanIndex]->group; +					group->scanIndex = 0; +				} +				continue; +			} +			group->scanIndex++; +		} +	} + +	pcli->pfnSortCLC(hwnd, dat, 0); + +	RestoreSelection(dat, hSelected); +} + +void cli_SortCLC(HWND hwnd, ClcData *dat, int useInsertionSort) +{ +	MCONTACT hSelected = SaveSelection(dat); +	corecli.pfnSortCLC(hwnd, dat, useInsertionSort); +	RestoreSelection(dat, hSelected); +} + +int GetNewSelection(ClcGroup *group, int selection, int direction) +{ +	if (selection < 0) +		return 0; + +	int lastcount = 0, count = 0; + +	group->scanIndex = 0; +	for (;;) { +		if (group->scanIndex == group->cl.count) { +			group = group->parent; +			if (group == NULL) break; +			group->scanIndex++; +			continue; +		} +		 +		if (count >= selection) +			return count; +		 +		lastcount = count; +		count++; +		if (!direction && count > selection) +			return lastcount; + +		if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (group->cl.items[group->scanIndex]->group->expanded)) { +			group = group->cl.items[group->scanIndex]->group; +			group->scanIndex = 0; +			continue; +		} +		group->scanIndex++; +	} +	return lastcount; +} + +struct SavedContactState_t { +	MCONTACT hContact; +	WORD iExtraImage[EXTRA_ICON_COUNT]; +	int checked; +}; + +struct SavedGroupState_t { +	int groupId, expanded; +}; + +struct SavedInfoState_t { +	int parentId; +	ClcContact contact; +}; + +BOOL LOCK_RECALC_SCROLLBAR = FALSE; +void cli_SaveStateAndRebuildList(HWND hwnd, ClcData *dat) +{ +	LOCK_RECALC_SCROLLBAR = TRUE; + +	NMCLISTCONTROL nm; +	int i, j; +	OBJLIST<SavedGroupState_t> savedGroup(4); +	OBJLIST<SavedContactState_t> savedContact(4); +	OBJLIST<SavedInfoState_t> savedInfo(4); + +	ClcGroup *group; +	ClcContact *contact; + +	pcli->pfnHideInfoTip(hwnd, dat); +	KillTimer(hwnd, TIMERID_INFOTIP); +	KillTimer(hwnd, TIMERID_RENAME); +	pcli->pfnEndRename(hwnd, dat, 1); + +	dat->needsResort = 1; +	group = &dat->list; +	group->scanIndex = 0; +	for (;;) { +		if (group->scanIndex == group->cl.count) { +			group = group->parent; +			if (group == NULL) +				break; +		} +		else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) { +			group = group->cl.items[group->scanIndex]->group; +			group->scanIndex = 0; + +			SavedGroupState_t* p = new SavedGroupState_t; +			p->groupId = group->groupId; +			p->expanded = group->expanded; +			savedGroup.insert(p); +			continue; +		} +		else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) { +			SavedContactState_t* p = new SavedContactState_t; +			p->hContact = group->cl.items[group->scanIndex]->hContact; +			memcpy(p->iExtraImage, group->cl.items[group->scanIndex]->iExtraImage, sizeof(p->iExtraImage)); +			p->checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED; +			savedContact.insert(p); +		} +		else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) { +			SavedInfoState_t *p = new SavedInfoState_t; +			memset(p, 0, sizeof(SavedInfoState_t)); +			if (group->parent == NULL) +				p->parentId = -1; +			else +				p->parentId = group->groupId; +			p->contact = *group->cl.items[group->scanIndex]; +			savedInfo.insert(p); +		} +		group->scanIndex++; +	} + +	pcli->pfnFreeGroup(&dat->list); +	pcli->pfnRebuildEntireList(hwnd, dat); + +	group = &dat->list; +	group->scanIndex = 0; +	for (;;) { +		if (group->scanIndex == group->cl.count) { +			group = group->parent; +			if (group == NULL) +				break; +		} +		else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) { +			group = group->cl.items[group->scanIndex]->group; +			group->scanIndex = 0; +			for (i = 0; i < savedGroup.getCount(); i++) +				if (savedGroup[i].groupId == group->groupId) { +					group->expanded = savedGroup[i].expanded; +					break; +				} +			continue; +		} +		else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) { +			for (i = 0; i < savedContact.getCount(); i++) +				if (savedContact[i].hContact == group->cl.items[group->scanIndex]->hContact) { +					memcpy(group->cl.items[group->scanIndex]->iExtraImage, savedContact[i].iExtraImage, sizeof(contact->iExtraImage)); +					if (savedContact[i].checked) +						group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED; +					break; +				} +		} +		group->scanIndex++; +	} + +	for (i = 0; i < savedInfo.getCount(); i++) { +		if (savedInfo[i].parentId == -1) +			group = &dat->list; +		else { +			if (!pcli->pfnFindItem(hwnd, dat, savedInfo[i].parentId | HCONTACT_ISGROUP, &contact, NULL, NULL)) +				continue; +			group = contact->group; +		} +		j = pcli->pfnAddInfoItemToGroup(group, savedInfo[i].contact.flags, _T("")); +		*group->cl.items[j] = savedInfo[i].contact; +	} + +	LOCK_RECALC_SCROLLBAR = FALSE; +	pcli->pfnRecalculateGroupCheckboxes(hwnd, dat); + +	pcli->pfnRecalcScrollBar(hwnd, dat); +	nm.hdr.code = CLN_LISTREBUILT; +	nm.hdr.hwndFrom = hwnd; +	nm.hdr.idFrom = GetDlgCtrlID(hwnd); +	SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm); +} + + +WORD pdnce___GetStatus(ClcCacheEntry *pdnce) +{ +	return (!pdnce) ? ID_STATUS_OFFLINE : pdnce->m_cache_nStatus; +} + +ClcContact* cliCreateClcContact() +{ +	ClcContact* contact = (ClcContact*)mir_calloc(sizeof(ClcContact)); +	memset(contact->iExtraImage, 0xFF, sizeof(contact->iExtraImage)); +	return contact; +} + +ClcCacheEntry* cliCreateCacheItem(MCONTACT hContact) +{ +	ClcCacheEntry *p = (ClcCacheEntry *)mir_calloc(sizeof(ClcCacheEntry)); +	if (p == NULL) +		return NULL; + +	p->hContact = hContact; +	InvalidateDNCEbyPointer(hContact, p, 0); +	p->szSecondLineText = NULL; +	p->szThirdLineText = NULL; +	p->ssSecondLine.plText = NULL; +	p->ssThirdLine.plText = NULL; +	return p; +} + +void cliInvalidateDisplayNameCacheEntry(MCONTACT hContact) +{ +	if (hContact == INVALID_CONTACT_ID) +		corecli.pfnInvalidateDisplayNameCacheEntry(INVALID_CONTACT_ID); +	else { +		ClcCacheEntry *p = pcli->pfnGetCacheEntry(hContact); +		if (p) +			InvalidateDNCEbyPointer(hContact, p, 0); +	} +} + +void cli_SetContactCheckboxes(ClcContact *cc, int checked) +{ +	corecli.pfnSetContactCheckboxes(cc, checked); + +	for (int i = 0; i < cc->SubAllocated; i++) +		corecli.pfnSetContactCheckboxes(&cc->subcontacts[i], checked); +} + +char* cli_GetGroupCountsText(ClcData *dat, ClcContact *contact) +{ +	return corecli.pfnGetGroupCountsText(dat, contact); +} + +int cliGetGroupContentsCount(ClcGroup *group, int visibleOnly) +{ +	int count = group->cl.count; +	ClcGroup *topgroup = group; + +	group->scanIndex = 0; +	for (;;) { +		if (group->scanIndex == group->cl.count) { +			if (group == topgroup) +				break; +			group = group->parent; +		} +		else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (!(visibleOnly & 0x01) || group->cl.items[group->scanIndex]->group->expanded)) { +			group = group->cl.items[group->scanIndex]->group; +			group->scanIndex = 0; +			count += group->cl.count; +			continue; +		} +		else if ((group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) && +			(group->cl.items[group->scanIndex]->subcontacts != NULL) && +			((group->cl.items[group->scanIndex]->SubExpanded || (!visibleOnly)))) { +			count += group->cl.items[group->scanIndex]->SubAllocated; +		} +		group->scanIndex++; +	} +	return count; +} + +/* +* checks the currently active view mode filter and returns true, if the contact should be hidden +* if no view mode is active, it returns the CList/Hidden setting +* also cares about sub contacts (if meta is active) +*/ + +int __fastcall CLVM_GetContactHiddenStatus(MCONTACT hContact, char *szProto, ClcData *dat) +{ +	int dbHidden = db_get_b(hContact, "CList", "Hidden", 0);		// default hidden state, always respect it. +	int filterResult = 1; +	int searchResult = 0; +	DBVARIANT dbv = { 0 }; +	char szTemp[64]; +	TCHAR szGroupMask[256]; +	DWORD dwLocalMask; +	ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact); +	// always hide subcontacts (but show them on embedded contact lists) + +	if (dat != NULL && dat->IsMetaContactsEnabled && db_mc_isSub(hContact)) +		return -1; //subcontact +	if (pdnce && pdnce->isUnknown && dat != NULL && !dat->force_in_dialog) +		return 1; //'Unknown Contact' +	if (dat != NULL && dat->filterSearch && dat->szQuickSearch && pdnce && pdnce->tszName) { +		// search filtering +		TCHAR *lowered_name = CharLowerW(NEWTSTR_ALLOCA(pdnce->tszName)); +		TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch)); +		searchResult = _tcsstr(lowered_name, lowered_search) ? 0 : 1; +	} +	if (pdnce && g_CluiData.bFilterEffective && dat != NULL && !dat->force_in_dialog) { +		if (szProto == NULL) +			szProto = GetContactProto(hContact); +		// check stickies first (priority), only if we really have stickies defined (CLVM_STICKY_CONTACTS is set). +		if (g_CluiData.bFilterEffective & CLVM_STICKY_CONTACTS) { +			if ((dwLocalMask = db_get_dw(hContact, CLVM_MODULE, g_CluiData.current_viewmode, 0)) != 0) { +				if (g_CluiData.bFilterEffective & CLVM_FILTER_STICKYSTATUS) { +					WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); +					return !((1 << (wStatus - ID_STATUS_OFFLINE)) & HIWORD(dwLocalMask)) | searchResult; +				} +				return 0 | searchResult; +			} +		} +		// check the proto, use it as a base filter result for all further checks +		if (g_CluiData.bFilterEffective & CLVM_FILTER_PROTOS) { +			mir_snprintf(szTemp, SIZEOF(szTemp), "%s|", szProto); +			filterResult = strstr(g_CluiData.protoFilter, szTemp) ? 1 : 0; +		} +		if (g_CluiData.bFilterEffective & CLVM_FILTER_GROUPS) { +			if (!db_get_ts(hContact, "CList", "Group", &dbv)) { +				mir_sntprintf(szGroupMask, SIZEOF(szGroupMask), _T("%s|"), &dbv.ptszVal[0]); +				filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? (filterResult | (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0)) : (filterResult & (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0)); +				mir_free(dbv.ptszVal); +			} +			else if (g_CluiData.filterFlags & CLVM_INCLUDED_UNGROUPED) +				filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 1; +			else +				filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 0; +		} +		if (g_CluiData.bFilterEffective & CLVM_FILTER_STATUS) { +			WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); +			filterResult = (g_CluiData.filterFlags & CLVM_GROUPSTATUS_OP) ? ((filterResult | ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0))) : (filterResult & ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0)); +		} +		if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG) { +			if (pdnce->dwLastMsgTime != -1) { +				DWORD now = g_CluiData.t_now; +				now -= g_CluiData.lastMsgFilter; +				if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_OLDERTHAN) +					filterResult = filterResult & (pdnce->dwLastMsgTime < now); +				else if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_NEWERTHAN) +					filterResult = filterResult & (pdnce->dwLastMsgTime > now); +			} +		} +		return (dbHidden | !filterResult | searchResult); +	} + +	return dbHidden | searchResult; +} diff --git a/plugins/Clist_modern/src/modern_row.cpp b/plugins/Clist_modern/src/modern_row.cpp index 4916f60d3f..a6bac28ed0 100644 --- a/plugins/Clist_modern/src/modern_row.cpp +++ b/plugins/Clist_modern/src/modern_row.cpp @@ -1,761 +1,762 @@ -/*
 -
 -Miranda NG: the free IM client for Microsoft* Windows*
 -
 -Copyright (c) 2012-14 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.
 -
 -Created by Anton Senko aka ZORG , tweaked by Artem Shpynov aka FYR
 -*/
 -
 -#include "hdr/modern_commonheaders.h"
 -
 -/*
 -#include <windows.h>
 -#include <commctrl.h>
 -#include <stdio.h>
 -#include <time.h>
 -#include <stddef.h>
 -#include <process.h>
 -#include <io.h>
 -#include <string.h>
 -#include <direct.h>
 -#include "resource.h"
 -#include "hdr/modern_commonheaders.h"
 -*/
 -#include "hdr/modern_row.h"
 -
 -//Futher declaration
 -void rowCalculateMinSize(ROWCELL* cell);
 -void rowEqualize(ROWCELL* cell);
 -void rowResetEmptyRects(ROWCELL* cell);
 -void rowDeleteTree(ROWCELL* cell);
 -////////
 -
 -
 -
 -//extern ROWCELL * gl_RowRoot;	// Óêàçàòåëü íà êîðíåâîé òýã  < contact> â øàáëîíå
 -//ROWOBJECTS RowTA;				// Ñòðóêòóðà, ÷åðåç êîòîðóþ îñóùåñòâëÿåòñÿ äîñòóï ê ýëåìåíòàì êîíòàêòà.
 -// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam
 -
 -
 -// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam
 -
 -char *tmplbuf;					// Áóôåð äëÿ õðàíåíèÿ øàáëîíà â òåêñòîâîì âèäå
 -
 -ROWCELL *cppInitModernRow(ROWCELL	** tabAccess)
 -{
 -	int fsize;
 -	int seq = 0;
 -	ROWCELL * RowRoot = NULL;
 -	FILE * hFile;
 -	int i=0;
 -	if (!db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT)) return NULL;
 -	tmplbuf = NULL;
 -	if ( db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT) == 1)
 -		tmplbuf = db_get_sa(NULL,"ModernData","RowTemplate");
 -	if (tmplbuf) {
 -		rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess);
 -		mir_free(tmplbuf);
 -		return RowRoot;
 -	}
 -	if (hFile = fopen("template.txt", "rb"))
 -	{
 -		fsize = _filelength(_fileno(hFile));
 -		tmplbuf = (char*)malloc(fsize+1);
 -		ZeroMemory(tmplbuf, fsize+1);
 -
 -		for (i=0; i < fsize; i++) tmplbuf[i] = getc(hFile);
 -		tmplbuf[i] = 0;
 -		i=0;
 -		rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess);
 -		db_set_s(NULL,"ModernData","RowTemplate",tmplbuf);
 -		free(tmplbuf);
 -		fclose(hFile);
 -		return RowRoot;
 -	}
 -	return NULL;
 -
 -}
 -
 -void cppDeleteTree(ROWCELL	* RowRoot)
 -{
 -	ROWCELL *rc = RowRoot;
 -	rowDeleteTree(rc);
 -}
 -
 -int cppCalculateRowHeight(ROWCELL	*RowRoot)
 -{
 -	RowRoot->h = 0;
 -	RowRoot->w = 0;
 -	rowResetEmptyRects(RowRoot);
 -	rowCalculateMinSize(RowRoot);
 -	rowEqualize(RowRoot);
 -	if (RowRoot) return RowRoot->r.bottom;
 -	return 0;
 -}
 -void cppCalculateRowItemsPos(ROWCELL	*RowRoot, int width)
 -{
 -	rowSizeWithReposition(RowRoot, width);
 -}
 -
 -// rowAddCell
 -// Âûäåëÿåò íåîáõîäèìîå êîë-âî äèí. ïàìÿòè äëÿ ñòðóêòóðû ROWCELL
 -// è ñâÿçûâàåò åå ñ äåðåâîì îïèñàíèÿ êîíòàêòà
 -// link - ïîëå child èëè next, ðîäèòåëüñêîé ñòðóêòóðû ROWCELL
 -// cont - òèï êîíòåéíåðà: ñòðîêà, ñòîëáåö èëè êîðíåâîé óçåë
 -//
 -//
 -const ROWCELL * rowAddCell(ROWCELL* &link, int cont)
 -{
 -	link = (ROWCELL*)malloc(sizeof(ROWCELL));
 -	ZeroMemory(link, sizeof(ROWCELL));
 -	link->cont = cont;
 -	return link;
 -}
 -
 -// rowDeleteTree
 -// Îñâîáîæäàåò ïàìÿòü çàíÿòóþ äåðåâîì îïèñàíèÿ êîíòàêòà
 -// cell - àäðåñ êîðíåâîãî óçëà äåðåâà îïèñàíèÿ êîíòàêòà
 -//
 -//
 -void rowDeleteTree(ROWCELL* cell)
 -{
 -	if (!cell) return;
 -	if (cell->child)
 -		rowDeleteTree((ROWCELL*)(cell->child));
 -	if (cell->next)
 -		rowDeleteTree((ROWCELL*)(cell->next));
 -	free(cell);
 -	cell = NULL;
 -	return;
 -}
 -
 -// rowParserGetNextWord
 -// Âûáèðàåò èç ïîòîêà äàííûõ (ñåé÷àñ ôàéëîâîãî) î÷åðåäíîå ñëîâî.
 -// Ñëîâîì ñ÷èòàåòñÿ ïîñëåäîâàòåëüíîñòü ñèìâîëîâ, îãðàíè÷åííàÿ çíàêàìè: SP,  < , >, ;, TAB, CR, LF
 -// ñèìâîëû îò ; è äî êîíöà ñòðîêè ñ÷èòàþòñÿ êîììåíòàðèåì.
 -// NOTE: Äàííàÿ ðåàëèçàöèÿ íå ñîâñåì ïîäõîäèò äëÿ âêëþ÷åíèÿ åå â ModernCL,
 -// à ïî ñåìó, òóò íàäî áóäåò ïåðåäåëûâàòü
 -// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
 -// hbuf - óêàçàòåëü áóôåðà
 -//
 -//
 -char * rowParserGetNextWord(char *tbuf, int &hbuf)
 -{
 -	static char buf[256];
 -	char ch;
 -
 -	int j = -1;
 -
 -	ZeroMemory(buf, 256);
 -
 -	while(tbuf[hbuf] != 0)
 -	{
 -		ch = tbuf[hbuf];
 -
 -		// Remark found
 -		if (ch == ';')
 -		{
 -			if (j >= 0) return buf;
 -
 -			while (tbuf[hbuf] != 10 && tbuf[hbuf] != 13) hbuf++;
 -		}
 -
 -		// Tag-bracers found
 -		if (!(ch == '>' && j < 0)) //not single '>' found
 -		{
 -			if ((ch == '<' || ch == '>') && j >= 0)
 -			{
 -				if (ch == '>')
 -				{
 -					if (buf[0] == '/' || buf[0] == '<')  buf[++j] = ch;
 -					hbuf++;
 -				}
 -				return buf;
 -			}
 -
 -			if (ch == ' ' || ch == 9 || ch == 10 || ch == 13 || ch == ';' || ch == '>')
 -			{
 -				if (ch == '>')
 -				{
 -					buf[++j] = ch;
 -					hbuf++;
 -				}
 -
 -				if (j >= 0) return buf;	// Word is selected
 -			}
 -			else
 -				buf[++j] = ch;
 -		}
 -		hbuf++;
 -	}
 -	return NULL;
 -}
 -
 -// rowParserGetParam
 -// èùåò è èíòåðïðåòèðóåò ñëîâà â øàáëîíå, çàêëþ÷åííûå ìåæäó òýãàìè
 -// cell - óêàçàòåëü íà òåêóùèé èíòåðïðåòèðóåìûé êîíòåéíåð øàáëîíà
 -// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
 -// hbuf - óêàçàòåëü áóôåðà
 -//
 -//
 -void rowParserGetParam(ROWCELL* &cell, char *tbuf, int &hbuf)
 -{
 -	char * word = rowParserGetNextWord(tbuf, hbuf);
 -	int param = 0;
 -
 -	if (!_strnicmp(word, "avatar",     strlen(word))) param = TC_AVATAR;
 -	else if (!_strnicmp(word, "text1",      strlen(word))) param = TC_TEXT1;
 -	else if (!_strnicmp(word, "text2",      strlen(word))) param = TC_TEXT2;
 -	else if (!_strnicmp(word, "text3",      strlen(word))) param = TC_TEXT3;
 -	else if (!_strnicmp(word, "status",     strlen(word))) param = TC_STATUS;
 -	else if (!_strnicmp(word, "extra",      strlen(word))) param = TC_EXTRA;
 -	else if (!_strnicmp(word, "extra1",     strlen(word))) param = TC_EXTRA1;
 -	else if (!_strnicmp(word, "extra2",     strlen(word))) param = TC_EXTRA2;
 -	else if (!_strnicmp(word, "extra3",     strlen(word))) param = TC_EXTRA3;
 -	else if (!_strnicmp(word, "extra4",     strlen(word))) param = TC_EXTRA4;
 -	else if (!_strnicmp(word, "extra5",     strlen(word))) param = TC_EXTRA5;
 -	else if (!_strnicmp(word, "extra6",     strlen(word))) param = TC_EXTRA6;
 -	else if (!_strnicmp(word, "extra7",     strlen(word))) param = TC_EXTRA7;
 -	else if (!_strnicmp(word, "extra8",     strlen(word))) param = TC_EXTRA8;
 -	else if (!_strnicmp(word, "extra9",     strlen(word))) param = TC_EXTRA9;
 -	else if (!_strnicmp(word, "time",       strlen(word))) param = TC_TIME;
 -	else if (!_strnicmp(word, "space",      strlen(word))) param = TC_SPACE;
 -	else if (!_strnicmp(word, "fspace",      strlen(word))) param = TC_FIXED;
 -
 -	else if (!_strnicmp(word, "left",       strlen(word))) param = TC_LEFT;
 -	else if (!_strnicmp(word, "top",        strlen(word))) param = TC_TOP;
 -	else if (!_strnicmp(word, "vcenter",    strlen(word))) param = TC_VCENTER;
 -	else if (!_strnicmp(word, "hcenter",    strlen(word))) param = TC_HCENTER;
 -	else if (!_strnicmp(word, "right",      strlen(word))) param = TC_RIGHT;
 -	else if (!_strnicmp(word, "bottom",     strlen(word))) param = TC_BOTTOM;
 -
 -	else if (!_strnicmp(word, "layer",      strlen(word))) cell->layer = TRUE;
 -
 -	else if (!_strnicmp(word, "width",      strlen(word))) param = TC_WIDTH;
 -	else if (!_strnicmp(word, "height",     strlen(word))) param = TC_HEIGHT;
 -
 -	else
 -	{
 -		hbuf -= (int)strlen(word);
 -		return;
 -	}
 -
 -	if (param>TC_TEXT3 && param != TC_SPACE) cell->hasfixed = 1;
 -
 -	switch (param)
 -	{
 -	case TC_TEXT1:
 -	case TC_TEXT2:
 -	case TC_TEXT3:
 -	case TC_SPACE:
 -		cell->sizing = 1;
 -	case TC_STATUS:
 -	case TC_AVATAR:
 -	case TC_EXTRA:
 -	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:
 -	case TC_TIME:
 -	case TC_FIXED:
 -
 -		cell->type = param;
 -		break;
 -
 -	case TC_HCENTER:
 -	case TC_RIGHT:
 -		cell->halign = param;
 -		break;
 -
 -	case TC_VCENTER:
 -	case TC_BOTTOM:
 -		cell->valign = param;
 -		break;
 -
 -	case TC_WIDTH:
 -		word = rowParserGetNextWord(tbuf, hbuf);
 -		param = atoi(word);
 -		cell->w = param;
 -		break;
 -
 -	case TC_HEIGHT:
 -		word = rowParserGetNextWord(tbuf, hbuf);
 -		param = atoi(word);
 -		cell->h = param;
 -	}
 -
 -	rowParserGetParam(cell, tbuf, hbuf);
 -	return;
 -}
 -// rowParse
 -// Èùåò â øàáëîíå òåãè  < contact>,  < tr> è  < tc>, è äîáàâëÿåò ñîîòâåòñòâóþùèå óçëû
 -// â äåðåâî îïèñàíèÿ êîíòàêòà
 -// cell - ïîëå child èëè next ðîäèòåëüñêîãî êîíòåéíåðà
 -// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð
 -// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
 -// hbuf - óêàçàòåëü áóôåðà
 -// sequence - íóæíî çàäàâàòü 0, ýòî î÷åðåäíîñòü íàõîæäåíèÿ
 -//
 -BOOL rowParse(ROWCELL* &cell, ROWCELL* parent, char *tbuf, int &hbuf, int &sequence, ROWCELL** RowTabAccess )
 -{
 -	char * word;
 -	word = rowParserGetNextWord(tbuf, hbuf);
 -	int cont;
 -
 -	if      (!_strnicmp(word, "<tr",   strlen(word))  || !_strnicmp(word, "<tr>",   strlen(word))) cont = TC_ROW;
 -	else if (!_strnicmp(word, "<tc",   strlen(word))  || !_strnicmp(word, "<tc>",   strlen(word))) cont = TC_COL;
 -	else if (!_strnicmp(word, "/>",     strlen(word)) ||
 -		!_strnicmp(word, "</tr>",  strlen(word)) ||
 -		!_strnicmp(word, "</tc>",  strlen(word))) return TRUE;
 -	else return FALSE;
 -
 -	rowAddCell(cell, cont);
 -	rowParserGetParam(cell, tbuf, hbuf);
 -	if (cell->type != 0 && cell->type != TC_SPACE && cell->type != TC_FIXED)
 -		RowTabAccess[sequence++] = cell;
 -
 -	if (!rowParse(cell->child, cell, tbuf, hbuf, sequence,RowTabAccess))
 -		return FALSE;
 -
 -	if (!parent)
 -	{
 -		RowTabAccess[sequence] = NULL;
 -		return TRUE;
 -	}
 -
 -	if (!rowParse(cell->next, parent, tbuf, hbuf, sequence,RowTabAccess))
 -		return FALSE;
 -
 -	parent->sizing |= cell->sizing;
 -	parent->hasfixed |= cell->hasfixed;
 -	return TRUE;
 -}
 -
 -void rowResetEmptyRects(ROWCELL* cell)
 -{
 -	if (!cell) return;
 -	if (cell->type == 0)
 -	{
 -		SetRect(&(cell->r), 0, 0, 0, 0);
 -		cell->full_width = 0;
 -		cell->fixed_width = 0;
 -	}
 -	rowResetEmptyRects(cell->child);
 -	rowResetEmptyRects(cell->next);
 -}
 -
 -// rowCalculateMinSize
 -// Âû÷èñëåíèå ìèíèìàëüíûõ ðàçìåðîâ êàæäîãî êîíòåéíåðà äåðåâà îïèñàíèÿ êîíòàêòà
 -// Ýòà ôó-ÿ ÂÑÅÃÄÀ! äîëæíà âûçûâàòüñÿ íåïîñðåäñòâåííî ïåðåä rowPositioning
 -// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
 -// NOTE: Ïåðåä âûçûâîì rowCalculateMinSize íåîáõîäèìî çàïîëíèòü ïîëÿ w è h ñòðóêòóðû RowTA, äëÿ êàæäîãî ýëåìåíòà
 -//
 -void rowCalculateMinSize(ROWCELL* cell)
 -{
 -	ROWCELL* curchild = NULL;
 -	int w = 0, h = 0;
 -	int wl = 0, hl = 0;
 -	int fullWidth = 0;
 -	if (!cell) return;
 -
 -	cell->r.left	 = 0;
 -	cell->r.top		 = 0;
 -
 -	if (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE)
 -		cell->r.right	 = cell->w;
 -	else
 -		cell->r.right	 = 0;
 -
 -	cell->r.bottom	 = cell->h;
 -
 -	rowCalculateMinSize(cell->child);
 -	rowCalculateMinSize(cell->next);
 -
 -	if (!(curchild = cell->child)) return;
 -
 -	if (cell->cont == TC_ROW)
 -	{
 -		do
 -		{
 -			h = max(h, curchild->r.bottom);
 -
 -			if (curchild->layer)
 -			{
 -				//w = max(w, curchild->r.right);
 -				wl += curchild->r.right;
 -				fullWidth = max(fullWidth,max(curchild->full_width,curchild->w));
 -			}
 -			else
 -			{
 -				w += curchild->r.right;
 -				fullWidth += max(curchild->full_width,curchild->w);
 -			}
 -		}
 -		while (curchild = curchild->next);
 -	}
 -
 -	if (cell->cont == TC_COL)
 -	{
 -		while (curchild)
 -		{
 -			w = max(w, curchild->r.right);
 -			fullWidth = max(fullWidth,max(curchild->full_width,curchild->w));
 -
 -			if (curchild->layer)
 -			{
 -				hl = curchild->r.bottom;
 -				//				h = max(h, curchild->r.bottom);
 -			}
 -			else
 -				h += curchild->r.bottom;
 -
 -			curchild = curchild->next;
 -		}
 -	}
 -
 -	cell->r.right  = max(max(w, cell->r.right),wl);
 -	cell->r.bottom = max(max(h, cell->r.bottom),hl);
 -	cell->full_width = max(fullWidth,cell->full_width);
 -	cell->fixed_width = max(cell->fixed_width,cell->r.right);
 -	return;
 -}
 -
 -// void rowEqualise(ROWCELL* cell)
 -//
 -// Óðàâíèâàåò âûñîòû äåòåé âíóòðè ñòðîê, è øèðèíû äåòåé âíóòðè ñòîáöîâ
 -// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
 -//
 -void rowEqualize(ROWCELL* cell)
 -{
 -	ROWCELL* curchild = NULL;
 -	if (!cell) return;
 -	rowEqualize(cell->child);
 -	rowEqualize(cell->next);
 -
 -	if (!(curchild = cell->child)) return;
 -
 -	if (cell->cont == TC_ROW)
 -	{
 -		do
 -		{
 -			if (curchild->layer) continue;
 -			curchild->r.bottom = cell->r.bottom;
 -		}
 -		while (curchild = curchild->next);
 -	}
 -
 -	if (cell->cont == TC_COL)
 -	{
 -		do
 -		{
 -			if (curchild->layer) continue;
 -			curchild->r.right = cell->r.right;
 -		}
 -		while (curchild = curchild->next);
 -	}
 -
 -
 -	//rowEqualize(cell->child);
 -	//rowEqualize(cell->next);
 -}
 -
 -// void rowPlacing(pttCell cell, pttCell parent)
 -//
 -// Ïîçèöèîíèðóåò ýëåìåíò ñòðîêè êîíòàêòà â åãî êîíòåéíåðå
 -// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð
 -//
 -void rowPlacing(pROWCELL cell)
 -{
 -	if (cell->type == 0) return;
 -
 -	switch(cell->type)
 -	{
 -	case TC_TEXT1:
 -	case TC_TEXT2:
 -	case TC_TEXT3:
 -	case TC_SPACE:
 -		cell->r.right += cell->r.left;
 -		break;
 -	default:
 -		{
 -			switch(cell->halign)
 -			{
 -			case TC_LEFT:
 -				break;
 -			case TC_HCENTER:
 -				cell->r.left += (cell->r.right - cell->w)/2;
 -				break;
 -			case TC_RIGHT:
 -				cell->r.left += cell->r.right - cell->w;
 -			}
 -			cell->r.right = cell->r.left + cell->w;
 -		}
 -	}
 -
 -	switch(cell->valign)
 -	{
 -	case TC_TOP:
 -		break;
 -	case TC_VCENTER:
 -		cell->r.top += (cell->r.bottom - cell->h)/2;
 -		break;
 -	case TC_BOTTOM:
 -		cell->r.top += cell->r.bottom - cell->h;
 -	}
 -	cell->r.bottom = cell->r.top + cell->h;
 -}
 -
 -// void ttTLProc(pROWCELL cell, pROWCELL parent)
 -//
 -// Ïîçèöèîíèðóåò ïëàâàþùèé êîíòåéíåð, âíóòðè ðîäèòåëüñêîãî
 -// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð
 -// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð
 -//
 -void rowLayerProc(pROWCELL cell, pROWCELL parent)
 -{
 -	if (cell->sizing)
 -	{
 -		cell->r.left = parent->r.left;
 -		//cell->r.right += cell->r.left;
 -	}
 -	else
 -	{
 -		switch(cell->halign)
 -		{
 -		case TC_LEFT:
 -			cell->r.left = parent->r.left;
 -			break;
 -		case TC_HCENTER:
 -			cell->r.left = parent->r.left + (parent->r.right - cell->r.right)/2;
 -			break;
 -		case TC_RIGHT:
 -			cell->r.left = parent->r.left + parent->r.right - cell->r.right;
 -		}
 -	}
 -
 -	switch(cell->valign)
 -	{
 -	case TC_TOP:
 -		cell->r.top = parent->r.top;
 -		break;
 -	case TC_VCENTER:
 -		cell->r.top = parent->r.top + (parent->r.bottom - cell->r.bottom)/2;
 -		break;
 -	case TC_BOTTOM:
 -		cell->r.top = parent->r.top + parent->r.bottom - cell->r.bottom;
 -		break;
 -	}
 -}
 -
 -// void rowPositioning(pROWCELL cell, int &dist)
 -//
 -// Âû÷èñëÿåò ïðÿìîóãîëüíèêè ýëåìåíòîâ êîíòàêòà, ó÷èòûâàÿ âûðàâíèâàíèå â êîíòåéíåðå
 -// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
 -// dist - íîâàÿ øèðèíà êîíòàêòà
 -//
 -void rowPositioning(pROWCELL cell, int &dist)
 -{
 -	ROWCELL* curchild = NULL;
 -
 -	int x = cell->r.left;
 -	int y = cell->r.top;
 -
 -	int h = cell->r.bottom;
 -	int w = dist;
 -
 -	int r = 0;
 -	int size = 0;
 -	int cw = 0;
 -	int fixedsized = 0;
 -	int autosized = 0;
 -	int dummy = 0;
 -
 -	// Êîðððåêòèðîâêà íàçíà÷àåìîé øèðèíû dist
 -	if (w < cell->r.right && (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE) || !cell->sizing)
 -		dist = w = cell->r.right;
 -
 -	cell->r.right = dist;
 -	dummy = dist;
 -	if (!(curchild = cell->child))
 -	{
 -		rowPlacing(cell);
 -		return;
 -	}
 -
 -	// Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòðîêå
 -	if (cell->cont == TC_ROW)
 -	{
 -		fixedsized = cell->fixed_width;
 -		while (curchild)
 -		{
 -			// Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tc
 -			if (curchild->layer)
 -			{
 -				curchild = curchild->next;
 -				continue;
 -			}
 -
 -			cw += curchild->r.right;
 -
 -			if (curchild->sizing)
 -			{
 -				autosized += max(curchild->w,curchild->full_width);
 -				r++;
 -			}
 -			else
 -				size += curchild->r.right;
 -
 -			curchild = curchild->next;
 -		}
 -
 -		w -= size;
 -		fixedsized -= size;
 -
 -		if (r == 0)
 -		{
 -			switch(cell->halign)
 -			{
 -			case TC_HCENTER:
 -				x += (dist - cw)/2;// - 1;
 -				break;
 -			case TC_RIGHT:
 -				x += dist - cw;
 -				break;
 -			}
 -		}
 -
 -
 -		curchild = cell->child;
 -
 -		size = 0;
 -		while(curchild)
 -		{
 -			if (curchild->layer)
 -			{
 -				//int dummy = 0;
 -				rowLayerProc(curchild, cell);
 -				rowPositioning(curchild, dummy);
 -			}
 -			else
 -			{
 -				curchild->r.top = cell->r.top;
 -				curchild->r.left = x;
 -
 -
 -				w -= size;
 -				if (curchild->sizing)
 -				{
 -					size = w;
 -					r--;
 -				}
 -				else
 -					size = curchild->r.right;
 -
 -				rowPositioning(curchild, size);
 -				x += size;
 -
 -				if (!curchild->sizing)
 -					size = 0;
 -			}
 -
 -			curchild = curchild->next;
 -		}
 -	}
 -
 -	// Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòîëáöå
 -	if (cell->cont == TC_COL)
 -	{
 -		while (curchild)
 -		{
 -			// Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tr
 -			if (curchild->layer)
 -			{
 -				curchild = curchild->next;
 -				continue;
 -			}
 -
 -			size += curchild->r.bottom;
 -			curchild = curchild->next;
 -		}
 -
 -		if (h > size)
 -		{
 -			switch(cell->valign)
 -			{
 -			case TC_VCENTER:
 -				y += (h - size) / 2;
 -				break;
 -			case TC_BOTTOM:
 -				y += (h - size);
 -				break;
 -			}
 -		}
 -
 -		curchild = cell->child;
 -		while(curchild)
 -		{
 -			if (curchild->layer)
 -			{
 -				rowLayerProc(curchild, cell);
 -				rowPositioning(curchild, dummy);
 -			}
 -			else
 -			{
 -				curchild->r.top = y;
 -				y += curchild->r.bottom;
 -
 -				curchild->r.left  = cell->r.left;
 -				curchild->r.right = dist;
 -
 -				rowPositioning(curchild, size);
 -
 -			}
 -
 -			curchild = curchild->next;
 -		}
 -	}
 -
 -	rowPlacing(cell);
 -
 -}
 -
 -// void rowSizeWithReposition(ROWCELL* &root, int width)
 -//
 -// Ïðîèçâîäèò ïðîñ÷åò è ïîçèöèîíèðîâàíèå ýëåìåíòîâ êîòàêòà
 -// Ïåðåä âûçîâîì íåîáõîäèìî çàïîëíèòü ñòðóêòóðó RowTA
 -//
 -void rowSizeWithReposition(ROWCELL* &root, int width)
 -{
 -	root->h = 0;
 -	root->w = 0;
 -	rowCalculateMinSize(root);
 -	rowEqualize(root);
 -	rowPositioning(root, width);
 -	root->h = root->r.bottom;
 -	root->w = root->r.right;
 -}
 -
 -#undef _CPPCODE
 +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 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. + +Created by Anton Senko aka ZORG , tweaked by Artem Shpynov aka FYR +*/ + +#include "hdr/modern_commonheaders.h" + +/* +#include <windows.h> +#include <commctrl.h> +#include <stdio.h> +#include <time.h> +#include <stddef.h> +#include <process.h> +#include <io.h> +#include <string.h> +#include <direct.h> +#include "resource.h" +#include "hdr/modern_commonheaders.h" +*/ +#include "hdr/modern_row.h" + +//Futher declaration +void rowCalculateMinSize(ROWCELL* cell); +void rowEqualize(ROWCELL* cell); +void rowResetEmptyRects(ROWCELL* cell); +void rowDeleteTree(ROWCELL* cell); +//////// + + + +//extern ROWCELL * gl_RowRoot;	// Óêàçàòåëü íà êîðíåâîé òýã  < contact> â øàáëîíå +//ROWOBJECTS RowTA;				// Ñòðóêòóðà, ÷åðåç êîòîðóþ îñóùåñòâëÿåòñÿ äîñòóï ê ýëåìåíòàì êîíòàêòà. +// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam + + +// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam + +char *tmplbuf;					// Áóôåð äëÿ õðàíåíèÿ øàáëîíà â òåêñòîâîì âèäå + +ROWCELL *cppInitModernRow(ROWCELL	** tabAccess) +{ +	int fsize; +	int seq = 0; +	ROWCELL * RowRoot = NULL; +	FILE * hFile; +	int i=0; +	if (!db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT)) return NULL; +	tmplbuf = NULL; +	if ( db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT) == 1) +		tmplbuf = db_get_sa(NULL,"ModernData","RowTemplate"); +	if (tmplbuf) { +		rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess); +		mir_free(tmplbuf); +		return RowRoot; +	} +	if (hFile = fopen("template.txt", "rb")) +	{ +		fsize = _filelength(_fileno(hFile)); +		tmplbuf = (char*)malloc(fsize+1); +		ZeroMemory(tmplbuf, fsize+1); + +		for (i=0; i < fsize; i++) tmplbuf[i] = getc(hFile); +		tmplbuf[i] = 0; +		i=0; +		rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess); +		db_set_s(NULL,"ModernData","RowTemplate",tmplbuf); +		free(tmplbuf); +		fclose(hFile); +		return RowRoot; +	} +	return NULL; + +} + +void cppDeleteTree(ROWCELL	* RowRoot) +{ +	ROWCELL *rc = RowRoot; +	rowDeleteTree(rc); +} + +int cppCalculateRowHeight(ROWCELL	*RowRoot) +{ +	if (RowRoot == NULL) +		return 0; +	RowRoot->h = 0; +	RowRoot->w = 0; +	rowResetEmptyRects(RowRoot); +	rowCalculateMinSize(RowRoot); +	rowEqualize(RowRoot); +	return RowRoot->r.bottom; +} +void cppCalculateRowItemsPos(ROWCELL	*RowRoot, int width) +{ +	rowSizeWithReposition(RowRoot, width); +} + +// rowAddCell +// Âûäåëÿåò íåîáõîäèìîå êîë-âî äèí. ïàìÿòè äëÿ ñòðóêòóðû ROWCELL +// è ñâÿçûâàåò åå ñ äåðåâîì îïèñàíèÿ êîíòàêòà +// link - ïîëå child èëè next, ðîäèòåëüñêîé ñòðóêòóðû ROWCELL +// cont - òèï êîíòåéíåðà: ñòðîêà, ñòîëáåö èëè êîðíåâîé óçåë +// +// +const ROWCELL * rowAddCell(ROWCELL* &link, int cont) +{ +	link = (ROWCELL*)malloc(sizeof(ROWCELL)); +	ZeroMemory(link, sizeof(ROWCELL)); +	link->cont = cont; +	return link; +} + +// rowDeleteTree +// Îñâîáîæäàåò ïàìÿòü çàíÿòóþ äåðåâîì îïèñàíèÿ êîíòàêòà +// cell - àäðåñ êîðíåâîãî óçëà äåðåâà îïèñàíèÿ êîíòàêòà +// +// +void rowDeleteTree(ROWCELL* cell) +{ +	if (!cell) return; +	if (cell->child) +		rowDeleteTree((ROWCELL*)(cell->child)); +	if (cell->next) +		rowDeleteTree((ROWCELL*)(cell->next)); +	free(cell); +	cell = NULL; +	return; +} + +// rowParserGetNextWord +// Âûáèðàåò èç ïîòîêà äàííûõ (ñåé÷àñ ôàéëîâîãî) î÷åðåäíîå ñëîâî. +// Ñëîâîì ñ÷èòàåòñÿ ïîñëåäîâàòåëüíîñòü ñèìâîëîâ, îãðàíè÷åííàÿ çíàêàìè: SP,  < , >, ;, TAB, CR, LF +// ñèìâîëû îò ; è äî êîíöà ñòðîêè ñ÷èòàþòñÿ êîììåíòàðèåì. +// NOTE: Äàííàÿ ðåàëèçàöèÿ íå ñîâñåì ïîäõîäèò äëÿ âêëþ÷åíèÿ åå â ModernCL, +// à ïî ñåìó, òóò íàäî áóäåò ïåðåäåëûâàòü +// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà +// hbuf - óêàçàòåëü áóôåðà +// +// +char * rowParserGetNextWord(char *tbuf, int &hbuf) +{ +	static char buf[256]; +	char ch; + +	int j = -1; + +	ZeroMemory(buf, 256); + +	while(tbuf[hbuf] != 0) +	{ +		ch = tbuf[hbuf]; + +		// Remark found +		if (ch == ';') +		{ +			if (j >= 0) return buf; + +			while (tbuf[hbuf] != 10 && tbuf[hbuf] != 13) hbuf++; +		} + +		// Tag-bracers found +		if (!(ch == '>' && j < 0)) //not single '>' found +		{ +			if ((ch == '<' || ch == '>') && j >= 0) +			{ +				if (ch == '>') +				{ +					if (buf[0] == '/' || buf[0] == '<')  buf[++j] = ch; +					hbuf++; +				} +				return buf; +			} + +			if (ch == ' ' || ch == 9 || ch == 10 || ch == 13 || ch == ';' || ch == '>') +			{ +				if (ch == '>') +				{ +					buf[++j] = ch; +					hbuf++; +				} + +				if (j >= 0) return buf;	// Word is selected +			} +			else +				buf[++j] = ch; +		} +		hbuf++; +	} +	return NULL; +} + +// rowParserGetParam +// èùåò è èíòåðïðåòèðóåò ñëîâà â øàáëîíå, çàêëþ÷åííûå ìåæäó òýãàìè +// cell - óêàçàòåëü íà òåêóùèé èíòåðïðåòèðóåìûé êîíòåéíåð øàáëîíà +// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà +// hbuf - óêàçàòåëü áóôåðà +// +// +void rowParserGetParam(ROWCELL* &cell, char *tbuf, int &hbuf) +{ +	char * word = rowParserGetNextWord(tbuf, hbuf); +	int param = 0; + +	if (!_strnicmp(word, "avatar",     strlen(word))) param = TC_AVATAR; +	else if (!_strnicmp(word, "text1",      strlen(word))) param = TC_TEXT1; +	else if (!_strnicmp(word, "text2",      strlen(word))) param = TC_TEXT2; +	else if (!_strnicmp(word, "text3",      strlen(word))) param = TC_TEXT3; +	else if (!_strnicmp(word, "status",     strlen(word))) param = TC_STATUS; +	else if (!_strnicmp(word, "extra",      strlen(word))) param = TC_EXTRA; +	else if (!_strnicmp(word, "extra1",     strlen(word))) param = TC_EXTRA1; +	else if (!_strnicmp(word, "extra2",     strlen(word))) param = TC_EXTRA2; +	else if (!_strnicmp(word, "extra3",     strlen(word))) param = TC_EXTRA3; +	else if (!_strnicmp(word, "extra4",     strlen(word))) param = TC_EXTRA4; +	else if (!_strnicmp(word, "extra5",     strlen(word))) param = TC_EXTRA5; +	else if (!_strnicmp(word, "extra6",     strlen(word))) param = TC_EXTRA6; +	else if (!_strnicmp(word, "extra7",     strlen(word))) param = TC_EXTRA7; +	else if (!_strnicmp(word, "extra8",     strlen(word))) param = TC_EXTRA8; +	else if (!_strnicmp(word, "extra9",     strlen(word))) param = TC_EXTRA9; +	else if (!_strnicmp(word, "time",       strlen(word))) param = TC_TIME; +	else if (!_strnicmp(word, "space",      strlen(word))) param = TC_SPACE; +	else if (!_strnicmp(word, "fspace",      strlen(word))) param = TC_FIXED; + +	else if (!_strnicmp(word, "left",       strlen(word))) param = TC_LEFT; +	else if (!_strnicmp(word, "top",        strlen(word))) param = TC_TOP; +	else if (!_strnicmp(word, "vcenter",    strlen(word))) param = TC_VCENTER; +	else if (!_strnicmp(word, "hcenter",    strlen(word))) param = TC_HCENTER; +	else if (!_strnicmp(word, "right",      strlen(word))) param = TC_RIGHT; +	else if (!_strnicmp(word, "bottom",     strlen(word))) param = TC_BOTTOM; + +	else if (!_strnicmp(word, "layer",      strlen(word))) cell->layer = TRUE; + +	else if (!_strnicmp(word, "width",      strlen(word))) param = TC_WIDTH; +	else if (!_strnicmp(word, "height",     strlen(word))) param = TC_HEIGHT; + +	else +	{ +		hbuf -= (int)strlen(word); +		return; +	} + +	if (param>TC_TEXT3 && param != TC_SPACE) cell->hasfixed = 1; + +	switch (param) +	{ +	case TC_TEXT1: +	case TC_TEXT2: +	case TC_TEXT3: +	case TC_SPACE: +		cell->sizing = 1; +	case TC_STATUS: +	case TC_AVATAR: +	case TC_EXTRA: +	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: +	case TC_TIME: +	case TC_FIXED: + +		cell->type = param; +		break; + +	case TC_HCENTER: +	case TC_RIGHT: +		cell->halign = param; +		break; + +	case TC_VCENTER: +	case TC_BOTTOM: +		cell->valign = param; +		break; + +	case TC_WIDTH: +		word = rowParserGetNextWord(tbuf, hbuf); +		param = atoi(word); +		cell->w = param; +		break; + +	case TC_HEIGHT: +		word = rowParserGetNextWord(tbuf, hbuf); +		param = atoi(word); +		cell->h = param; +	} + +	rowParserGetParam(cell, tbuf, hbuf); +	return; +} +// rowParse +// Èùåò â øàáëîíå òåãè  < contact>,  < tr> è  < tc>, è äîáàâëÿåò ñîîòâåòñòâóþùèå óçëû +// â äåðåâî îïèñàíèÿ êîíòàêòà +// cell - ïîëå child èëè next ðîäèòåëüñêîãî êîíòåéíåðà +// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð +// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà +// hbuf - óêàçàòåëü áóôåðà +// sequence - íóæíî çàäàâàòü 0, ýòî î÷åðåäíîñòü íàõîæäåíèÿ +// +BOOL rowParse(ROWCELL* &cell, ROWCELL* parent, char *tbuf, int &hbuf, int &sequence, ROWCELL** RowTabAccess ) +{ +	char * word; +	word = rowParserGetNextWord(tbuf, hbuf); +	int cont; + +	if      (!_strnicmp(word, "<tr",   strlen(word))  || !_strnicmp(word, "<tr>",   strlen(word))) cont = TC_ROW; +	else if (!_strnicmp(word, "<tc",   strlen(word))  || !_strnicmp(word, "<tc>",   strlen(word))) cont = TC_COL; +	else if (!_strnicmp(word, "/>",     strlen(word)) || +		!_strnicmp(word, "</tr>",  strlen(word)) || +		!_strnicmp(word, "</tc>",  strlen(word))) return TRUE; +	else return FALSE; + +	rowAddCell(cell, cont); +	rowParserGetParam(cell, tbuf, hbuf); +	if (cell->type != 0 && cell->type != TC_SPACE && cell->type != TC_FIXED) +		RowTabAccess[sequence++] = cell; + +	if (!rowParse(cell->child, cell, tbuf, hbuf, sequence,RowTabAccess)) +		return FALSE; + +	if (!parent) +	{ +		RowTabAccess[sequence] = NULL; +		return TRUE; +	} + +	if (!rowParse(cell->next, parent, tbuf, hbuf, sequence,RowTabAccess)) +		return FALSE; + +	parent->sizing |= cell->sizing; +	parent->hasfixed |= cell->hasfixed; +	return TRUE; +} + +void rowResetEmptyRects(ROWCELL* cell) +{ +	if (!cell) return; +	if (cell->type == 0) +	{ +		SetRect(&(cell->r), 0, 0, 0, 0); +		cell->full_width = 0; +		cell->fixed_width = 0; +	} +	rowResetEmptyRects(cell->child); +	rowResetEmptyRects(cell->next); +} + +// rowCalculateMinSize +// Âû÷èñëåíèå ìèíèìàëüíûõ ðàçìåðîâ êàæäîãî êîíòåéíåðà äåðåâà îïèñàíèÿ êîíòàêòà +// Ýòà ôó-ÿ ÂÑÅÃÄÀ! äîëæíà âûçûâàòüñÿ íåïîñðåäñòâåííî ïåðåä rowPositioning +// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà +// NOTE: Ïåðåä âûçûâîì rowCalculateMinSize íåîáõîäèìî çàïîëíèòü ïîëÿ w è h ñòðóêòóðû RowTA, äëÿ êàæäîãî ýëåìåíòà +// +void rowCalculateMinSize(ROWCELL* cell) +{ +	ROWCELL* curchild = NULL; +	int w = 0, h = 0; +	int wl = 0, hl = 0; +	int fullWidth = 0; +	if (!cell) return; + +	cell->r.left	 = 0; +	cell->r.top		 = 0; + +	if (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE) +		cell->r.right	 = cell->w; +	else +		cell->r.right	 = 0; + +	cell->r.bottom	 = cell->h; + +	rowCalculateMinSize(cell->child); +	rowCalculateMinSize(cell->next); + +	if (!(curchild = cell->child)) return; + +	if (cell->cont == TC_ROW) +	{ +		do +		{ +			h = max(h, curchild->r.bottom); + +			if (curchild->layer) +			{ +				//w = max(w, curchild->r.right); +				wl += curchild->r.right; +				fullWidth = max(fullWidth,max(curchild->full_width,curchild->w)); +			} +			else +			{ +				w += curchild->r.right; +				fullWidth += max(curchild->full_width,curchild->w); +			} +		} +		while (curchild = curchild->next); +	} + +	if (cell->cont == TC_COL) +	{ +		while (curchild) +		{ +			w = max(w, curchild->r.right); +			fullWidth = max(fullWidth,max(curchild->full_width,curchild->w)); + +			if (curchild->layer) +			{ +				hl = curchild->r.bottom; +				//				h = max(h, curchild->r.bottom); +			} +			else +				h += curchild->r.bottom; + +			curchild = curchild->next; +		} +	} + +	cell->r.right  = max(max(w, cell->r.right),wl); +	cell->r.bottom = max(max(h, cell->r.bottom),hl); +	cell->full_width = max(fullWidth,cell->full_width); +	cell->fixed_width = max(cell->fixed_width,cell->r.right); +	return; +} + +// void rowEqualise(ROWCELL* cell) +// +// Óðàâíèâàåò âûñîòû äåòåé âíóòðè ñòðîê, è øèðèíû äåòåé âíóòðè ñòîáöîâ +// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà +// +void rowEqualize(ROWCELL* cell) +{ +	ROWCELL* curchild = NULL; +	if (!cell) return; +	rowEqualize(cell->child); +	rowEqualize(cell->next); + +	if (!(curchild = cell->child)) return; + +	if (cell->cont == TC_ROW) +	{ +		do +		{ +			if (curchild->layer) continue; +			curchild->r.bottom = cell->r.bottom; +		} +		while (curchild = curchild->next); +	} + +	if (cell->cont == TC_COL) +	{ +		do +		{ +			if (curchild->layer) continue; +			curchild->r.right = cell->r.right; +		} +		while (curchild = curchild->next); +	} + + +	//rowEqualize(cell->child); +	//rowEqualize(cell->next); +} + +// void rowPlacing(pttCell cell, pttCell parent) +// +// Ïîçèöèîíèðóåò ýëåìåíò ñòðîêè êîíòàêòà â åãî êîíòåéíåðå +// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð +// +void rowPlacing(pROWCELL cell) +{ +	if (cell->type == 0) return; + +	switch(cell->type) +	{ +	case TC_TEXT1: +	case TC_TEXT2: +	case TC_TEXT3: +	case TC_SPACE: +		cell->r.right += cell->r.left; +		break; +	default: +		{ +			switch(cell->halign) +			{ +			case TC_LEFT: +				break; +			case TC_HCENTER: +				cell->r.left += (cell->r.right - cell->w)/2; +				break; +			case TC_RIGHT: +				cell->r.left += cell->r.right - cell->w; +			} +			cell->r.right = cell->r.left + cell->w; +		} +	} + +	switch(cell->valign) +	{ +	case TC_TOP: +		break; +	case TC_VCENTER: +		cell->r.top += (cell->r.bottom - cell->h)/2; +		break; +	case TC_BOTTOM: +		cell->r.top += cell->r.bottom - cell->h; +	} +	cell->r.bottom = cell->r.top + cell->h; +} + +// void ttTLProc(pROWCELL cell, pROWCELL parent) +// +// Ïîçèöèîíèðóåò ïëàâàþùèé êîíòåéíåð, âíóòðè ðîäèòåëüñêîãî +// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð +// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð +// +void rowLayerProc(pROWCELL cell, pROWCELL parent) +{ +	if (cell->sizing) +	{ +		cell->r.left = parent->r.left; +		//cell->r.right += cell->r.left; +	} +	else +	{ +		switch(cell->halign) +		{ +		case TC_LEFT: +			cell->r.left = parent->r.left; +			break; +		case TC_HCENTER: +			cell->r.left = parent->r.left + (parent->r.right - cell->r.right)/2; +			break; +		case TC_RIGHT: +			cell->r.left = parent->r.left + parent->r.right - cell->r.right; +		} +	} + +	switch(cell->valign) +	{ +	case TC_TOP: +		cell->r.top = parent->r.top; +		break; +	case TC_VCENTER: +		cell->r.top = parent->r.top + (parent->r.bottom - cell->r.bottom)/2; +		break; +	case TC_BOTTOM: +		cell->r.top = parent->r.top + parent->r.bottom - cell->r.bottom; +		break; +	} +} + +// void rowPositioning(pROWCELL cell, int &dist) +// +// Âû÷èñëÿåò ïðÿìîóãîëüíèêè ýëåìåíòîâ êîíòàêòà, ó÷èòûâàÿ âûðàâíèâàíèå â êîíòåéíåðå +// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà +// dist - íîâàÿ øèðèíà êîíòàêòà +// +void rowPositioning(pROWCELL cell, int &dist) +{ +	ROWCELL* curchild = NULL; + +	int x = cell->r.left; +	int y = cell->r.top; + +	int h = cell->r.bottom; +	int w = dist; + +	int r = 0; +	int size = 0; +	int cw = 0; +	int fixedsized = 0; +	int autosized = 0; +	int dummy = 0; + +	// Êîðððåêòèðîâêà íàçíà÷àåìîé øèðèíû dist +	if (w < cell->r.right && (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE) || !cell->sizing) +		dist = w = cell->r.right; + +	cell->r.right = dist; +	dummy = dist; +	if (!(curchild = cell->child)) +	{ +		rowPlacing(cell); +		return; +	} + +	// Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòðîêå +	if (cell->cont == TC_ROW) +	{ +		fixedsized = cell->fixed_width; +		while (curchild) +		{ +			// Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tc +			if (curchild->layer) +			{ +				curchild = curchild->next; +				continue; +			} + +			cw += curchild->r.right; + +			if (curchild->sizing) +			{ +				autosized += max(curchild->w,curchild->full_width); +				r++; +			} +			else +				size += curchild->r.right; + +			curchild = curchild->next; +		} + +		w -= size; +		fixedsized -= size; + +		if (r == 0) +		{ +			switch(cell->halign) +			{ +			case TC_HCENTER: +				x += (dist - cw)/2;// - 1; +				break; +			case TC_RIGHT: +				x += dist - cw; +				break; +			} +		} + + +		curchild = cell->child; + +		size = 0; +		while(curchild) +		{ +			if (curchild->layer) +			{ +				//int dummy = 0; +				rowLayerProc(curchild, cell); +				rowPositioning(curchild, dummy); +			} +			else +			{ +				curchild->r.top = cell->r.top; +				curchild->r.left = x; + + +				w -= size; +				if (curchild->sizing) +				{ +					size = w; +					r--; +				} +				else +					size = curchild->r.right; + +				rowPositioning(curchild, size); +				x += size; + +				if (!curchild->sizing) +					size = 0; +			} + +			curchild = curchild->next; +		} +	} + +	// Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòîëáöå +	if (cell->cont == TC_COL) +	{ +		while (curchild) +		{ +			// Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tr +			if (curchild->layer) +			{ +				curchild = curchild->next; +				continue; +			} + +			size += curchild->r.bottom; +			curchild = curchild->next; +		} + +		if (h > size) +		{ +			switch(cell->valign) +			{ +			case TC_VCENTER: +				y += (h - size) / 2; +				break; +			case TC_BOTTOM: +				y += (h - size); +				break; +			} +		} + +		curchild = cell->child; +		while(curchild) +		{ +			if (curchild->layer) +			{ +				rowLayerProc(curchild, cell); +				rowPositioning(curchild, dummy); +			} +			else +			{ +				curchild->r.top = y; +				y += curchild->r.bottom; + +				curchild->r.left  = cell->r.left; +				curchild->r.right = dist; + +				rowPositioning(curchild, size); + +			} + +			curchild = curchild->next; +		} +	} + +	rowPlacing(cell); + +} + +// void rowSizeWithReposition(ROWCELL* &root, int width) +// +// Ïðîèçâîäèò ïðîñ÷åò è ïîçèöèîíèðîâàíèå ýëåìåíòîâ êîòàêòà +// Ïåðåä âûçîâîì íåîáõîäèìî çàïîëíèòü ñòðóêòóðó RowTA +// +void rowSizeWithReposition(ROWCELL* &root, int width) +{ +	root->h = 0; +	root->w = 0; +	rowCalculateMinSize(root); +	rowEqualize(root); +	rowPositioning(root, width); +	root->h = root->r.bottom; +	root->w = root->r.right; +} + +#undef _CPPCODE diff --git a/plugins/Clist_modern/src/modern_skinbutton.cpp b/plugins/Clist_modern/src/modern_skinbutton.cpp index e0b45a2f86..a340a544e2 100644 --- a/plugins/Clist_modern/src/modern_skinbutton.cpp +++ b/plugins/Clist_modern/src/modern_skinbutton.cpp @@ -1,765 +1,769 @@ -/*
 -
 -Miranda NG: the free IM client for Microsoft* Windows*
 -
 -Copyright (c) 2012-14 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.
 -*/
 -
 -/*
 -This file contains code related to new modern free positioned skinned buttons
 -*/
 -
 -#include "hdr/modern_commonheaders.h"
 -#include "hdr/modern_skinengine.h"
 -#include "hdr/modern_clcpaint.h"
 -#include "m_api/m_skinbutton.h"
 -
 -#define MODERNSKINBUTTONCLASS "MirandaModernSkinButtonClass"
 -BOOL ModernSkinButtonModuleIsLoaded = FALSE;
 -static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg,  WPARAM wParam, LPARAM lParam);
 -int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam);
 -int SkinSelector_DeleteMask(MODERNMASK *mm);
 -HWND SetToolTip(HWND hwnd, TCHAR * tip);
 -
 -typedef struct _ModernSkinButtonCtrl
 -{
 -	HWND    hwnd;
 -	BYTE    down; // button state
 -	BYTE    focus;   // has focus (1 or 0)
 -	BYTE    hover;
 -	BYTE    IsSwitcher;
 -	BOOL    fCallOnPress;
 -	char    * ID;
 -	char    * CommandService;
 -	char    * StateService;
 -	char    * HandleService;
 -	char    * ValueDBSection;
 -	char    * ValueTypeDef;
 -	int     Left, Top, Bottom, Right;
 -	HMENU   hMenu;
 -	TCHAR   * Hint;
 -
 -} ModernSkinButtonCtrl;
 -typedef struct _HandleServiceParams
 -{
 -	HWND    hwnd;
 -	DWORD   msg;
 -	WPARAM  wParam;
 -	LPARAM  lParam;
 -	BOOL    handled;
 -} HandleServiceParams;
 -
 -static CRITICAL_SECTION csTips;
 -static HWND hwndToolTips = NULL;
 -
 -int ModernSkinButtonLoadModule()
 -{
 -	WNDCLASSEX wc;
 -	ZeroMemory(&wc, sizeof(wc));
 -	wc.cbSize         = sizeof(wc);
 -	wc.lpszClassName  = _T(MODERNSKINBUTTONCLASS);
 -	wc.lpfnWndProc    = ModernSkinButtonWndProc;
 -	wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
 -	wc.cbWndExtra     = sizeof(ModernSkinButtonCtrl*);
 -	wc.hbrBackground  = 0;
 -	wc.style          = CS_GLOBALCLASS;
 -	RegisterClassEx(&wc);
 -	InitializeCriticalSection(&csTips);
 -	ModernSkinButtonModuleIsLoaded = TRUE;
 -	return 0;
 -}
 -
 -int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam)
 -{
 -	DeleteCriticalSection(&csTips);
 -	return 0;
 -}
 -
 -static int ModernSkinButtonPaintWorker(HWND hwnd, HDC whdc)
 -{
 -	HDC hdc;
 -	HBITMAP bmp,oldbmp;
 -	RECT rc;
 -	HDC sdc = NULL;
 -	ModernSkinButtonCtrl* bct = (ModernSkinButtonCtrl *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
 -	if (!bct) return 0;
 -	if (!IsWindowVisible(hwnd)) return 0;
 -	if (!whdc && !g_CluiData.fLayered) InvalidateRect(hwnd,NULL,FALSE);
 -
 -	if (whdc && g_CluiData.fLayered) hdc = whdc;
 -	else
 -	{
 -		//sdc = GetWindowDC(GetParent(hwnd));
 -		hdc = CreateCompatibleDC(NULL);
 -	}
 -	GetClientRect(hwnd,&rc);
 -	bmp = ske_CreateDIB32(rc.right,rc.bottom);
 -	oldbmp = (HBITMAP)SelectObject(hdc,bmp);
 -	if (!g_CluiData.fLayered)
 -		ske_BltBackImage(bct->hwnd,hdc,NULL);
 -	{
 -		MODERNMASK Request = {0};
 -		//   int res;
 -		//HBRUSH br = CreateSolidBrush(RGB(255,255,255));
 -		char * Value = NULL;
 -		DWORD val = 0;
 -		{
 -			if (bct->ValueDBSection && bct->ValueTypeDef)
 -			{
 -				char * key;
 -				char * section;
 -				DWORD defval = 0;
 -				char buf[20];
 -				key = mir_strdup(bct->ValueDBSection);
 -				section = key;
 -				if (bct->ValueTypeDef[0] != 's')
 -					defval = (DWORD)atol(bct->ValueTypeDef+1);
 -				do
 -				{
 -					if (key[0] == '/') {key[0] = '\0'; key++; break;}
 -					key++;
 -				} while (key[0] != '\0');
 -				switch (bct->ValueTypeDef[0])
 -				{
 -				case 's':
 -					{
 -						Value = db_get_sa(NULL,section,key);
 -						if (!Value)
 -							Value = mir_strdup(bct->ValueTypeDef+1);
 -						break;
 -					}
 -				case 'd':
 -					defval = db_get_dw(NULL,section,key,defval);
 -					Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
 -					break;
 -				case 'w':
 -					defval = db_get_w(NULL,section,key,defval);
 -					Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
 -					break;
 -				case 'b':
 -					defval = db_get_b(NULL,section,key,defval);
 -					Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
 -					break;
 -				}
 -				mir_free(section);
 -			}
 -
 -		}
 -		g_clcPainter.AddParam(&Request,mod_CalcHash("Module"),"MButton",0);
 -		g_clcPainter.AddParam(&Request,mod_CalcHash("ID"),bct->ID,0);
 -		g_clcPainter.AddParam(&Request,mod_CalcHash("Down"),bct->down?"1":"0",0);
 -		g_clcPainter.AddParam(&Request,mod_CalcHash("Focused"),bct->focus?"1":"0",0);
 -		g_clcPainter.AddParam(&Request,mod_CalcHash("Hovered"),bct->hover?"1":"0",0);
 -		if (Value) {
 -			g_clcPainter.AddParam(&Request,mod_CalcHash("Value"),Value,0);
 -			mir_free(Value);
 -		}
 -		SkinDrawGlyphMask(hdc,&rc,&rc,&Request);
 -		SkinSelector_DeleteMask(&Request);
 -		// DeleteObject(br);
 -	}
 -
 -	if (!whdc && g_CluiData.fLayered)
 -	{
 -		RECT r;
 -		SetRect(&r,bct->Left,bct->Top,bct->Right,bct->Bottom);
 -		ske_DrawImageAt(hdc,&r);
 -		//CallingService to immeadeately update window with new image.
 -	}
 -	if (whdc && !g_CluiData.fLayered)
 -	{
 -		RECT r = {0};
 -		GetClientRect(bct->hwnd,&r);
 -		BitBlt(whdc, 0, 0, r.right,r.bottom,hdc, 0, 0, SRCCOPY);
 -	}
 -	SelectObject(hdc,oldbmp);
 -	DeleteObject(bmp);
 -	if (!whdc || !g_CluiData.fLayered)
 -	{
 -		SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
 -		DeleteDC(hdc);
 -	}
 -	//  if (sdc)
 -	//    ReleaseDC(GetParent(hwnd),sdc);
 -	return 0;
 -}
 -
 -static int ModernSkinButtonToggleDBValue(char * ValueDBSection,char *ValueTypeDef)
 -{
 -	if (ValueDBSection && ValueTypeDef)
 -	{
 -		char * key;
 -		char * section;
 -		char * val;
 -		char * val2;
 -		char * Value;
 -		long l1,l2,curval;
 -		DWORD defval = 0;
 -		//        char buf[20];
 -		key = mir_strdup(ValueDBSection);
 -		section = key;
 -		do
 -		{
 -			if (key[0] == '/') {key[0] = '\0'; key++; break;}
 -			key++;
 -		} while (key[0] != '\0');
 -
 -		val = mir_strdup(ValueTypeDef+1);
 -		val2 = val;
 -		do
 -		{
 -			if (val2[0] == '/') {val2[0] = '\0'; val2++; break;}
 -			val2++;
 -		} while (val2[0] != '\0');
 -
 -		if (ValueTypeDef[0] != 's')
 -		{
 -			l1 = (DWORD)atol(val);
 -			l2 = (DWORD)atol(val2);
 -		}
 -
 -		switch (ValueTypeDef[0]) {
 -		case 's':
 -			Value = db_get_sa(NULL,section,key);
 -			if (!Value  || (Value && mir_bool_strcmpi(Value,val2)))
 -				Value = mir_strdup(val);
 -			else
 -				Value = mir_strdup(val2);
 -			db_set_s(NULL,section,key,Value);
 -			mir_free(Value);
 -			break;
 -
 -		case 'd':
 -			curval = db_get_dw(NULL,section,key,l2);
 -			curval = (curval == l2)?l1:l2;
 -			db_set_dw(NULL,section,key,(DWORD)curval);
 -			break;
 -
 -		case 'w':
 -			curval = db_get_w(NULL,section,key,l2);
 -			curval = (curval == l2)?l1:l2;
 -			db_set_w(NULL,section,key,(WORD)curval);
 -			break;
 -
 -		case 'b':
 -			curval = db_get_b(NULL,section,key,l2);
 -			curval = (curval == l2)?l1:l2;
 -			db_set_b(NULL,section,key,(BYTE)curval);
 -			break;
 -		}
 -		mir_free(section);
 -		mir_free(val);
 -	}
 -	return 0;
 -}
 -
 -static char *_skipblank(char * str) //str will be modified;
 -{
 -	char * endstr = str+strlen(str);
 -	while ((*str == ' ' || *str == '\t') && *str != '\0') str++;
 -	while ((*endstr == ' ' || *endstr == '\t') && *endstr != '\0' && endstr < str) endstr--;
 -	if (*endstr != '\0')
 -	{
 -		endstr++;
 -		*endstr = '\0';
 -	}
 -	return str;
 -}
 -
 -static int _CallServiceStrParams(IN char * toParce, OUT int *Return)
 -{
 -	char * pszService;
 -	char * param1 = NULL;
 -	char * param2 = NULL;
 -	int paramCount = 0;
 -	int result = 0;
 -	pszService = mir_strdup(toParce);
 -	param2 = strrchr(pszService, '%');
 -	if (param2)
 -	{
 -		paramCount++;
 -		*param2 = '\0';	param2++;
 -		_skipblank(param2);
 -		if (strlen(param2) == 0) param2 = NULL;
 -	}
 -	param1 = strrchr(pszService, '%');
 -	if (param1)
 -	{
 -		paramCount++;
 -		*param1 = '\0';	param1++;
 -		_skipblank(param1);
 -		if (strlen(param1) == 0) param1 = NULL;
 -	}
 -	if (!pszService) return 0;
 -	if (strlen(pszService) == 0) {
 -		mir_free(pszService);
 -		return 0;
 -	}
 -	if (param1 && *param1 == '\"')
 -	{
 -		param1++;
 -		*(param1+strlen(param1)) = '\0';
 -	}
 -	else if (param1)
 -	{
 -		param1 = (char*)atoi(param1);
 -	}
 -	if (param2 && *param2 == '\"')
 -	{
 -		param2++;
 -		*(param2+strlen(param2)) = '\0';
 -	}
 -	else if (param2)
 -		param2 = (char*)atoi(param2);
 -
 -	if (paramCount == 1)
 -	{
 -		param1 = param2;
 -		param2 = NULL;
 -	}
 -	if (!ServiceExists(pszService))
 -	{
 -		result = 0;
 -	}
 -	else
 -	{
 -		int ret = 0;
 -		result = 1;
 -		ret = CallService(pszService, (WPARAM)param1, (WPARAM)param2);
 -		if (Return) *Return = ret;
 -	}
 -	mir_free(pszService);
 -	return result;
 -}
 -
 -
 -static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg,  WPARAM wParam, LPARAM lParam)
 -{
 -	ModernSkinButtonCtrl* bct = (msg != WM_NCCREATE)?(ModernSkinButtonCtrl *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA):0;
 -	if (bct && bct->HandleService && IsBadStringPtrA(bct->HandleService,255))
 -		bct->HandleService = NULL;
 -
 -	if (bct)
 -		if (bct->HandleService && ServiceExists(bct->HandleService)) {
 -			HandleServiceParams MSG = {0};
 -			MSG.hwnd = hwndDlg;
 -			MSG.msg = msg;
 -			MSG.wParam = wParam;
 -			MSG.lParam = lParam;
 -			int t = CallService(bct->HandleService,(WPARAM)&MSG,0);
 -			if (MSG.handled) return t;
 -		}
 -
 -	switch(msg) {
 -	case WM_NCCREATE:
 -		SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE)|BS_OWNERDRAW);
 -		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
 -		if (((CREATESTRUCT *)lParam)->lpszName) SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName);
 -		return TRUE;
 -
 -	case WM_DESTROY:
 -		if (bct) {
 -			EnterCriticalSection(&csTips);
 -			if (hwndToolTips) {
 -				TOOLINFO ti;
 -				ZeroMemory(&ti, sizeof(ti));
 -				ti.cbSize = sizeof(ti);
 -				ti.uFlags = TTF_IDISHWND;
 -				ti.hwnd = bct->hwnd;
 -				ti.uId = (UINT_PTR)bct->hwnd;
 -				if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
 -					SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
 -				}
 -				if (SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti) == 0) {
 -					DestroyWindow(hwndToolTips);
 -					hwndToolTips = NULL;
 -				}
 -			}
 -			LeaveCriticalSection(&csTips);
 -			mir_free(bct->ID);
 -			mir_free(bct->CommandService);
 -			mir_free(bct->StateService);
 -			mir_free(bct->HandleService);
 -			mir_free(bct->Hint);
 -			mir_free(bct->ValueDBSection);
 -			mir_free(bct->ValueTypeDef);
 -			mir_free(bct);
 -		}
 -		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
 -		break;	// DONT! fall thru
 -
 -	case WM_SETCURSOR:
 -		{
 -			HCURSOR hCurs1 = LoadCursor(NULL, IDC_ARROW);
 -			if (hCurs1) SetCursor(hCurs1);
 -			if (bct) SetToolTip(hwndDlg, bct->Hint);
 -		}
 -		return 1;
 -
 -	case WM_PRINT:
 -		if (IsWindowVisible(hwndDlg))
 -			ModernSkinButtonPaintWorker(hwndDlg,(HDC)wParam);
 -		break;
 -
 -	case WM_PAINT:
 -		if (IsWindowVisible(hwndDlg) && !g_CluiData.fLayered) {
 -			PAINTSTRUCT ps = {0};
 -			BeginPaint(hwndDlg,&ps);
 -			ModernSkinButtonPaintWorker(hwndDlg,(HDC)ps.hdc);
 -			EndPaint(hwndDlg,&ps);
 -		}
 -		return DefWindowProc(hwndDlg, msg, wParam, lParam);
 -
 -	case WM_CAPTURECHANGED:
 -		bct->hover = 0;
 -		bct->down = 0;
 -		ModernSkinButtonPaintWorker(bct->hwnd,0);
 -		break;
 -
 -	case WM_MOUSEMOVE:
 -		if (!bct->hover) {
 -			SetCapture(bct->hwnd);
 -			bct->hover = 1;
 -			ModernSkinButtonPaintWorker(bct->hwnd,0);
 -		}
 -		else {
 -			POINT t = UNPACK_POINT(lParam);
 -			ClientToScreen(bct->hwnd,&t);
 -			if (WindowFromPoint(t) != bct->hwnd)
 -				ReleaseCapture();
 -		}
 -		return 0;
 -
 -	case WM_LBUTTONDOWN:
 -		bct->down = 1;
 -		SetForegroundWindow(GetParent(bct->hwnd));
 -		ModernSkinButtonPaintWorker(bct->hwnd,0);
 -		if (bct && bct->CommandService && IsBadStringPtrA(bct->CommandService,255))
 -			bct->CommandService = NULL;
 -		if (bct->fCallOnPress) {
 -			if (bct->CommandService) {
 -				if (!_CallServiceStrParams(bct->CommandService, NULL) &&   (bct->ValueDBSection && bct->ValueTypeDef))
 -						ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef);
 -			}
 -			bct->down = 0;
 -
 -			ModernSkinButtonPaintWorker(bct->hwnd,0);
 -		}
 -		return 0;
 -
 -	case WM_LBUTTONUP:
 -		if (bct->down) {
 -			ReleaseCapture();
 -			bct->hover = 0;
 -			bct->down = 0;
 -			ModernSkinButtonPaintWorker(bct->hwnd,0);
 -			if (bct && bct->CommandService && IsBadStringPtrA(bct->CommandService,255))
 -				bct->CommandService = NULL;
 -			if (bct->CommandService)
 -				if (_CallServiceStrParams(bct->CommandService, NULL))
 -				{}
 -				else if (bct->ValueDBSection && bct->ValueTypeDef)
 -					ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef);
 -		}
 -	}
 -	return DefWindowProc(hwndDlg, msg, wParam, lParam);
 -}
 -
 -HWND SetToolTip(HWND hwnd, TCHAR * tip)
 -{
 -	TOOLINFO ti;
 -	if (!tip) return 0;
 -	EnterCriticalSection(&csTips);
 -	if (!hwndToolTips) {
 -		//  hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
 -
 -		hwndToolTips = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
 -			WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
 -			CW_USEDEFAULT, CW_USEDEFAULT,
 -			CW_USEDEFAULT, CW_USEDEFAULT,
 -			hwnd, NULL, GetModuleHandle(NULL),
 -			NULL);
 -
 -		SetWindowPos(hwndToolTips, HWND_TOPMOST, 0, 0, 0, 0,
 -			SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 -	}
 -
 -	ZeroMemory(&ti, sizeof(ti));
 -	ti.cbSize = sizeof(ti);
 -	ti.uFlags = TTF_IDISHWND;
 -	ti.hwnd = hwnd;
 -	ti.uId = (UINT_PTR)hwnd;
 -	if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
 -		SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
 -	}
 -	ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
 -	ti.uId = (UINT_PTR)hwnd;
 -	ti.lpszText = (TCHAR*)tip;
 -	SendMessage(hwndToolTips,TTM_ADDTOOL, 0, (LPARAM)&ti);
 -
 -	LeaveCriticalSection(&csTips);
 -	return hwndToolTips;
 -}
 -
 -
 -
 -typedef struct _MButton
 -{
 -	HWND hwnd;
 -	BYTE    ConstrainPositionFrom;  //(BBRRTTLL)  L = 0 - from left, L = 1 from right, L = 2 from center
 -	int OrL,OrR,OrT,OrB;
 -	int minW,minH;
 -	ModernSkinButtonCtrl * bct;
 -
 -} MButton;
 -MButton * Buttons = NULL;
 -DWORD ButtonsCount = 0;
 -
 -#define _center_h( rc ) (((rc)->right + (rc)->left ) >> 1)
 -#define _center_v( rc ) (((rc)->bottom + (rc)->top ) >> 1)
 -
 -int ModernSkinButton_AddButton(HWND parent,
 -							   char * ID,
 -							   char * CommandService,
 -							   char * StateDefService,
 -							   char * HandeService,
 -							   int Left,
 -							   int Top,
 -							   int Right,
 -							   int Bottom,
 -							   DWORD sbFlags,
 -							   TCHAR * Hint,
 -							   char * DBkey,
 -							   char * TypeDef,
 -							   int MinWidth, int MinHeight)
 -{
 -	//  if (!parent) return 0;
 -	if (!ModernSkinButtonModuleIsLoaded) return 0;
 -	if (!Buttons)
 -		Buttons = (MButton*)mir_alloc(sizeof(MButton));
 -	else
 -		Buttons = (MButton*)mir_realloc(Buttons,sizeof(MButton)*(ButtonsCount+1));
 -	{
 -		//HWND hwnd;
 -		RECT rc = {0};
 -		ModernSkinButtonCtrl* bct;
 -		int l,r,b,t;
 -		if (parent) GetClientRect(parent,&rc);
 -		l = ( sbFlags & SBF_ALIGN_TL_RIGHT )   ? ( rc.right + Left ) :
 -          ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Left ) :
 -          ( rc.left + Left );
 -
 -        t = ( sbFlags & SBF_ALIGN_TL_BOTTOM )  ? ( rc.bottom + Top ) :
 -          ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Top ) :
 -          ( rc.top+Top );
 -
 -        r = ( sbFlags & SBF_ALIGN_BR_RIGHT )   ? ( rc.right + Right ) :
 -          ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Right ) :
 -          ( rc.left + Right );
 -
 -        b = ( sbFlags & SBF_ALIGN_BR_BOTTOM )  ? ( rc.bottom + Bottom ) :
 -          ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Bottom ) :
 -          ( rc.top + Bottom );
 -		bct = (ModernSkinButtonCtrl *)mir_alloc(sizeof(ModernSkinButtonCtrl));
 -		memset(bct, 0, sizeof(ModernSkinButtonCtrl));
 -		bct->Left = l;
 -		bct->Right = r;
 -		bct->Top = t;
 -		bct->Bottom = b;
 -		bct->fCallOnPress = ( sbFlags & SBF_CALL_ON_PRESS ) != 0;
 -		bct->HandleService = mir_strdup(HandeService);
 -		bct->CommandService = mir_strdup(CommandService);
 -		bct->StateService = mir_strdup(StateDefService);
 -		if (DBkey && &DBkey != '\0') bct->ValueDBSection = mir_strdup(DBkey); else bct->ValueDBSection = NULL;
 -		if (TypeDef && &TypeDef != '\0') bct->ValueTypeDef = mir_strdup(TypeDef); else bct->ValueTypeDef = mir_strdup("sDefault");
 -		bct->ID=mir_strdup(ID);
 -		bct->Hint = mir_tstrdup(Hint);
 -		Buttons[ButtonsCount].bct = bct;
 -		Buttons[ButtonsCount].hwnd = NULL;
 -		Buttons[ButtonsCount].OrL = Left;
 -		Buttons[ButtonsCount].OrT = Top;
 -		Buttons[ButtonsCount].OrR = Right;
 -		Buttons[ButtonsCount].OrB = Bottom;
 -		Buttons[ButtonsCount].ConstrainPositionFrom = (BYTE)sbFlags;
 -		Buttons[ButtonsCount].minH = MinHeight;
 -		Buttons[ButtonsCount].minW = MinWidth;
 -		ButtonsCount++;
 -		//  CLUI_ShowWindowMod(hwnd,SW_SHOW);
 -	}
 -	return 0;
 -}
 -
 -
 -
 -static int ModernSkinButtonErase(int l,int t,int r, int b)
 -{
 -	DWORD i;
 -	if (!ModernSkinButtonModuleIsLoaded) return 0;
 -	if (!g_CluiData.fLayered) return 0;
 -	if (!g_pCachedWindow) return 0;
 -	if (!g_pCachedWindow->hImageDC  || !g_pCachedWindow->hBackDC) return 0;
 -	if (!(l || r || t || b))
 -	{
 -		for (i=0; i < ButtonsCount; i++)
 -		{
 -			if (pcli->hwndContactList && Buttons[i].hwnd != NULL)
 -			{
 -				//TODO: Erase button
 -				BitBlt(g_pCachedWindow->hImageDC,Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right-Buttons[i].bct->Left,Buttons[i].bct->Bottom-Buttons[i].bct->Top,
 -					g_pCachedWindow->hBackDC,Buttons[i].bct->Left,Buttons[i].bct->Top,SRCCOPY);
 -			}
 -		}
 -	}
 -	else
 -	{
 -		BitBlt(g_pCachedWindow->hImageDC,l,t,r-l,b-t, g_pCachedWindow->hBackDC,l,t,SRCCOPY);
 -	}
 -	return 0;
 -}
 -
 -static HWND ModernSkinButtonCreateWindow(ModernSkinButtonCtrl * bct, HWND parent)
 -{
 -	HWND hwnd;
 -
 -	if (bct == NULL) return FALSE;
 -	{
 -		TCHAR *UnicodeID;
 -		UnicodeID = mir_a2u(bct->ID);
 -		hwnd = CreateWindow(_T(MODERNSKINBUTTONCLASS),UnicodeID,WS_VISIBLE|WS_CHILD,bct->Left,bct->Top,bct->Right-bct->Left,bct->Bottom-bct->Top,parent,NULL,g_hInst,NULL);
 -		mir_free(UnicodeID);
 -	}
 -
 -	bct->hwnd = hwnd;
 -	bct->focus = 0;
 -	SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)bct);
 -	return hwnd;
 -}
 -
 -int ModernSkinButtonRedrawAll(HDC hdc)
 -{
 -	DWORD i;
 -	if (!ModernSkinButtonModuleIsLoaded) return 0;
 -	g_mutex_bLockUpdating++;
 -	for (i=0; i < ButtonsCount; i++)
 -	{
 -		if (pcli->hwndContactList && Buttons[i].hwnd == NULL)
 -			Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,pcli->hwndContactList);
 -		ModernSkinButtonPaintWorker(Buttons[i].hwnd,0);
 -	}
 -	g_mutex_bLockUpdating--;
 -	return 0;
 -}
 -
 -int ModernSkinButtonDeleteAll()
 -{
 -	if (!ModernSkinButtonModuleIsLoaded)
 -		return 0;
 -
 -	for (size_t i=0; i < ButtonsCount; i++)
 -		if (Buttons[i].hwnd)
 -			DestroyWindow(Buttons[i].hwnd);
 -
 -	mir_free_and_nil(Buttons);
 -	ButtonsCount = 0;
 -	return 0;
 -}
 -
 -int ModernSkinButton_ReposButtons(HWND parent, BYTE draw, RECT *r)
 -{
 -	DWORD i;
 -	RECT rc;
 -	RECT clr;
 -	RECT rd;
 -	BOOL altDraw = FALSE;
 -	static SIZE oldWndSize = {0};
 -	if (!ModernSkinButtonModuleIsLoaded) return 0;
 -	GetWindowRect(parent,&rd);
 -	GetClientRect(parent,&clr);
 -	if (!r)
 -		GetWindowRect(parent,&rc);
 -	else
 -		rc = *r;
 -	if (g_CluiData.fLayered && ( draw & SBRF_DO_ALT_DRAW ))
 -	{
 -		int sx,sy;
 -		sx = rd.right-rd.left;
 -		sy = rd.bottom-rd.top;
 -		if (sx != oldWndSize.cx || sy != oldWndSize.cy)
 -			altDraw = TRUE;//EraseButtons();
 -		oldWndSize.cx = sx;
 -		oldWndSize.cy = sy;
 -	}
 -
 -	OffsetRect(&rc,-rc.left,-rc.top);
 -	rc.right = rc.left+(clr.right-clr.left);
 -	rc.bottom = rc.top+(clr.bottom-clr.top);
 -	for (i=0; i < ButtonsCount; i++)
 -	{
 -		int l,r,b,t;
 -		RECT oldRect = {0};
 -		int sbFlags = Buttons[i].ConstrainPositionFrom;
 -		if (parent && Buttons[i].hwnd == NULL)
 -		{
 -			Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,parent);
 -			altDraw = FALSE;
 -		}
 -
 -        l = ( sbFlags & SBF_ALIGN_TL_RIGHT )   ? ( rc.right + Buttons[i].OrL ) :
 -            ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Buttons[i].OrL ) :
 -            ( rc.left + Buttons[i].OrL );
 -
 -        t = ( sbFlags & SBF_ALIGN_TL_BOTTOM )  ? ( rc.bottom + Buttons[i].OrT ) :
 -            ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrT ) :
 -            ( rc.top + Buttons[i].OrT );
 -
 -        r = ( sbFlags & SBF_ALIGN_BR_RIGHT )   ? ( rc.right + Buttons[i].OrR ) :
 -            ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Buttons[i].OrR ) :
 -            ( rc.left + Buttons[i].OrR );
 -
 -        b = ( sbFlags & SBF_ALIGN_BR_BOTTOM )  ? ( rc.bottom + Buttons[i].OrB ) :
 -            ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrB ) :
 -            ( rc.top + Buttons[i].OrB );
 -
 -        SetWindowPos(Buttons[i].hwnd,HWND_TOP,l,t,r-l,b-t,0);
 -		if (  (rc.right-rc.left < Buttons[i].minW /* &&  Buttons[i].minW != 0*/)
 -			 || (rc.bottom-rc.top < Buttons[i].minH /* &&  Buttons[i].minH != 0*/))
 -			CLUI_ShowWindowMod(Buttons[i].hwnd,SW_HIDE);
 -		else
 -			CLUI_ShowWindowMod(Buttons[i].hwnd,SW_SHOW);
 -		if ((1 || altDraw) &&
 -			(Buttons[i].bct->Left != l  ||
 -			Buttons[i].bct->Top != t   ||
 -			Buttons[i].bct->Right != r ||
 -			Buttons[i].bct->Bottom != b))
 -		{
 -			//Need to erase in old location
 -			ModernSkinButtonErase(Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right,Buttons[i].bct->Bottom);
 -		}
 -
 -		Buttons[i].bct->Left = l;
 -		Buttons[i].bct->Top = t;
 -		Buttons[i].bct->Right = r;
 -		Buttons[i].bct->Bottom = b;
 -
 -
 -	}
 -	if ( draw & SBRF_DO_REDRAW_ALL ) ModernSkinButtonRedrawAll(0);
 -	return 0;
 +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 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. +*/ + +/* +This file contains code related to new modern free positioned skinned buttons +*/ + +#include "hdr/modern_commonheaders.h" +#include "hdr/modern_skinengine.h" +#include "hdr/modern_clcpaint.h" +#include "m_api/m_skinbutton.h" + +#define MODERNSKINBUTTONCLASS "MirandaModernSkinButtonClass" +BOOL ModernSkinButtonModuleIsLoaded = FALSE; +static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg,  WPARAM wParam, LPARAM lParam); +int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam); +int SkinSelector_DeleteMask(MODERNMASK *mm); +HWND SetToolTip(HWND hwnd, TCHAR * tip); + +typedef struct _ModernSkinButtonCtrl +{ +	HWND    hwnd; +	BYTE    down; // button state +	BYTE    focus;   // has focus (1 or 0) +	BYTE    hover; +	BYTE    IsSwitcher; +	BOOL    fCallOnPress; +	char    * ID; +	char    * CommandService; +	char    * StateService; +	char    * HandleService; +	char    * ValueDBSection; +	char    * ValueTypeDef; +	int     Left, Top, Bottom, Right; +	HMENU   hMenu; +	TCHAR   * Hint; + +} ModernSkinButtonCtrl; +typedef struct _HandleServiceParams +{ +	HWND    hwnd; +	DWORD   msg; +	WPARAM  wParam; +	LPARAM  lParam; +	BOOL    handled; +} HandleServiceParams; + +static CRITICAL_SECTION csTips; +static HWND hwndToolTips = NULL; + +int ModernSkinButtonLoadModule() +{ +	WNDCLASSEX wc; +	ZeroMemory(&wc, sizeof(wc)); +	wc.cbSize         = sizeof(wc); +	wc.lpszClassName  = _T(MODERNSKINBUTTONCLASS); +	wc.lpfnWndProc    = ModernSkinButtonWndProc; +	wc.hCursor        = LoadCursor(NULL, IDC_ARROW); +	wc.cbWndExtra     = sizeof(ModernSkinButtonCtrl*); +	wc.hbrBackground  = 0; +	wc.style          = CS_GLOBALCLASS; +	RegisterClassEx(&wc); +	InitializeCriticalSection(&csTips); +	ModernSkinButtonModuleIsLoaded = TRUE; +	return 0; +} + +int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam) +{ +	DeleteCriticalSection(&csTips); +	return 0; +} + +static int ModernSkinButtonPaintWorker(HWND hwnd, HDC whdc) +{ +	HDC hdc; +	HBITMAP bmp,oldbmp; +	RECT rc; +	HDC sdc = NULL; +	ModernSkinButtonCtrl* bct = (ModernSkinButtonCtrl *)GetWindowLongPtr(hwnd, GWLP_USERDATA); +	if (!bct) return 0; +	if (!IsWindowVisible(hwnd)) return 0; +	if (!whdc && !g_CluiData.fLayered) InvalidateRect(hwnd,NULL,FALSE); + +	if (whdc && g_CluiData.fLayered) hdc = whdc; +	else +	{ +		//sdc = GetWindowDC(GetParent(hwnd)); +		hdc = CreateCompatibleDC(NULL); +	} +	GetClientRect(hwnd,&rc); +	bmp = ske_CreateDIB32(rc.right,rc.bottom); +	oldbmp = (HBITMAP)SelectObject(hdc,bmp); +	if (!g_CluiData.fLayered) +		ske_BltBackImage(bct->hwnd,hdc,NULL); +	{ +		MODERNMASK Request = {0}; +		//   int res; +		//HBRUSH br = CreateSolidBrush(RGB(255,255,255)); +		char * Value = NULL; +		DWORD val = 0; +		{ +			if (bct->ValueDBSection && bct->ValueTypeDef) +			{ +				char * key; +				char * section; +				DWORD defval = 0; +				char buf[20]; +				key = mir_strdup(bct->ValueDBSection); +				section = key; +				if (bct->ValueTypeDef[0] != 's') +					defval = (DWORD)atol(bct->ValueTypeDef+1); +				do +				{ +					if (key[0] == '/') {key[0] = '\0'; key++; break;} +					key++; +				} while (key[0] != '\0'); +				switch (bct->ValueTypeDef[0]) +				{ +				case 's': +					{ +						Value = db_get_sa(NULL,section,key); +						if (!Value) +							Value = mir_strdup(bct->ValueTypeDef+1); +						break; +					} +				case 'd': +					defval = db_get_dw(NULL,section,key,defval); +					Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf))); +					break; +				case 'w': +					defval = db_get_w(NULL,section,key,defval); +					Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf))); +					break; +				case 'b': +					defval = db_get_b(NULL,section,key,defval); +					Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf))); +					break; +				} +				mir_free(section); +			} + +		} +		g_clcPainter.AddParam(&Request,mod_CalcHash("Module"),"MButton",0); +		g_clcPainter.AddParam(&Request,mod_CalcHash("ID"),bct->ID,0); +		g_clcPainter.AddParam(&Request,mod_CalcHash("Down"),bct->down?"1":"0",0); +		g_clcPainter.AddParam(&Request,mod_CalcHash("Focused"),bct->focus?"1":"0",0); +		g_clcPainter.AddParam(&Request,mod_CalcHash("Hovered"),bct->hover?"1":"0",0); +		if (Value) { +			g_clcPainter.AddParam(&Request,mod_CalcHash("Value"),Value,0); +			mir_free(Value); +		} +		SkinDrawGlyphMask(hdc,&rc,&rc,&Request); +		SkinSelector_DeleteMask(&Request); +		// DeleteObject(br); +	} + +	if (!whdc && g_CluiData.fLayered) +	{ +		RECT r; +		SetRect(&r,bct->Left,bct->Top,bct->Right,bct->Bottom); +		ske_DrawImageAt(hdc,&r); +		//CallingService to immeadeately update window with new image. +	} +	if (whdc && !g_CluiData.fLayered) +	{ +		RECT r = {0}; +		GetClientRect(bct->hwnd,&r); +		BitBlt(whdc, 0, 0, r.right,r.bottom,hdc, 0, 0, SRCCOPY); +	} +	SelectObject(hdc,oldbmp); +	DeleteObject(bmp); +	if (!whdc || !g_CluiData.fLayered) +	{ +		SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); +		DeleteDC(hdc); +	} +	//  if (sdc) +	//    ReleaseDC(GetParent(hwnd),sdc); +	return 0; +} + +static int ModernSkinButtonToggleDBValue(char * ValueDBSection,char *ValueTypeDef) +{ +	if (ValueDBSection && ValueTypeDef) +	{ +		char * key; +		char * section; +		char * val; +		char * val2; +		char * Value; +		long l1,l2,curval; +		DWORD defval = 0; +		//        char buf[20]; +		key = mir_strdup(ValueDBSection); +		section = key; +		do +		{ +			if (key[0] == '/') {key[0] = '\0'; key++; break;} +			key++; +		} while (key[0] != '\0'); + +		val = mir_strdup(ValueTypeDef+1); +		val2 = val; +		do +		{ +			if (val2[0] == '/') {val2[0] = '\0'; val2++; break;} +			val2++; +		} while (val2[0] != '\0'); + +		if (ValueTypeDef[0] != 's') +		{ +			l1 = (DWORD)atol(val); +			l2 = (DWORD)atol(val2); +		} + +		switch (ValueTypeDef[0]) { +		case 's': +			Value = db_get_sa(NULL,section,key); +			if (!Value  || (Value && mir_bool_strcmpi(Value,val2))) +				Value = mir_strdup(val); +			else +				Value = mir_strdup(val2); +			db_set_s(NULL,section,key,Value); +			mir_free(Value); +			break; + +		case 'd': +			curval = db_get_dw(NULL,section,key,l2); +			curval = (curval == l2)?l1:l2; +			db_set_dw(NULL,section,key,(DWORD)curval); +			break; + +		case 'w': +			curval = db_get_w(NULL,section,key,l2); +			curval = (curval == l2)?l1:l2; +			db_set_w(NULL,section,key,(WORD)curval); +			break; + +		case 'b': +			curval = db_get_b(NULL,section,key,l2); +			curval = (curval == l2)?l1:l2; +			db_set_b(NULL,section,key,(BYTE)curval); +			break; +		} +		mir_free(section); +		mir_free(val); +	} +	return 0; +} + +static char *_skipblank(char * str) //str will be modified; +{ +	char * endstr = str+strlen(str); +	while ((*str == ' ' || *str == '\t') && *str != '\0') str++; +	while ((*endstr == ' ' || *endstr == '\t') && *endstr != '\0' && endstr < str) endstr--; +	if (*endstr != '\0') +	{ +		endstr++; +		*endstr = '\0'; +	} +	return str; +} + +static int _CallServiceStrParams(IN char * toParce, OUT int *Return) +{ +	char * pszService; +	char * param1 = NULL; +	char * param2 = NULL; +	int paramCount = 0; +	int result = 0; + +	pszService = mir_strdup(toParce); +	if (!pszService) +		return 0; +	if (strlen(pszService) == 0) { +		mir_free(pszService); +		return 0; +	} +	param2 = strrchr(pszService, '%'); +	if (param2) +	{ +		paramCount++; +		*param2 = '\0';	param2++; +		_skipblank(param2); +		if (strlen(param2) == 0) +			param2 = NULL; +	} +	param1 = strrchr(pszService, '%'); +	if (param1) +	{ +		paramCount++; +		*param1 = '\0';	param1++; +		_skipblank(param1); +		if (strlen(param1) == 0) +			param1 = NULL; +	} +	if (param1 && *param1 == '\"') +	{ +		param1++; +		*(param1+strlen(param1)) = '\0'; +	} +	else if (param1) +	{ +		param1 = (char*)atoi(param1); +	} +	if (param2 && *param2 == '\"') +	{ +		param2++; +		*(param2+strlen(param2)) = '\0'; +	} +	else if (param2) +		param2 = (char*)atoi(param2); + +	if (paramCount == 1) +	{ +		param1 = param2; +		param2 = NULL; +	} +	if (!ServiceExists(pszService)) +	{ +		result = 0; +	} +	else +	{ +		int ret = 0; +		result = 1; +		ret = CallService(pszService, (WPARAM)param1, (WPARAM)param2); +		if (Return) *Return = ret; +	} +	mir_free(pszService); +	return result; +} + + +static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg,  WPARAM wParam, LPARAM lParam) +{ +	ModernSkinButtonCtrl* bct = (msg != WM_NCCREATE)?(ModernSkinButtonCtrl *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA):0; +	if (bct && bct->HandleService && IsBadStringPtrA(bct->HandleService,255)) +		bct->HandleService = NULL; + +	if (bct) +		if (bct->HandleService && ServiceExists(bct->HandleService)) { +			HandleServiceParams MSG = {0}; +			MSG.hwnd = hwndDlg; +			MSG.msg = msg; +			MSG.wParam = wParam; +			MSG.lParam = lParam; +			int t = CallService(bct->HandleService,(WPARAM)&MSG,0); +			if (MSG.handled) return t; +		} + +	switch(msg) { +	case WM_NCCREATE: +		SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE)|BS_OWNERDRAW); +		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); +		if (((CREATESTRUCT *)lParam)->lpszName) SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName); +		return TRUE; + +	case WM_DESTROY: +		if (bct == NULL) +			break; +		EnterCriticalSection(&csTips); +		if (hwndToolTips) { +			TOOLINFO ti; +			ZeroMemory(&ti, sizeof(ti)); +			ti.cbSize = sizeof(ti); +			ti.uFlags = TTF_IDISHWND; +			ti.hwnd = bct->hwnd; +			ti.uId = (UINT_PTR)bct->hwnd; +			if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) { +				SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti); +			} +			if (SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti) == 0) { +				DestroyWindow(hwndToolTips); +				hwndToolTips = NULL; +			} +		} +		LeaveCriticalSection(&csTips); +		mir_free(bct->ID); +		mir_free(bct->CommandService); +		mir_free(bct->StateService); +		mir_free(bct->HandleService); +		mir_free(bct->Hint); +		mir_free(bct->ValueDBSection); +		mir_free(bct->ValueTypeDef); +		mir_free(bct); +		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); +		break;	// DONT! fall thru + +	case WM_SETCURSOR: +		{ +			HCURSOR hCurs1 = LoadCursor(NULL, IDC_ARROW); +			if (hCurs1) SetCursor(hCurs1); +			if (bct) SetToolTip(hwndDlg, bct->Hint); +		} +		return 1; + +	case WM_PRINT: +		if (IsWindowVisible(hwndDlg)) +			ModernSkinButtonPaintWorker(hwndDlg,(HDC)wParam); +		break; + +	case WM_PAINT: +		if (IsWindowVisible(hwndDlg) && !g_CluiData.fLayered) { +			PAINTSTRUCT ps = {0}; +			BeginPaint(hwndDlg,&ps); +			ModernSkinButtonPaintWorker(hwndDlg,(HDC)ps.hdc); +			EndPaint(hwndDlg,&ps); +		} +		return DefWindowProc(hwndDlg, msg, wParam, lParam); + +	case WM_CAPTURECHANGED: +		bct->hover = 0; +		bct->down = 0; +		ModernSkinButtonPaintWorker(bct->hwnd,0); +		break; + +	case WM_MOUSEMOVE: +		if (!bct->hover) { +			SetCapture(bct->hwnd); +			bct->hover = 1; +			ModernSkinButtonPaintWorker(bct->hwnd,0); +		} +		else { +			POINT t = UNPACK_POINT(lParam); +			ClientToScreen(bct->hwnd,&t); +			if (WindowFromPoint(t) != bct->hwnd) +				ReleaseCapture(); +		} +		return 0; + +	case WM_LBUTTONDOWN: +		bct->down = 1; +		SetForegroundWindow(GetParent(bct->hwnd)); +		ModernSkinButtonPaintWorker(bct->hwnd,0); +		if (bct->CommandService && IsBadStringPtrA(bct->CommandService,255)) +			bct->CommandService = NULL; +		if (bct->fCallOnPress) { +			if (bct->CommandService) { +				if (!_CallServiceStrParams(bct->CommandService, NULL) &&   (bct->ValueDBSection && bct->ValueTypeDef)) +						ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef); +			} +			bct->down = 0; + +			ModernSkinButtonPaintWorker(bct->hwnd,0); +		} +		return 0; + +	case WM_LBUTTONUP: +		if (bct->down) { +			ReleaseCapture(); +			bct->hover = 0; +			bct->down = 0; +			ModernSkinButtonPaintWorker(bct->hwnd,0); +			if (bct->CommandService && IsBadStringPtrA(bct->CommandService,255)) +				bct->CommandService = NULL; +			if (bct->CommandService) +				if (_CallServiceStrParams(bct->CommandService, NULL)) +				{} +				else if (bct->ValueDBSection && bct->ValueTypeDef) +					ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef); +		} +	} +	return DefWindowProc(hwndDlg, msg, wParam, lParam); +} + +HWND SetToolTip(HWND hwnd, TCHAR * tip) +{ +	TOOLINFO ti; +	if (!tip) return 0; +	EnterCriticalSection(&csTips); +	if (!hwndToolTips) { +		//  hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL); + +		hwndToolTips = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, +			WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, +			CW_USEDEFAULT, CW_USEDEFAULT, +			CW_USEDEFAULT, CW_USEDEFAULT, +			hwnd, NULL, GetModuleHandle(NULL), +			NULL); + +		SetWindowPos(hwndToolTips, HWND_TOPMOST, 0, 0, 0, 0, +			SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); +	} + +	ZeroMemory(&ti, sizeof(ti)); +	ti.cbSize = sizeof(ti); +	ti.uFlags = TTF_IDISHWND; +	ti.hwnd = hwnd; +	ti.uId = (UINT_PTR)hwnd; +	if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) { +		SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti); +	} +	ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS; +	ti.uId = (UINT_PTR)hwnd; +	ti.lpszText = (TCHAR*)tip; +	SendMessage(hwndToolTips,TTM_ADDTOOL, 0, (LPARAM)&ti); + +	LeaveCriticalSection(&csTips); +	return hwndToolTips; +} + + + +typedef struct _MButton +{ +	HWND hwnd; +	BYTE    ConstrainPositionFrom;  //(BBRRTTLL)  L = 0 - from left, L = 1 from right, L = 2 from center +	int OrL,OrR,OrT,OrB; +	int minW,minH; +	ModernSkinButtonCtrl * bct; + +} MButton; +MButton * Buttons = NULL; +DWORD ButtonsCount = 0; + +#define _center_h( rc ) (((rc)->right + (rc)->left ) >> 1) +#define _center_v( rc ) (((rc)->bottom + (rc)->top ) >> 1) + +int ModernSkinButton_AddButton(HWND parent, +							   char * ID, +							   char * CommandService, +							   char * StateDefService, +							   char * HandeService, +							   int Left, +							   int Top, +							   int Right, +							   int Bottom, +							   DWORD sbFlags, +							   TCHAR * Hint, +							   char * DBkey, +							   char * TypeDef, +							   int MinWidth, int MinHeight) +{ +	//  if (!parent) return 0; +	if (!ModernSkinButtonModuleIsLoaded) return 0; +	if (!Buttons) +		Buttons = (MButton*)mir_alloc(sizeof(MButton)); +	else +		Buttons = (MButton*)mir_realloc(Buttons,sizeof(MButton)*(ButtonsCount+1)); +	{ +		//HWND hwnd; +		RECT rc = {0}; +		ModernSkinButtonCtrl* bct; +		int l,r,b,t; +		if (parent) GetClientRect(parent,&rc); +		l = ( sbFlags & SBF_ALIGN_TL_RIGHT )   ? ( rc.right + Left ) : +          ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Left ) : +          ( rc.left + Left ); + +        t = ( sbFlags & SBF_ALIGN_TL_BOTTOM )  ? ( rc.bottom + Top ) : +          ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Top ) : +          ( rc.top+Top ); + +        r = ( sbFlags & SBF_ALIGN_BR_RIGHT )   ? ( rc.right + Right ) : +          ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Right ) : +          ( rc.left + Right ); + +        b = ( sbFlags & SBF_ALIGN_BR_BOTTOM )  ? ( rc.bottom + Bottom ) : +          ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Bottom ) : +          ( rc.top + Bottom ); +		bct = (ModernSkinButtonCtrl *)mir_alloc(sizeof(ModernSkinButtonCtrl)); +		memset(bct, 0, sizeof(ModernSkinButtonCtrl)); +		bct->Left = l; +		bct->Right = r; +		bct->Top = t; +		bct->Bottom = b; +		bct->fCallOnPress = ( sbFlags & SBF_CALL_ON_PRESS ) != 0; +		bct->HandleService = mir_strdup(HandeService); +		bct->CommandService = mir_strdup(CommandService); +		bct->StateService = mir_strdup(StateDefService); +		if (DBkey && &DBkey != '\0') bct->ValueDBSection = mir_strdup(DBkey); else bct->ValueDBSection = NULL; +		if (TypeDef && &TypeDef != '\0') bct->ValueTypeDef = mir_strdup(TypeDef); else bct->ValueTypeDef = mir_strdup("sDefault"); +		bct->ID=mir_strdup(ID); +		bct->Hint = mir_tstrdup(Hint); +		Buttons[ButtonsCount].bct = bct; +		Buttons[ButtonsCount].hwnd = NULL; +		Buttons[ButtonsCount].OrL = Left; +		Buttons[ButtonsCount].OrT = Top; +		Buttons[ButtonsCount].OrR = Right; +		Buttons[ButtonsCount].OrB = Bottom; +		Buttons[ButtonsCount].ConstrainPositionFrom = (BYTE)sbFlags; +		Buttons[ButtonsCount].minH = MinHeight; +		Buttons[ButtonsCount].minW = MinWidth; +		ButtonsCount++; +		//  CLUI_ShowWindowMod(hwnd,SW_SHOW); +	} +	return 0; +} + + + +static int ModernSkinButtonErase(int l,int t,int r, int b) +{ +	DWORD i; +	if (!ModernSkinButtonModuleIsLoaded) return 0; +	if (!g_CluiData.fLayered) return 0; +	if (!g_pCachedWindow) return 0; +	if (!g_pCachedWindow->hImageDC  || !g_pCachedWindow->hBackDC) return 0; +	if (!(l || r || t || b)) +	{ +		for (i=0; i < ButtonsCount; i++) +		{ +			if (pcli->hwndContactList && Buttons[i].hwnd != NULL) +			{ +				//TODO: Erase button +				BitBlt(g_pCachedWindow->hImageDC,Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right-Buttons[i].bct->Left,Buttons[i].bct->Bottom-Buttons[i].bct->Top, +					g_pCachedWindow->hBackDC,Buttons[i].bct->Left,Buttons[i].bct->Top,SRCCOPY); +			} +		} +	} +	else +	{ +		BitBlt(g_pCachedWindow->hImageDC,l,t,r-l,b-t, g_pCachedWindow->hBackDC,l,t,SRCCOPY); +	} +	return 0; +} + +static HWND ModernSkinButtonCreateWindow(ModernSkinButtonCtrl * bct, HWND parent) +{ +	HWND hwnd; + +	if (bct == NULL) return FALSE; +	{ +		TCHAR *UnicodeID; +		UnicodeID = mir_a2u(bct->ID); +		hwnd = CreateWindow(_T(MODERNSKINBUTTONCLASS),UnicodeID,WS_VISIBLE|WS_CHILD,bct->Left,bct->Top,bct->Right-bct->Left,bct->Bottom-bct->Top,parent,NULL,g_hInst,NULL); +		mir_free(UnicodeID); +	} + +	bct->hwnd = hwnd; +	bct->focus = 0; +	SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)bct); +	return hwnd; +} + +int ModernSkinButtonRedrawAll(HDC hdc) +{ +	DWORD i; +	if (!ModernSkinButtonModuleIsLoaded) return 0; +	g_mutex_bLockUpdating++; +	for (i=0; i < ButtonsCount; i++) +	{ +		if (pcli->hwndContactList && Buttons[i].hwnd == NULL) +			Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,pcli->hwndContactList); +		ModernSkinButtonPaintWorker(Buttons[i].hwnd,0); +	} +	g_mutex_bLockUpdating--; +	return 0; +} + +int ModernSkinButtonDeleteAll() +{ +	if (!ModernSkinButtonModuleIsLoaded) +		return 0; + +	for (size_t i=0; i < ButtonsCount; i++) +		if (Buttons[i].hwnd) +			DestroyWindow(Buttons[i].hwnd); + +	mir_free_and_nil(Buttons); +	ButtonsCount = 0; +	return 0; +} + +int ModernSkinButton_ReposButtons(HWND parent, BYTE draw, RECT *r) +{ +	DWORD i; +	RECT rc; +	RECT clr; +	RECT rd; +	BOOL altDraw = FALSE; +	static SIZE oldWndSize = {0}; +	if (!ModernSkinButtonModuleIsLoaded) return 0; +	GetWindowRect(parent,&rd); +	GetClientRect(parent,&clr); +	if (!r) +		GetWindowRect(parent,&rc); +	else +		rc = *r; +	if (g_CluiData.fLayered && ( draw & SBRF_DO_ALT_DRAW )) +	{ +		int sx,sy; +		sx = rd.right-rd.left; +		sy = rd.bottom-rd.top; +		if (sx != oldWndSize.cx || sy != oldWndSize.cy) +			altDraw = TRUE;//EraseButtons(); +		oldWndSize.cx = sx; +		oldWndSize.cy = sy; +	} + +	OffsetRect(&rc,-rc.left,-rc.top); +	rc.right = rc.left+(clr.right-clr.left); +	rc.bottom = rc.top+(clr.bottom-clr.top); +	for (i=0; i < ButtonsCount; i++) +	{ +		int l,r,b,t; +		RECT oldRect = {0}; +		int sbFlags = Buttons[i].ConstrainPositionFrom; +		if (parent && Buttons[i].hwnd == NULL) +		{ +			Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,parent); +			altDraw = FALSE; +		} + +        l = ( sbFlags & SBF_ALIGN_TL_RIGHT )   ? ( rc.right + Buttons[i].OrL ) : +            ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Buttons[i].OrL ) : +            ( rc.left + Buttons[i].OrL ); + +        t = ( sbFlags & SBF_ALIGN_TL_BOTTOM )  ? ( rc.bottom + Buttons[i].OrT ) : +            ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrT ) : +            ( rc.top + Buttons[i].OrT ); + +        r = ( sbFlags & SBF_ALIGN_BR_RIGHT )   ? ( rc.right + Buttons[i].OrR ) : +            ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Buttons[i].OrR ) : +            ( rc.left + Buttons[i].OrR ); + +        b = ( sbFlags & SBF_ALIGN_BR_BOTTOM )  ? ( rc.bottom + Buttons[i].OrB ) : +            ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrB ) : +            ( rc.top + Buttons[i].OrB ); + +        SetWindowPos(Buttons[i].hwnd,HWND_TOP,l,t,r-l,b-t,0); +		if (  (rc.right-rc.left < Buttons[i].minW /* &&  Buttons[i].minW != 0*/) +			 || (rc.bottom-rc.top < Buttons[i].minH /* &&  Buttons[i].minH != 0*/)) +			CLUI_ShowWindowMod(Buttons[i].hwnd,SW_HIDE); +		else +			CLUI_ShowWindowMod(Buttons[i].hwnd,SW_SHOW); +		if ((1 || altDraw) && +			(Buttons[i].bct->Left != l  || +			Buttons[i].bct->Top != t   || +			Buttons[i].bct->Right != r || +			Buttons[i].bct->Bottom != b)) +		{ +			//Need to erase in old location +			ModernSkinButtonErase(Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right,Buttons[i].bct->Bottom); +		} + +		Buttons[i].bct->Left = l; +		Buttons[i].bct->Top = t; +		Buttons[i].bct->Right = r; +		Buttons[i].bct->Bottom = b; + + +	} +	if ( draw & SBRF_DO_REDRAW_ALL ) ModernSkinButtonRedrawAll(0); +	return 0;  }
\ No newline at end of file diff --git a/plugins/Clist_modern/src/modern_skinengine.cpp b/plugins/Clist_modern/src/modern_skinengine.cpp index 48965be1f0..ba02bcb6df 100644 --- a/plugins/Clist_modern/src/modern_skinengine.cpp +++ b/plugins/Clist_modern/src/modern_skinengine.cpp @@ -1,4145 +1,4140 @@ -/*
 -
 -Miranda NG: the free IM client for Microsoft* Windows*
 -
 -Copyright (c) 2012-14 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
 -#include "hdr/modern_commonheaders.h"
 -#include <m_png.h>
 -#include "m_api/m_skin_eng.h"
 -#include "hdr/modern_skinselector.h"
 -#include "CLUIFrames/cluiframes.h"
 -
 -#define _EFFECTENUM_FULL_H
 -#include "hdr/modern_effectenum.h"
 -#undef _EFFECTENUM_FULL_H
 -
 -#include "hdr/modern_skinengine.h"
 -#include "hdr/modern_commonprototypes.h"
 -#include "hdr/modern_sync.h"
 -//Implementation
 -
 -/* Global variables */
 -
 -SKINOBJECTSLIST g_SkinObjectList = {0};
 -CURRWNDIMAGEDATA *g_pCachedWindow = NULL;
 -
 -BOOL g_flag_bPostWasCanceled  = FALSE;
 -BOOL g_flag_bFullRepaint      = FALSE;
 -BOOL g_mutex_bLockUpdating    = FALSE;
 -
 -SortedList *gl_plGlyphTexts = NULL;
 -SortedList *gl_plSkinFonts  = NULL;
 -
 -/* Private module variables */
 -
 -static HANDLE  hSkinLoadedEvent;
 -
 -static GLYPHIMAGE *pLoadedImages = NULL;
 -static DWORD dwLoadedImagesCount = 0;
 -static DWORD dwLoadedImagesAlocated = 0;
 -
 -static BOOL flag_bUpdateQueued = FALSE;
 -static BOOL	flag_bJustDrawNonFramedObjects = FALSE;
 -static BOOL mutex_bLockUpdate = FALSE;
 -
 -static LIST<EFFECTSSTACKITEM> arEffectStack(10, HandleKeySortT);
 -static SKINOBJECTSLIST *pCurrentSkin = NULL;
 -static char  **pszSettingName = NULL;
 -static int   nArrayLen = 0;
 -
 -static BYTE  pbGammaWeight[256] = {0};
 -static BYTE  pbGammaWeightAdv[256] = {0};
 -static BOOL  bGammaWeightFilled = FALSE;
 -
 -static CRITICAL_SECTION cs_SkinChanging = {0};
 -
 -static LISTMODERNMASK *MainModernMaskList = NULL;
 -
 -/* Private module procedures */
 -static BOOL ske_GetMaskBit(BYTE *line, int x);
 -static INT_PTR  ske_Service_AlphaTextOut(WPARAM wParam, LPARAM lParam);
 -static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, LPARAM lParam);
 -
 -static int  ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor);
 -static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin);
 -static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin);
 -static int  ske_DeleteAllSettingInSection(char * SectionName);
 -static int  ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin);
 -static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType,SKINOBJECTSLIST* Skin);
 -static int  ske_LoadSkinFromResource(BOOL bOnlyObjects);
 -static void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult);
 -static int  ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting);
 -static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam);
 -static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam);
 -static INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam);
 -
 -static MODERNEFFECT meCurrentEffect = {-1,{0}, 0, 0};
 -
 -
 -//////////////////////////////////////////////////////////////////////////
 -// Ini file parser
 -//////////////////////////////////////////////////////////////////////////
 -IniParser::IniParser(TCHAR * tcsFileName, BYTE flags) : _Flags(flags)
 -{
 -	_DoInit();
 -	if (!tcsFileName) return;
 -
 -	if (tcsFileName[0] == _T('%'))
 -	{
 -		//TODO: Add parser of resource filename here
 -		_LoadResourceIni(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF");
 -		return;
 -	}
 -
 -	_hFile = _tfopen(tcsFileName, _T("r"));
 -
 -	if (_hFile != NULL)
 -	{
 -		_eType = IT_FILE;
 -		_isValid = true;
 -	}
 -}
 -
 -IniParser::IniParser(HINSTANCE hInst, const char *  resourceName, const char * resourceType, BYTE flags) : _Flags(flags)
 -{
 -	_DoInit();
 -	_LoadResourceIni(hInst, resourceName, resourceType);
 -}
 -
 -IniParser::~IniParser()
 -{
 -	mir_free(_szSection);
 -	if (_hFile) fclose(_hFile);
 -	if (_hGlobalRes) {
 -		UnlockResource(_hGlobalRes);
 -		FreeResource(_hGlobalRes);
 -	}
 -
 -	_szSection = NULL;
 -	_hGlobalRes = NULL;
 -	_hFile = NULL;
 -	_isValid = false;
 -	_eType = IT_UNKNOWN;
 -}
 -
 -HRESULT IniParser::Parse(ParserCallback_t pLineCallBackProc, LPARAM SecCheck)
 -{
 -	if (_isValid && pLineCallBackProc)
 -	{
 -		_pLineCallBackProc = pLineCallBackProc;
 -		_SecCheck = SecCheck;
 -		switch (_eType) {
 -		case IT_FILE:
 -			return _DoParseFile();
 -		case IT_RESOURCE:
 -			return _DoParseResource();
 -		}
 -	}
 -	return E_FAIL;
 -}
 -
 -HRESULT IniParser::WriteStrToDb( const char * szSection, const char * szName, const char * szValue, IniParser * This )
 -{
 -	if ( This->_SecCheck) {
 -		//TODO check security here
 -		if ( wildcmp( szSection,"Skin_Description_Section"))
 -			return S_OK;
 -	}
 -	if (( This->_Flags == IniParser::FLAG_ONLY_OBJECTS ) && !wildcmp( szSection, DEFAULTSKINSECTION))
 -		return S_OK;					 // skip not objects
 -
 -	switch (szValue[0]) {
 -	case 'b':
 -		db_set_b(NULL, szSection, szName, (BYTE)atoi(szValue + 1));
 -		break;
 -
 -	case 'w':
 -		db_set_w(NULL, szSection, szName, (WORD)atoi(szValue + 1));
 -		break;
 -
 -	case 'd':
 -		db_set_dw(NULL, szSection, szName, (DWORD)atoi(szValue + 1));
 -		break;
 -
 -	case 's':
 -		db_set_s(NULL, szSection, szName, szValue + 1);
 -		break;
 -	}
 -	return S_OK;
 -}
 -
 -int IniParser::GetSkinFolder( IN const TCHAR * szFileName, OUT TCHAR * pszFolderName )
 -{
 -	TCHAR *szBuff = mir_tstrdup(szFileName);
 -	TCHAR *pszPos = szBuff + _tcslen(szBuff);
 -	while ( pszPos > szBuff && *pszPos != _T('.')) { pszPos--; }
 -	*pszPos = _T('\0');
 -	_tcscpy( pszFolderName, szBuff );
 -
 -	TCHAR custom_folder[MAX_PATH];
 -	TCHAR cus[MAX_PATH];
 -	TCHAR *b3;
 -	_tcscpy( custom_folder, pszFolderName );
 -	b3 = custom_folder + _tcslen( custom_folder );
 -	while ( b3 > custom_folder && *b3 != _T('\\')) { b3--; }
 -	*b3 = _T('\0');
 -
 -	GetPrivateProfileString(_T("Skin_Description_Section"),_T("SkinFolder"),_T(""),cus,SIZEOF(custom_folder),szFileName);
 -	if (cus[0] != 0)
 -		mir_sntprintf(pszFolderName, MAX_PATH, _T("%s\\%s"), custom_folder, cus);
 -
 -	mir_free(szBuff);
 -	PathToRelativeT(pszFolderName, pszFolderName);
 -	return 0;
 -}
 -
 -void IniParser::_DoInit()
 -{
 -	_isValid = false;
 -	_eType = IT_UNKNOWN;
 -	_szSection = NULL;
 -	_hFile = NULL;
 -	_hGlobalRes = NULL;
 -	_dwSizeOfRes = 0;
 -	_pPosition = NULL;
 -	_pLineCallBackProc = NULL;
 -	_SecCheck = 0;
 -}
 -
 -void IniParser::_LoadResourceIni( HINSTANCE hInst,  const char *  resourceName, const char * resourceType )
 -{
 -	if (_eType != IT_UNKNOWN)
 -		return;
 -
 -	HRSRC hRSrc = FindResourceA(hInst, resourceName, resourceType);
 -	if (!hRSrc)
 -		return;
 -
 -	_hGlobalRes = LoadResource(hInst, hRSrc);
 -	if (!_hGlobalRes)
 -		return;
 -
 -	_dwSizeOfRes = SizeofResource(hInst, hRSrc);
 -	_pPosition = (char*)LockResource(_hGlobalRes);
 -
 -	_isValid = true;
 -	_eType = IT_RESOURCE;
 -}
 -
 -HRESULT IniParser::_DoParseFile()
 -{
 -	char szLine[MAX_LINE_LEN];
 -	_nLine = 0;
 -	while (fgets(szLine, SIZEOF(szLine), _hFile) != NULL) {
 -		size_t len = 0;
 -		char * pLine = (char*)_RemoveTailings(szLine, len);
 -		if (len > 0) {
 -			pLine[len] = '\0';
 -			if (!_DoParseLine(pLine))	return E_FAIL;
 -		}
 -		else _nLine++;
 -	};
 -
 -	return S_OK;
 -}
 -
 -HRESULT IniParser::_DoParseResource()
 -{
 -	_nLine = 0;
 -	char szLine[MAX_LINE_LEN];
 -	char * pos = (char*)_pPosition;
 -
 -	while (pos < _pPosition + _dwSizeOfRes) {
 -		int i = 0;
 -		while (pos < _pPosition + _dwSizeOfRes && *pos != '\n' && *pos != '\0' && i < MAX_LINE_LEN - 1) {
 -			if ((*pos) != '\r')
 -				szLine[i++] = *pos;
 -			pos++;
 -		}
 -		szLine[i] = '\0';
 -		pos++;
 -
 -		size_t len = 0;
 -		char * pLine = (char*)_RemoveTailings(szLine, len);
 -		if (len > 0) {
 -			pLine[len] = '\0';
 -			if (!_DoParseLine(pLine))	return E_FAIL;
 -		}
 -		else _nLine++;
 -	}
 -	return S_OK;
 -}
 -
 -const char * IniParser::_RemoveTailings( const char * szLine, size_t& len )
 -{
 -	const char * pStart = szLine;
 -	while (*pStart == ' ' || *pStart == '\t')
 -		pStart++; //skip spaces at begin
 -	const char * pEnd = pStart + strlen(pStart);
 -	while (pEnd > pStart && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n' || *pEnd == '\r'))
 -		pEnd--;
 -
 -	len = pEnd - pStart;
 -	return pStart;
 -}
 -
 -BOOL IniParser::_DoParseLine( char * szLine )
 -{
 -	_nLine++;
 -	DWORD len = strlen( szLine );
 -
 -	if (len == 0)	return TRUE;
 -
 -	switch( szLine[0] ) {
 -	case ';':
 -		return TRUE; // start of comment is found
 -
 -	case '[':
 -		//New section start here
 -		mir_free(_szSection);
 -		_szSection = NULL;
 -		{
 -			char *tbuf = szLine + 1;	// skip [
 -
 -			char *ebuf = tbuf;
 -
 -			while (*ebuf != ']' && *ebuf != '\0') ebuf++;
 -			if (*ebuf == '\0')
 -				return FALSE; // no close bracket
 -
 -			DWORD sectionLen = ebuf - tbuf;
 -			_szSection = (char*)mir_alloc(sectionLen + 1);
 -			strncpy(_szSection, tbuf, sectionLen);
 -			_szSection[sectionLen] = '\0';
 -		}
 -		return TRUE;
 -
 -	default:
 -		if (!_szSection )
 -			return TRUE;  //param found out of section
 -
 -		char *keyName = szLine;
 -		char *keyValue = szLine;
 -
 -		DWORD eqPlace = 0;
 -		DWORD len2 = strlen(keyName);
 -
 -		while ( eqPlace < len2 && keyName[ eqPlace ] != '=' )
 -			eqPlace++; //find '='
 -
 -		if (eqPlace == 0 || eqPlace == len2)
 -			return TRUE; // = not found or no key name //say false
 -
 -		keyName[eqPlace] = '\0';
 -
 -		keyValue = keyName + eqPlace + 1;
 -
 -		//remove tail spaces in Name
 -		{
 -			DWORD len3 = strlen(keyName);
 -			int j = len3-1;
 -			while (j>0 && (keyName[j] == ' ' || keyName[j] == '\t')) j--;
 -			if (j >= 0) keyName[j+1] = '\0';
 -		}
 -		//remove start spaces in Value
 -		{
 -			DWORD len3 = strlen(keyValue);
 -			DWORD j = 0;
 -			while (j < len3 && (keyValue[j] == ' ' || keyValue[j] == '\t')) j++;
 -			if (j < len3) keyValue += j;
 -		}
 -		//remove tail spaces in Value
 -		{
 -			DWORD len3 = strlen(keyValue);
 -			int j = len3-1;
 -			while (j>0 && (keyValue[j] == ' ' || keyValue[j] == '\t' || keyValue[j] == '\n')) j--;
 -			if (j >= 0) keyValue[j+1] = '\0';
 -		}
 -		_pLineCallBackProc( _szSection, keyName, keyValue, this );
 -	}
 -	return TRUE;
 -}
 -//////////////////////////////////////////////////////////////////////////
 -// End of IniParser
 -//////////////////////////////////////////////////////////////////////////
 -
 -HRESULT SkinEngineLoadModule()
 -{
 -	ModernSkinButtonLoadModule();
 -	InitializeCriticalSection(&cs_SkinChanging);
 -	MainModernMaskList = (LISTMODERNMASK*)mir_calloc(sizeof(LISTMODERNMASK));
 -	//init variables
 -	g_SkinObjectList.dwObjLPAlocated = 0;
 -	g_SkinObjectList.dwObjLPReserved = 0;
 -	g_SkinObjectList.pObjects = NULL;
 -	// Initialize GDI+
 -	InitGdiPlus();
 -	AniAva_InitModule();
 -	//create services
 -	CreateServiceFunction(MS_SKIN_DRAWGLYPH,ske_Service_DrawGlyph);
 -	CreateServiceFunction(MS_SKINENG_UPTATEFRAMEIMAGE,ske_Service_UpdateFrameImage);
 -	CreateServiceFunction(MS_SKINENG_INVALIDATEFRAMEIMAGE,ske_Service_InvalidateFrameImage);
 -	CreateServiceFunction(MS_SKINENG_ALPHATEXTOUT,ske_Service_AlphaTextOut);
 -	CreateServiceFunction(MS_SKINENG_DRAWICONEXFIX,ske_Service_DrawIconEx);
 -
 -	CreateServiceFunction(MS_DRAW_TEXT_WITH_EFFECT,ske_Service_DrawTextWithEffect);
 -
 -	//create event handle
 -	hSkinLoadedEvent = HookEvent(ME_SKIN_SERVICESCREATED,CLUI_OnSkinLoad);
 -	NotifyEventHooks(g_CluiData.hEventSkinServicesCreated, 0, 0);
 -	return S_OK;
 -}
 -
 -int SkinEngineUnloadModule()
 -{
 -	//unload services
 -	ModernSkinButtonUnloadModule(0, 0);
 -	ske_UnloadSkin(&g_SkinObjectList);
 -
 -	mir_free_and_nil(g_SkinObjectList.pObjects);
 -	mir_free_and_nil(g_SkinObjectList.pMaskList);
 -	mir_free_and_nil(MainModernMaskList);
 -
 -	for (int i=0; i < arEffectStack.getCount(); i++)
 -		mir_free(arEffectStack[i]);
 -	arEffectStack.destroy();
 -
 -	if (g_pCachedWindow) {
 -		SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld);
 -		SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld);
 -		DeleteObject(g_pCachedWindow->hBackDIB);
 -		DeleteObject(g_pCachedWindow->hImageDIB);
 -		DeleteDC(g_pCachedWindow->hBackDC);
 -		DeleteDC(g_pCachedWindow->hImageDC);
 -		ReleaseDC(NULL,g_pCachedWindow->hScreenDC);
 -		mir_free_and_nil(g_pCachedWindow);
 -	}
 -	DeleteCriticalSection(&cs_SkinChanging);
 -	GdiFlush();
 -	DestroyHookableEvent(g_CluiData.hEventSkinServicesCreated);
 -	AniAva_UnloadModule();
 -	ShutdownGdiPlus();
 -	//free variables
 -	return 1;
 -}
 -
 -BOOL ske_AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int nHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction)
 -{
 -	if (g_CluiData.fDisableSkinEngine && !(blendFunction.BlendFlags&128))
 -	{
 -		if (nWidthDest != nWidthSrc || nHeightDest != nHeightSrc)
 -			return StretchBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc, SRCCOPY);
 -		else
 -			return BitBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc, SRCCOPY);
 -	}
 -
 -	if (blendFunction.BlendFlags&128) //Use gdi+ engine
 -	{
 -		return GDIPlus_AlphaBlend( hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,
 -			hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,
 -			&blendFunction);
 -	}
 -	blendFunction.BlendFlags &= ~128;
 -	return AlphaBlend(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,blendFunction);
 -}
 -
 -static int ske_LockSkin()
 -{
 -	EnterCriticalSection(&cs_SkinChanging);
 -	return 0;
 -}
 -
 -static int ske_UnlockSkin()
 -{
 -	LeaveCriticalSection(&cs_SkinChanging);
 -	return 0;
 -}
 -
 -struct DCBUFFER
 -{
 -	HDC hdcOwnedBy;
 -	int nUsageID;
 -	int width;
 -	int height;
 -	void* pImage;
 -	HDC hDC;
 -	HBITMAP oldBitmap;
 -	HBITMAP hBitmap;
 -	DWORD dwDestroyAfterTime;
 -};
 -
 -static int SortBufferList(const DCBUFFER *buf1, const DCBUFFER *buf2)
 -{
 -	if (buf1->hdcOwnedBy != buf2->hdcOwnedBy) return (int)(buf1->hdcOwnedBy < buf2->hdcOwnedBy);
 -	else if (buf1->nUsageID != buf2->nUsageID) return (int)(buf1->nUsageID < buf2->nUsageID);
 -	else return (int)(buf1->hDC < buf2->hDC);
 -}
 -
 -LIST<DCBUFFER> BufferList(2, SortBufferList);
 -CRITICAL_SECTION BufferListCS = {0};
 -
 -enum
 -{
 -	BUFFER_DRAWICON = 0,
 -	BUFFER_DRAWIMAGE
 -};
 -
 -HDC ske_RequestBufferDC(HDC hdcOwner, int dcID, int width, int height, BOOL fClear)
 -{
 -	mir_cslock lck(BufferListCS);
 -	//Try to find DC in buffer list
 -	DCBUFFER buf;
 -	buf.hdcOwnedBy = hdcOwner;
 -	buf.nUsageID = dcID;
 -	buf.hDC = NULL;
 -	DCBUFFER *pBuf = BufferList.find(&buf);
 -	if (!pBuf) {
 -		//if not found - allocate it
 -		pBuf = (DCBUFFER *)mir_alloc(sizeof(DCBUFFER));
 -		*pBuf = buf;
 -		pBuf->width = width;
 -		pBuf->height = height;
 -		pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage));
 -		pBuf->hDC = CreateCompatibleDC(hdcOwner);
 -		pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap);
 -		pBuf->dwDestroyAfterTime = 0;
 -		BufferList.insert(pBuf);
 -	}
 -	else
 -	{
 -		if (pBuf->width != width || pBuf->height != height)
 -		{
 -			//resize
 -			SelectObject(pBuf->hDC,pBuf->oldBitmap);
 -			DeleteObject(pBuf->hBitmap);
 -			pBuf->width = width;
 -			pBuf->height = height;
 -			pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage));
 -			pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap);
 -		}  else	if (fClear)
 -			memset(pBuf->pImage, 0, width*height*sizeof(DWORD));
 -	}
 -	pBuf->dwDestroyAfterTime = 0;
 -	return pBuf->hDC;
 -}
 -
 -int ske_ReleaseBufferDC(HDC hDC, int keepTime)
 -{
 -	DWORD dwCurrentTime = GetTickCount();
 -
 -	//Try to find DC in buffer list - set flag to be release after time;
 -	mir_cslock lck(BufferListCS);
 -	for (int i=0; i < BufferList.getCount(); i++) {
 -		DCBUFFER *pBuf = BufferList[i];
 -		if (pBuf) {
 -			if (hDC != NULL && pBuf->hDC == hDC) {
 -				pBuf->dwDestroyAfterTime = dwCurrentTime+keepTime;
 -				break;
 -			}
 -
 -			if ((pBuf->dwDestroyAfterTime && pBuf->dwDestroyAfterTime < dwCurrentTime) || keepTime == -1) {
 -				SelectObject(pBuf->hDC,pBuf->oldBitmap);
 -				DeleteObject(pBuf->hBitmap);
 -				DeleteDC(pBuf->hDC);
 -				mir_free(pBuf);
 -				BufferList.remove(i);
 -				i--;
 -			}
 -		}
 -	}
 -	return 0;
 -}
 -
 -BOOL ske_SetRgnOpaque(HDC memdc,HRGN hrgn, BOOL force)
 -{
 -	RGNDATA * rdata;
 -	DWORD rgnsz;
 -	DWORD d;
 -	RECT *rect;
 -	if (g_CluiData.fDisableSkinEngine && !force) return TRUE;
 -	rgnsz = GetRegionData(hrgn, 0, NULL);
 -	rdata = (RGNDATA *) mir_alloc(rgnsz);
 -	GetRegionData(hrgn,rgnsz,rdata);
 -	rect = (RECT *)rdata->Buffer;
 -	for (d = 0; d < rdata->rdh.nCount; d++)
 -	{
 -		ske_SetRectOpaque(memdc,&rect[d], force);
 -	}
 -	mir_free(rdata);
 -	return TRUE;
 -}
 -
 -
 -BOOL ske_SetRectOpaque(HDC memdc,RECT *fr, BOOL force)
 -{
 -	int f = 0;
 -	BYTE * bits;
 -	BITMAP bmp;
 -	HBITMAP hbmp;
 -
 -	if ( g_CluiData.fDisableSkinEngine && !force )
 -		return TRUE;
 -
 -	hbmp = (HBITMAP)GetCurrentObject( memdc,OBJ_BITMAP );
 -	GetObject( hbmp, sizeof(bmp), &bmp );
 -
 -	if ( bmp.bmPlanes != 1 )
 -		return FALSE;
 -
 -	if (!bmp.bmBits)
 -	{
 -		f = 1;
 -		bits = (BYTE*)malloc(bmp.bmWidthBytes*bmp.bmHeight);
 -		GetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits);
 -	}
 -	else
 -		bits = (BYTE*)bmp.bmBits;
 -
 -	int sx  = ( fr->left > 0 ) ? fr->left : 0;
 -	int sy  = ( fr->top > 0 ) ? fr->top : 0;
 -	int ex  = ( fr->right < bmp.bmWidth ) ? fr->right : bmp.bmWidth;
 -	int ey  = ( fr->bottom < bmp.bmHeight) ? fr->bottom : bmp.bmHeight;
 -
 -	int width = ex-sx;
 -
 -	BYTE* pLine = ((BYTE*)bits) + (bmp.bmHeight-sy-1)*bmp.bmWidthBytes + (sx << 2) + 3;
 -	for ( int y = 0; y < (ey - sy); y++ )
 -	{
 -		BYTE * pColumn = pLine;
 -		for ( int x = 0; x < width; x++ )
 -		{
 -			*pColumn = 255;
 -			pColumn += 4;
 -		}
 -		pLine -= bmp.bmWidthBytes;
 -	}
 -	if (f)
 -	{
 -		SetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits);
 -		free(bits);
 -	}
 -	// DeleteObject(hbmp);
 -	return 1;
 -}
 -
 -static BOOL ske_SkinFillRectByGlyph(HDC hDest, HDC hSource, RECT *rFill, RECT *rGlyph, RECT *rClip, BYTE mode, BYTE drawMode, int depth)
 -{
 -	int destw = 0, desth = 0;
 -	int xstart = 0, xmax = 0;
 -	int ystart = 0, ymax = 0;
 -	BLENDFUNCTION bfa = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 -	BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 -
 -	//initializations
 -	if (mode == FM_STRETCH)
 -	{
 -		HDC mem2dc;
 -		HBITMAP mem2bmp, oldbmp;
 -		RECT wr;
 -		IntersectRect(&wr,rClip,rFill);
 -		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
 -		if (drawMode != 2)
 -		{
 -			mem2dc = CreateCompatibleDC(hDest);
 -			mem2bmp = ske_CreateDIB32(wr.right-wr.left,wr.bottom-wr.top);
 -			oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
 -
 -		}
 -
 -		if (drawMode == 0 || drawMode == 2)
 -		{
 -			if (drawMode == 0)
 -			{
 -				ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top,
 -					hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
 -				ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf);
 -			}
 -			else
 -			{
 -				ske_AlphaBlend(hDest,rFill->left,rFill->top,rFill->right-rFill->left,rFill->bottom-rFill->top,
 -					hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
 -
 -			}
 -		}
 -		else
 -		{
 -			//            BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
 -			ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top,
 -				hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
 -			ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf);
 -		}
 -		if (drawMode != 2)
 -		{
 -			SelectObject(mem2dc,oldbmp);
 -			DeleteObject(mem2bmp);
 -			DeleteDC(mem2dc);
 -		}
 -		return 1;
 -	}
 -	else if (mode == FM_TILE_VERT && (rGlyph->bottom-rGlyph->top>0) &&  (rGlyph->right-rGlyph->left>0))
 -	{
 -		HDC mem2dc;
 -		HBITMAP mem2bmp,oldbmp;
 -		RECT wr;
 -		IntersectRect(&wr,rClip,rFill);
 -		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
 -		mem2dc = CreateCompatibleDC(hDest);
 -		//SetStretchBltMode(mem2dc, HALFTONE);
 -		mem2bmp = ske_CreateDIB32(wr.right-wr.left, rGlyph->bottom-rGlyph->top);
 -		oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
 -		if (!oldbmp)
 -			return 0;
 -
 -		/// draw here
 -		{
 -			int  y = 0, sy = 0, maxy = 0;
 -			int w = rFill->right-rFill->left;
 -			int h = rGlyph->bottom-rGlyph->top;
 -			if (h>0 && (wr.bottom-wr.top)*(wr.right-wr.left) != 0)
 -			{
 -				w = wr.right-wr.left;
 -				{
 -					//                   BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
 -					ske_AlphaBlend(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,bf);
 -					//StretchBlt(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,SRCCOPY);
 -				}
 -				if (drawMode == 0 || drawMode == 2)
 -				{
 -					if (drawMode == 0 )
 -					{
 -
 -						int dy;
 -						dy = (wr.top-rFill->top)%h;
 -						if (dy >= 0)
 -						{
 -							int ht;
 -							y = wr.top;
 -							ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top);
 -							BitBlt(hDest,wr.left,y,w,ht,mem2dc, 0, dy,SRCCOPY);
 -						}
 -
 -						y = wr.top+h-dy;
 -						while (y < wr.bottom-h){
 -							BitBlt(hDest,wr.left,y,w,h,mem2dc, 0, 0, SRCCOPY);
 -							y += h;
 -						}
 -						if (y <= wr.bottom)
 -							BitBlt(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, SRCCOPY);
 -
 -					}
 -					else
 -					{
 -						y = wr.top;
 -						while (y < wr.bottom-h)
 -						{
 -							//                             BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
 -							ske_AlphaBlend(hDest,wr.left,y,w,h, mem2dc, 0, 0, w,h,bf);
 -							y += h;
 -						}
 -						if (y <= wr.bottom)
 -						{
 -							//                           BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
 -							ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf);
 -						}
 -					}
 -
 -				}
 -				else
 -				{
 -					int dy;
 -
 -					BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 -
 -					dy = (wr.top-rFill->top)%h;
 -
 -					if (dy >= 0)
 -					{
 -						int ht;
 -						y = wr.top;
 -						ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top);
 -						ske_AlphaBlend(hDest,wr.left,y,w,ht,mem2dc, 0, dy,w,ht,bf);
 -					}
 -
 -					y = wr.top+h-dy;
 -					while (y < wr.bottom-h)
 -					{
 -						ske_AlphaBlend(hDest,wr.left,y,w,h,mem2dc, 0, 0, w,h,bf);
 -						y += h;
 -					}
 -					if (y <= wr.bottom)
 -						ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf);
 -				}
 -			}
 -		}
 -		SelectObject(mem2dc,oldbmp);
 -		DeleteObject(mem2bmp);
 -		DeleteDC(mem2dc);
 -	}
 -	else if (mode == FM_TILE_HORZ && (rGlyph->right-rGlyph->left>0) &&  (rGlyph->bottom-rGlyph->top>0) && (rFill->bottom-rFill->top)>0 && (rFill->right-rFill->left)>0)
 -	{
 -		HDC mem2dc;
 -		RECT wr;
 -		HBITMAP mem2bmp,oldbmp;
 -		int w = rGlyph->right-rGlyph->left;
 -		int h = rFill->bottom-rFill->top;
 -		IntersectRect(&wr,rClip,rFill);
 -		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
 -		h = wr.bottom-wr.top;
 -		mem2dc = CreateCompatibleDC(hDest);
 -
 -		mem2bmp = ske_CreateDIB32(w,h);
 -		oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
 -
 -		if (!oldbmp)
 -			return 0;
 -		/// draw here
 -		{
 -			int  x = 0, sy = 0, maxy = 0;
 -			{
 -				//SetStretchBltMode(mem2dc, HALFTONE);
 -				//StretchBlt(mem2dc, 0, 0, w,h,hSource,rGlyph->left+(wr.left-rFill->left),rGlyph->top,w,h,SRCCOPY);
 -
 -				//                    BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
 -				ske_AlphaBlend(mem2dc, 0, -(wr.top-rFill->top),w,rFill->bottom-rFill->top,hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf);
 -				if (drawMode == 0 || drawMode == 2)
 -				{
 -					if (drawMode == 0)
 -					{
 -
 -						int dx;
 -						dx = (wr.left-rFill->left)%w;
 -						if (dx >= 0)
 -						{
 -							int wt;
 -							x = wr.left;
 -							wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
 -							BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY);
 -						}
 -						x = wr.left+w-dx;
 -						while (x < wr.right-w){
 -							BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY);
 -							x += w;
 -						}
 -						if (x <= wr.right)
 -						BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY);
 -					}
 -					else
 -					{
 -						int dx;
 -						dx = (wr.left-rFill->left)%w;
 -						x = wr.left-dx;
 -						while (x < wr.right-w){
 -							ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
 -							x += w;
 -						}
 -						if (x <= wr.right)
 -							ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
 -					}
 -
 -				}
 -				else
 -				{
 -					BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 -					int dx;
 -					dx = (wr.left-rFill->left)%w;
 -					if (dx >= 0)
 -					{
 -						int wt;
 -						x = wr.left;
 -						wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
 -						ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf);
 -					}
 -					x = wr.left+w-dx;
 -					while (x < wr.right-w){
 -						ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
 -						x += w;
 -					}
 -					if (x <= wr.right)
 -						ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
 -
 -				}
 -			}
 -		}
 -		SelectObject(mem2dc,oldbmp);
 -		DeleteObject(mem2bmp);
 -		DeleteDC(mem2dc);
 -	}
 -	else if (mode == FM_TILE_BOTH && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0))
 -	{
 -		HDC mem2dc;
 -		int w = rGlyph->right-rGlyph->left;
 -		int  x = 0, sy = 0, maxy = 0;
 -		int h = rFill->bottom-rFill->top;
 -		HBITMAP mem2bmp,oldbmp;
 -		RECT wr;
 -		IntersectRect(&wr,rClip,rFill);
 -		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
 -		mem2dc = CreateCompatibleDC(hDest);
 -		mem2bmp = ske_CreateDIB32(w,wr.bottom-wr.top);
 -		h = wr.bottom-wr.top;
 -		oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
 -#ifdef _DEBUG
 -		if (!oldbmp)
 -			(NULL,"Tile bitmap not selected","ERROR", MB_OK);
 -#endif
 -		/// draw here
 -		{
 -
 -			//fill temp bitmap
 -			{
 -				int y;
 -				int dy;
 -				dy = (wr.top-rFill->top)%(rGlyph->bottom-rGlyph->top);
 -				y = -dy;
 -				while (y < wr.bottom-wr.top)
 -				{
 -
 -					ske_AlphaBlend(mem2dc, 0, y,w,rGlyph->bottom-rGlyph->top, hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf);
 -					y += rGlyph->bottom-rGlyph->top;
 -				}
 -
 -				//--
 -				//end temp bitmap
 -				if (drawMode == 0 || drawMode == 2)
 -				{
 -					if (drawMode == 0)
 -					{
 -
 -						int dx;
 -						dx = (wr.left-rFill->left)%w;
 -						if (dx >= 0)
 -						{
 -							int wt;
 -							x = wr.left;
 -							wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
 -							BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY);
 -						}
 -						x = wr.left+w-dx;
 -						while (x < wr.right-w){
 -							BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY);
 -							x += w;
 -						}
 -						if (x <= wr.right)
 -						BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY);
 -					}
 -					else
 -					{
 -						int dx;
 -						dx = (wr.left-rFill->left)%w;
 -						x = wr.left-dx;
 -						while (x < wr.right-w){
 -							ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
 -							x += w;
 -						}
 -						if (x <= wr.right)
 -							ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
 -					}
 -
 -				}
 -				else
 -				{
 -					BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 -
 -					int dx;
 -					dx = (wr.left-rFill->left)%w;
 -					if (dx >= 0)
 -					{
 -						int wt;
 -						x = wr.left;
 -						wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
 -						ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf);
 -					}
 -					x = wr.left+w-dx;
 -					while (x < wr.right-w){
 -						ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
 -						x += w;
 -					}
 -					if (x <= wr.right)
 -						ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
 -
 -				}
 -			}
 -
 -		}
 -		SelectObject(mem2dc,oldbmp);
 -		DeleteObject(mem2bmp);
 -		DeleteDC(mem2dc);
 -	}
 -	return 1;
 -
 -}
 -
 -HBITMAP ske_CreateDIB32(int cx, int cy)
 -{
 -	return ske_CreateDIB32Point(cx,cy,NULL);
 -}
 -
 -HBITMAP ske_CreateDIB32Point(int cx, int cy, void ** bits)
 -{
 -	if (cx < 0 || cy < 0)
 -		return NULL;
 -
 -	BITMAPINFO RGB32BitsBITMAPINFO = { 0 };
 -	RGB32BitsBITMAPINFO.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 -	RGB32BitsBITMAPINFO.bmiHeader.biWidth = cx;//bm.bmWidth;
 -	RGB32BitsBITMAPINFO.bmiHeader.biHeight = cy;//bm.bmHeight;
 -	RGB32BitsBITMAPINFO.bmiHeader.biPlanes = 1;
 -	RGB32BitsBITMAPINFO.bmiHeader.biBitCount = 32;
 -	// pointer used for direct Bitmap pixels access
 -
 -	UINT *ptPixels;
 -	HBITMAP DirectBitmap = CreateDIBSection(NULL,
 -		(BITMAPINFO *)&RGB32BitsBITMAPINFO,
 -		DIB_RGB_COLORS,
 -		(void **)&ptPixels,
 -		NULL, 0);
 -	if ((DirectBitmap == NULL || ptPixels == NULL) && cx != 0 && cy != 0)
 -	{
 -#ifdef _DEBUG
 -		MessageBoxA(NULL,"Object not allocated. Check GDI object count","ERROR",MB_OK|MB_ICONERROR);
 -		DebugBreak();
 -#endif
 -		;
 -	}
 -	else memset(ptPixels, 0, cx*cy*4);
 -	if (bits != NULL) *bits = ptPixels;
 -	return DirectBitmap;
 -}
 -
 -HRGN ske_CreateOpaqueRgn(BYTE Level, bool Opaque)
 -{
 -	if (!g_pCachedWindow)
 -		return NULL;
 -
 -	RGBQUAD *buf = (RGBQUAD *) g_pCachedWindow->hImageDIBByte;
 -	if (buf == NULL)
 -		return NULL;
 -
 -	unsigned int cRect = 64;
 -	PRGNDATA pRgnData = (PRGNDATA)malloc(sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
 -	memset(pRgnData, 0, sizeof(RGNDATAHEADER));
 -	pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
 -	pRgnData->rdh.iType = RDH_RECTANGLES;
 -
 -	for (int y = 0; y < g_pCachedWindow->Height; ++y) {
 -		bool inside = false;
 -		bool lastin = false;
 -		unsigned int entry = 0;
 -
 -		for (int x = 0; x < g_pCachedWindow->Width; ++x) {
 -			inside = Opaque ? (buf->rgbReserved > Level) : (buf->rgbReserved < Level);
 -			++buf;
 -
 -			if (inside != lastin) {
 -				if (inside) {
 -					lastin = true;
 -					entry = x;
 -				}
 -				else {
 -					if (pRgnData->rdh.nCount == cRect) {
 -						cRect = cRect + 64;
 -						pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
 -					}
 -					SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, x, g_pCachedWindow->Height - y + 1);
 -
 -					pRgnData->rdh.nCount++;
 -					lastin = false;
 -				}
 -			}
 -		}
 -
 -		if (lastin) {
 -			if (pRgnData->rdh.nCount == cRect) {
 -				cRect = cRect + 64;
 -				pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
 -			}
 -			SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, g_pCachedWindow->Width, g_pCachedWindow->Height - y + 1);
 -
 -			pRgnData->rdh.nCount++;
 -		}
 -	}
 -	
 -	HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData);
 -	free(pRgnData);
 -	return hRgn;
 -}
 -
 -static int ske_DrawSkinObject(SKINDRAWREQUEST * preq, GLYPHOBJECT * pobj)
 -{
 -	HDC memdc = NULL, glyphdc = NULL;
 -	int k = 0;
 -	//BITMAP bmp = {0};
 -	HBITMAP membmp = 0, oldbmp = 0, oldglyph = 0;
 -	BYTE Is32Bit = 0;
 -	RECT PRect;
 -	POINT mode2offset = {0};
 -	int depth = 0;
 -	int mode = 0; //0-FastDraw, 1-DirectAlphaDraw, 2-BufferedAlphaDraw
 -
 -	if (!(preq && pobj)) return -1;
 -	if ((!pobj->hGlyph || pobj->hGlyph == (HBITMAP)-1) && ((pobj->Style&7)  == ST_IMAGE  || (pobj->Style&7)  == ST_FRAGMENT ||  (pobj->Style&7)  == ST_SOLARIZE)) return 0;
 -	// Determine painting mode
 -	depth = GetDeviceCaps(preq->hDC,BITSPIXEL);
 -	depth = depth < 16?16:depth;
 -	Is32Bit = pobj->bmBitsPixel == 32;
 -	if ((!Is32Bit && pobj->dwAlpha == 255) &&  pobj->Style != ST_BRUSH) mode = 0;
 -	else if (pobj->dwAlpha == 255 && pobj->Style != ST_BRUSH) mode = 1;
 -	else mode = 2;
 -	// End painting mode
 -
 -	//force mode
 -
 -	if (preq->rcClipRect.bottom-preq->rcClipRect.top*preq->rcClipRect.right-preq->rcClipRect.left == 0)
 -		preq->rcClipRect = preq->rcDestRect;
 -	IntersectRect(&PRect,&preq->rcDestRect,&preq->rcClipRect);
 -	if (IsRectEmpty(&PRect))
 -	{
 -		return 0;
 -	}
 -	if (mode == 2)
 -	{
 -		memdc = CreateCompatibleDC(preq->hDC);
 -		membmp = ske_CreateDIB32(PRect.right-PRect.left,PRect.bottom-PRect.top);
 -		oldbmp = (HBITMAP)SelectObject(memdc,membmp);
 -		if (oldbmp == NULL)
 -		{
 -			if (mode == 2)
 -			{
 -				SelectObject(memdc,oldbmp);
 -				DeleteDC(memdc);
 -				DeleteObject(membmp);
 -			}
 -			return 0;
 -		}
 -	}
 -
 -	if (mode != 2) memdc = preq->hDC;
 -	{
 -		if (pobj->hGlyph && pobj->hGlyph != (HBITMAP)-1)
 -		{
 -			glyphdc = CreateCompatibleDC(preq->hDC);
 -			if (!oldglyph)
 -				oldglyph = (HBITMAP)SelectObject(glyphdc,pobj->hGlyph);
 -			else
 -				SelectObject(glyphdc,pobj->hGlyph);
 -		}
 -		// Drawing
 -		{
 -			RECT rFill, rGlyph, rClip;
 -			if ((pobj->Style&7)  == ST_BRUSH)
 -			{
 -				HBRUSH br = CreateSolidBrush(pobj->dwColor);
 -				RECT fr;
 -				if (mode == 2)
 -				{
 -					SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top);
 -					FillRect(memdc,&fr,br);
 -					ske_SetRectOpaque(memdc,&fr);
 -					// FillRectAlpha(memdc,&fr,pobj->dwColor|0xFF000000);
 -				}
 -				else
 -				{
 -					fr = PRect;
 -					// SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top);
 -					FillRect(preq->hDC,&fr,br);
 -				}
 -				DeleteObject(br);
 -				k = -1;
 -			}
 -			else
 -			{
 -				if (mode == 2)
 -				{
 -					mode2offset.x = PRect.left;
 -					mode2offset.y = PRect.top;
 -					OffsetRect(&PRect,-mode2offset.x,-mode2offset.y);
 -				}
 -				rClip = (preq->rcClipRect);
 -
 -				{
 -					int lft = 0;
 -					int top = 0;
 -					int rgh = pobj->bmWidth;
 -					int btm = pobj->bmHeight;
 -					if ((pobj->Style&7)  == ST_FRAGMENT)
 -					{
 -						lft = pobj->clipArea.x;
 -						top = pobj->clipArea.y;
 -						rgh = min(rgh,lft+pobj->szclipArea.cx);
 -						btm = min(btm,top+pobj->szclipArea.cy);
 -					}
 -
 -					// Draw center...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.top+pobj->dwTop;
 -						rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
 -						rFill.left = preq->rcDestRect.left+pobj->dwLeft;
 -						rFill.right = preq->rcDestRect.right-pobj->dwRight;
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -						rGlyph.top = top+pobj->dwTop;
 -						rGlyph.left = lft+pobj->dwLeft;
 -						rGlyph.right = rgh-pobj->dwRight;
 -						rGlyph.bottom = btm-pobj->dwBottom;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode,mode,depth);
 -					}
 -
 -					// Draw top side...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.top;
 -						rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
 -						rFill.left = preq->rcDestRect.left+pobj->dwLeft;
 -						rFill.right = preq->rcDestRect.right-pobj->dwRight;
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -						rGlyph.top = top+0;
 -						rGlyph.left = lft+pobj->dwLeft;
 -						rGlyph.right = rgh-pobj->dwRight;
 -						rGlyph.bottom = top+pobj->dwTop;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth);
 -					}
 -					// Draw bottom side...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
 -						rFill.bottom = preq->rcDestRect.bottom;
 -						rFill.left = preq->rcDestRect.left+pobj->dwLeft;
 -						rFill.right = preq->rcDestRect.right-pobj->dwRight;
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -
 -						rGlyph.top = btm-pobj->dwBottom;
 -						rGlyph.left = lft+pobj->dwLeft;
 -						rGlyph.right = rgh-pobj->dwRight;
 -						rGlyph.bottom = btm;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth);
 -					}
 -					// Draw left side...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.top+pobj->dwTop;
 -						rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
 -						rFill.left = preq->rcDestRect.left;
 -						rFill.right = preq->rcDestRect.left+pobj->dwLeft;
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -
 -						rGlyph.top = top+pobj->dwTop;
 -						rGlyph.left = lft;
 -						rGlyph.right = lft+pobj->dwLeft;
 -						rGlyph.bottom = btm-pobj->dwBottom;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth);
 -					}
 -
 -					// Draw right side...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.top+pobj->dwTop;
 -						rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
 -						rFill.left = preq->rcDestRect.right-pobj->dwRight;
 -						rFill.right = preq->rcDestRect.right;
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -
 -						rGlyph.top = top+pobj->dwTop;
 -						rGlyph.left = rgh-pobj->dwRight;
 -						rGlyph.right = rgh;
 -						rGlyph.bottom = btm-pobj->dwBottom;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth);
 -					}
 -
 -
 -					// Draw Top-Left corner...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.top;
 -						rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
 -						rFill.left = preq->rcDestRect.left;
 -						rFill.right = preq->rcDestRect.left+pobj->dwLeft;
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -
 -						rGlyph.top = top;
 -						rGlyph.left = lft;
 -						rGlyph.right = lft+pobj->dwLeft;
 -						rGlyph.bottom = top+pobj->dwTop;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
 -					}
 -					// Draw Top-Right corner...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.top;
 -						rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
 -						rFill.left = preq->rcDestRect.right-pobj->dwRight;
 -						rFill.right = preq->rcDestRect.right;
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -
 -						rGlyph.top = top;
 -						rGlyph.left = rgh-pobj->dwRight;
 -						rGlyph.right = rgh;
 -						rGlyph.bottom = top+pobj->dwTop;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
 -					}
 -
 -					// Draw Bottom-Left corner...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
 -						rFill.bottom = preq->rcDestRect.bottom;
 -						rFill.left = preq->rcDestRect.left;
 -						rFill.right = preq->rcDestRect.left+pobj->dwLeft;
 -
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -
 -						rGlyph.left = lft;
 -						rGlyph.right = lft+pobj->dwLeft;
 -						rGlyph.top = btm-pobj->dwBottom;
 -						rGlyph.bottom = btm;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
 -					}
 -					// Draw Bottom-Right corner...
 -					if (1)
 -					{
 -						rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
 -						rFill.bottom = preq->rcDestRect.bottom;
 -						rFill.left = preq->rcDestRect.right-pobj->dwRight;
 -						rFill.right = preq->rcDestRect.right;
 -
 -
 -						if (mode == 2)
 -							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
 -
 -						rGlyph.left = rgh-pobj->dwRight;
 -						rGlyph.right = rgh;
 -						rGlyph.top = btm-pobj->dwBottom;
 -						rGlyph.bottom = btm;
 -
 -						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
 -					}
 -				}
 -
 -			}
 -
 -			if ((k>0 || k == -1) && mode == 2)
 -			{
 -				{
 -					BLENDFUNCTION bf = {AC_SRC_OVER, 0, /*(bm.bmBitsPixel == 32)?255:*/pobj->dwAlpha, (pobj->bmBitsPixel == 32 && pobj->Style != ST_BRUSH)?AC_SRC_ALPHA:0};
 -					if (mode == 2)
 -						OffsetRect(&PRect,mode2offset.x,mode2offset.y);
 -					ske_AlphaBlend( preq->hDC,PRect.left,PRect.top,PRect.right-PRect.left,PRect.bottom-PRect.top,
 -						memdc, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top,bf);
 -				}
 -			}
 -		}
 -		//free GDI resources
 -		//--++--
 -
 -		//free GDI resources
 -		{
 -
 -			if (oldglyph) SelectObject(glyphdc,oldglyph);
 -			if (glyphdc) DeleteDC(glyphdc);
 -		}
 -		if (mode == 2)
 -		{
 -			SelectObject(memdc,oldbmp);
 -			DeleteDC(memdc);
 -			DeleteObject(membmp);
 -		}
 -
 -	}
 -	if (pobj->plTextList && pobj->plTextList->realCount>0)
 -	{
 -		int i;
 -		HFONT hOldFont;
 -		for (i=0; i < pobj->plTextList->realCount; i++)
 -		{
 -			GLYPHTEXT * gt = (GLYPHTEXT *)pobj->plTextList->items[i];
 -			if (!gt->hFont)
 -			{
 -				if (gl_plSkinFonts && gl_plSkinFonts->realCount>0)
 -				{
 -					int j = 0;
 -					for (j = 0; j < gl_plSkinFonts->realCount; j++)
 -					{
 -						SKINFONT * sf;
 -						sf = (SKINFONT*)gl_plSkinFonts->items[j];
 -						if (sf->szFontID && !strcmp(sf->szFontID,gt->szFontID))
 -						{
 -							gt->hFont = sf->hFont;
 -							break;
 -						}
 -					}
 -				}
 -				if (!gt->hFont) gt->hFont = (HFONT)-1;
 -			}
 -			if (gt->hFont != (HFONT)-1)
 -			{
 -				RECT rc = {0};
 -				hOldFont = (HFONT)SelectObject(preq->hDC,gt->hFont);
 -
 -
 -
 -				if (gt->RelativeFlags&2) rc.left = preq->rcDestRect.right+gt->iLeft;
 -				else if (gt->RelativeFlags&1) rc.left = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iLeft;
 -				else rc.left = preq->rcDestRect.left+gt->iLeft;
 -
 -				if (gt->RelativeFlags&8) rc.top = preq->rcDestRect.bottom+gt->iTop;
 -				else if (gt->RelativeFlags&4) rc.top = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iTop;
 -				else rc.top = preq->rcDestRect.top+gt->iTop;
 -
 -				if (gt->RelativeFlags&32) rc.right = preq->rcDestRect.right+gt->iRight;
 -				else if (gt->RelativeFlags&16) rc.right = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iRight;
 -				else rc.right = preq->rcDestRect.left+gt->iRight;
 -
 -				if (gt->RelativeFlags&128) rc.bottom = preq->rcDestRect.bottom+gt->iBottom;
 -				else if (gt->RelativeFlags&64) rc.bottom = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iBottom;
 -				else rc.bottom = preq->rcDestRect.top+gt->iBottom;
 -
 -				ske_AlphaTextOut(preq->hDC, gt->stText, -1, &rc,gt->dwFlags, gt->dwColor);
 -				SelectObject(preq->hDC,hOldFont);
 -			}
 -		}
 -	}
 -
 -	return 0;
 -}
 -
 -
 -
 -int ske_AddDescriptorToSkinObjectList (LPSKINOBJECTDESCRIPTOR lpDescr, SKINOBJECTSLIST* Skin)
 -{
 -	SKINOBJECTSLIST *sk;
 -	if (Skin) sk = Skin; else sk = &g_SkinObjectList;
 -	if (!sk) return 0;
 -	if (mir_bool_strcmpi(lpDescr->szObjectID,"_HEADER_")) return 0;
 -	{//check if new object allready presents.
 -		DWORD i=0;
 -		for (i=0; i < sk->dwObjLPAlocated; i++)
 -			if (!mir_strcmp(sk->pObjects[i].szObjectID,lpDescr->szObjectID)) return 0;
 -	}
 -	if (sk->dwObjLPAlocated+1>sk->dwObjLPReserved)
 -	{ // Realocated list to add space for new object
 -
 -		sk->pObjects = (SKINOBJECTDESCRIPTOR*)mir_realloc(sk->pObjects,sizeof(SKINOBJECTDESCRIPTOR)*(sk->dwObjLPReserved+1)/*alloc step*/);
 -		sk->dwObjLPReserved++;
 -	}
 -	{ //filling new objects field
 -		sk->pObjects[sk->dwObjLPAlocated].bType = lpDescr->bType;
 -		sk->pObjects[sk->dwObjLPAlocated].Data = NULL;
 -		sk->pObjects[sk->dwObjLPAlocated].szObjectID = mir_strdup(lpDescr->szObjectID);
 -		//  sk->Objects[sk->dwObjLPAlocated].szObjectName = mir_strdup(lpDescr->szObjectName);
 -		if (lpDescr->Data != NULL)
 -		{   //Copy defaults values
 -			switch (lpDescr->bType)
 -			{
 -			case OT_GLYPHOBJECT:
 -				{
 -					GLYPHOBJECT * obdat;
 -					GLYPHOBJECT * gl = (GLYPHOBJECT*)lpDescr->Data;
 -					sk->pObjects[sk->dwObjLPAlocated].Data = mir_alloc(sizeof(GLYPHOBJECT));
 -					obdat = (GLYPHOBJECT*)sk->pObjects[sk->dwObjLPAlocated].Data;
 -					memcpy(obdat,gl,sizeof(GLYPHOBJECT));
 -					if (gl->szFileName != NULL)
 -					{
 -						obdat->szFileName = mir_strdup(gl->szFileName);
 -						mir_free_and_nil(gl->szFileName);
 -					}
 -					else obdat->szFileName = NULL;
 -
 -					obdat->hGlyph = NULL;
 -					break;
 -				}
 -			}
 -
 -		}
 -	}
 -	sk->dwObjLPAlocated++;
 -	return 1;
 -}
 -
 -static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin)
 -{
 -	// DWORD i;
 -	SKINOBJECTSLIST* sk;
 -	sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
 -	return skin_FindObjectByRequest((char *)szName,sk->pMaskList);
 -}
 -
 -static LPSKINOBJECTDESCRIPTOR ske_FindObjectByMask(MODERNMASK *pModernMask, BYTE objType, SKINOBJECTSLIST* Skin)
 -{
 -	// DWORD i;
 -	SKINOBJECTSLIST* sk;
 -	sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
 -	if (!sk->pMaskList) return NULL;
 -	return skin_FindObjectByMask(pModernMask,sk->pMaskList);
 -}
 -
 -LPSKINOBJECTDESCRIPTOR ske_FindObjectByName(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin)
 -{
 -	DWORD i;
 -	SKINOBJECTSLIST* sk;
 -	sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
 -	for (i=0; i < sk->dwObjLPAlocated; i++)
 -	{
 -		if (sk->pObjects[i].bType == objType || objType == OT_ANY)
 -		{
 -			if (!mir_strcmp(sk->pObjects[i].szObjectID,szName))
 -				return &(sk->pObjects[i]);
 -		}
 -	}
 -	return NULL;
 -}
 -
 -//////////////////////////////////////////////////////////////////////////
 -// Paint glyph
 -// wParam - LPSKINDRAWREQUEST
 -// lParam - possible direct pointer to modern mask
 -//////////////////////////////////////////////////////////////////////////
 -
 -INT_PTR ske_Service_DrawGlyph(WPARAM wParam, LPARAM lParam)
 -{
 -	LPSKINDRAWREQUEST preq;
 -	LPSKINOBJECTDESCRIPTOR pgl;
 -	LPGLYPHOBJECT gl;
 -	if (!wParam) return -1;
 -	ske_LockSkin();
 -	__try
 -	{
 -		preq = (LPSKINDRAWREQUEST)wParam;
 -		if (lParam)
 -			pgl = ske_FindObjectByMask((MODERNMASK*)lParam, OT_GLYPHOBJECT,NULL);
 -		else
 -			pgl = ske_FindObject(preq->szObjectID, OT_GLYPHOBJECT,NULL);
 -		if (pgl == NULL) return -1;
 -		if (pgl->Data == NULL) return -1;
 -
 -		gl = (LPGLYPHOBJECT)pgl->Data;
 -		int iStyle = gl->Style & 7;
 -		if (iStyle == ST_SKIP)
 -			return ST_SKIP;
 -
 -		if (gl->hGlyph == NULL && gl->hGlyph != (HBITMAP)-1 && (iStyle == ST_IMAGE || iStyle == ST_FRAGMENT || iStyle == ST_SOLARIZE))
 -			if (gl->szFileName) {
 -				gl->hGlyph = ske_LoadGlyphImage( _A2T(gl->szFileName));
 -				if (gl->hGlyph) {
 -					BITMAP bmp = {0};
 -					GetObject(gl->hGlyph,sizeof(BITMAP),&bmp);
 -					gl->bmBitsPixel = (BYTE)bmp.bmBitsPixel;
 -					gl->bmHeight = bmp.bmHeight;
 -					gl->bmWidth = bmp.bmWidth;
 -				}
 -				else gl->hGlyph = (HBITMAP)-1; //invalid
 -			}
 -			return ske_DrawSkinObject(preq,gl);
 -	}
 -	__finally
 -	{
 -		ske_UnlockSkin();
 -	}
 -	return -1;
 -}
 -
 -
 -void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult)
 -{
 -	BITMAP bmp;
 -	BOOL flag = FALSE;
 -	BYTE * pBitmapBits;
 -	DWORD Len;
 -	int bh,bw,y,x;
 -
 -	GetObject(hbmp, sizeof(BITMAP), (LPSTR)&bmp);
 -	bh = bmp.bmHeight;
 -	bw = bmp.bmWidth;
 -	Len = bh*bw*4;
 -	flag = (bmp.bmBits == NULL);
 -	if (flag)
 -	{
 -		pBitmapBits = (LPBYTE)malloc(Len);
 -		GetBitmapBits(hbmp,Len,pBitmapBits);
 -	}
 -	else
 -		pBitmapBits = (BYTE*)bmp.bmBits;
 -	for (y = 0; y < bh; ++y)
 -	{
 -		BYTE *pPixel = pBitmapBits + bw * 4 * y;
 -
 -		for (x = 0; x < bw ; ++x)
 -		{
 -			if (Mult)
 -			{
 -				pPixel[0] = pPixel[0]*pPixel[3]/255;
 -				pPixel[1] = pPixel[1]*pPixel[3]/255;
 -				pPixel[2] = pPixel[2]*pPixel[3]/255;
 -			}
 -			else
 -			{
 -				pPixel[3] = 255;
 -			}
 -			pPixel += 4;
 -		}
 -	}
 -	if (flag)
 -	{
 -		Len = SetBitmapBits(hbmp,Len,pBitmapBits);
 -		free (pBitmapBits);
 -	}
 -	return;
 -}
 -
 -int ske_GetFullFilename(TCHAR *buf, const TCHAR *file, TCHAR *skinfolder, BOOL madeAbsolute)
 -{
 -	TCHAR *SkinPlace = db_get_tsa(NULL,SKIN,"SkinFolder");
 -	if (SkinPlace == NULL)
 -		SkinPlace = mir_tstrdup( _T("\\Skin\\default"));
 -
 -	TCHAR b2[MAX_PATH];
 -	if (file[0] != '\\' && file[1] != ':')
 -		mir_sntprintf(b2, MAX_PATH, _T("%s\\%s"), (skinfolder == NULL) ? SkinPlace : ((INT_PTR)skinfolder != -1) ? skinfolder : _T(""), file);
 -	else
 -		_tcsncpy(b2, file, SIZEOF(b2));
 -
 -	if (madeAbsolute) {
 -		if (b2[0] == '\\' && b2[1] != '\\')
 -			PathToAbsoluteT(b2+1, buf);
 -		else
 -			PathToAbsoluteT(b2, buf);
 -	}
 -	else _tcsncpy(buf, b2, MAX_PATH);
 -
 -	mir_free(SkinPlace);
 -	return 0;
 -}
 -
 -/*
 -This function is required to load TGA to dib buffer myself
 -Major part of routines is from http://tfcduke.developpez.com/tutoriel/format/tga/fichiers/tga.c
 -*/
 -
 -static BOOL ske_ReadTGAImageData(void * From, DWORD fromSize, BYTE * destBuf, DWORD bufSize, BOOL RLE)
 -{
 -	BYTE * pos = destBuf;
 -	BYTE * from = fromSize?(BYTE*)From:NULL;
 -	FILE * fp = !fromSize?(FILE*)From:NULL;
 -	DWORD destCount = 0;
 -	DWORD fromCount = 0;
 -	if (!RLE)
 -	{
 -		while (((from && fromCount < fromSize) || (fp &&  fromCount < bufSize))
 -			 && (destCount < bufSize))
 -		{
 -			BYTE r = from?from[fromCount++]:(BYTE)fgetc(fp);
 -			BYTE g = from?from[fromCount++]:(BYTE)fgetc(fp);
 -			BYTE b = from?from[fromCount++]:(BYTE)fgetc(fp);
 -			BYTE a = from?from[fromCount++]:(BYTE)fgetc(fp);
 -			pos[destCount++] = r;
 -			pos[destCount++] = g;
 -			pos[destCount++] = b;
 -			pos[destCount++] = a;
 -
 -			if (destCount>bufSize) break;
 -			if (from) 	if (fromCount < fromSize) break;
 -		}
 -	}
 -	else
 -	{
 -		BYTE rgba[4];
 -		BYTE packet_header;
 -		BYTE *ptr = pos;
 -		BYTE size;
 -		int i;
 -		while (ptr < pos + bufSize)
 -		{
 -			/* read first byte */
 -			packet_header = from?from[fromCount]:(BYTE)fgetc(fp);
 -			if (from) from++;
 -			size = 1 + (packet_header & 0x7f);
 -			if (packet_header & 0x80)
 -			{
 -				/* run-length packet */
 -				if (from)
 -				{
 -					*((DWORD*)rgba) = *((DWORD*)(from+fromCount));
 -					fromCount += 4;
 -				}
 -				else fread (rgba, sizeof (BYTE), 4, fp);
 -				for (i=0; i < size; ++i, ptr += 4)
 -				{
 -					ptr[2] = rgba[2];
 -					ptr[1] = rgba[1];
 -					ptr[0] = rgba[0];
 -					ptr[3] = rgba[3];
 -				}
 -			}
 -			else
 -			{	/* not run-length packet */
 -				for (i=0; i < size; ++i, ptr += 4)
 -				{
 -					ptr[0] = from? from[fromCount++]:(BYTE)fgetc (fp);
 -					ptr[1] = from? from[fromCount++]:(BYTE)fgetc (fp);
 -					ptr[2] = from? from[fromCount++]:(BYTE)fgetc (fp);
 -					ptr[3] = from? from[fromCount++]:(BYTE)fgetc (fp);
 -				}
 -			}
 -		}
 -	}
 -	return TRUE;
 -}
 -
 -static HBITMAP ske_LoadGlyphImage_TGA(const TCHAR *szFilename)
 -{
 -	BYTE *colormap = NULL;
 -	int cx = 0, cy = 0;
 -	BOOL err = FALSE;
 -	tga_header_t header;
 -	if (!szFilename) return NULL;
 -	if (!wildcmpit(szFilename, _T("*\\*%.tga"))) {
 -		//Loading TGA image from file
 -		FILE *fp = _tfopen (szFilename, _T("rb"));
 -		if (!fp) {
 -			TRACEVAR("error: couldn't open \"%s\"!\n", szFilename);
 -			return NULL;
 -		}
 -		/* read header */
 -		fread (&header, sizeof (tga_header_t), 1, fp);
 -		if ((header.pixel_depth != 32) || ((header.image_type != 10) && (header.image_type != 2))) {
 -			fclose(fp);
 -			return NULL;
 -		}
 -
 -		/*memory allocation */
 -		colormap = (BYTE*)malloc(header.width*header.height*4);
 -		cx = header.width;
 -		cy = header.height;
 -		fseek (fp, header.id_lenght, SEEK_CUR);
 -		fseek (fp, header.cm_length, SEEK_CUR);
 -		err = !ske_ReadTGAImageData((void*)fp, 0, colormap, header.width*header.height*4,header.image_type == 10);
 -		fclose(fp);
 -	}
 -	else {
 -		/* reading from resources IDR_TGA_DEFAULT_SKIN */
 -		DWORD size = 0;
 -		BYTE * mem;
 -		HGLOBAL hRes;
 -		HRSRC hRSrc = FindResourceA(g_hInst,MAKEINTRESOURCEA(IDR_TGA_DEFAULT_SKIN),"TGA");
 -		if (!hRSrc) return NULL;
 -		hRes = LoadResource(g_hInst,hRSrc);
 -		if (!hRes) return NULL;
 -		size = SizeofResource(g_hInst,hRSrc);
 -		mem = (BYTE*) LockResource(hRes);
 -		if (size>sizeof(header))
 -		{
 -			tga_header_t * header = (tga_header_t *)mem;
 -			if (header->pixel_depth == 32 &&  (header->image_type == 2  || header->image_type == 10))
 -			{
 -				colormap = (BYTE*)malloc(header->width*header->height*4);
 -				cx = header->width;
 -				cy = header->height;
 -				ske_ReadTGAImageData((void*)(mem+sizeof(tga_header_t)+header->id_lenght+header->cm_length), size-(sizeof(tga_header_t)+header->id_lenght+header->cm_length), colormap, cx*cy*4,header->image_type == 10);
 -			}
 -		}
 -		FreeResource(hRes);
 -	}
 -
 -	if (colormap) { //create dib section
 -		BYTE * pt;
 -		HBITMAP hbmp = ske_CreateDIB32Point(cx,cy,(void**)&pt);
 -		if (hbmp)
 -			memcpy(pt,colormap,cx*cy*4);
 -		free(colormap);
 -		return hbmp;
 -	}
 -	return NULL;
 -}
 -
 -
 -//this function is required to load PNG to dib buffer myself
 -static HBITMAP ske_LoadGlyphImage_Png2Dib(const TCHAR *tszFilename)
 -{
 -	HANDLE hFile, hMap = NULL;
 -	BYTE* ppMap = NULL;
 -	long  cbFileSize = 0;
 -	BITMAPINFOHEADER* pDib;
 -	BYTE* pDibBits;
 -
 -	if (!ServiceExists( MS_PNG2DIB )) {
 -		MessageBox( NULL, TranslateT("You need an image services plugin to process PNG images."), TranslateT("Error"), MB_OK );
 -		return (HBITMAP)NULL;
 -	}
 -
 -	if ((hFile = CreateFile(tszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
 -		if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL)
 -			if ((ppMap = ( BYTE* )MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL)
 -				cbFileSize = GetFileSize(hFile, NULL);
 -
 -	if (cbFileSize != 0) {
 -		PNG2DIB param;
 -		param.pSource = ppMap;
 -		param.cbSourceSize = cbFileSize;
 -		param.pResult = &pDib;
 -		if ( CallService(MS_PNG2DIB, 0, (LPARAM)¶m ))
 -			pDibBits = ( BYTE* )( pDib+1 );
 -		else
 -			cbFileSize = 0;
 -	}
 -
 -	if ( ppMap != NULL )	UnmapViewOfFile( ppMap );
 -	if ( hMap  != NULL )	CloseHandle( hMap );
 -	if ( hFile != NULL ) CloseHandle( hFile );
 -
 -	if ( cbFileSize == 0 )
 -		return (HBITMAP)NULL;
 -
 -	HBITMAP hBitmap;
 -	BITMAPINFO* bi = ( BITMAPINFO* )pDib;
 -	BYTE *pt = (BYTE*)bi;
 -	pt += bi->bmiHeader.biSize;
 -	if (bi->bmiHeader.biBitCount != 32) {
 -		HDC sDC = GetDC( NULL );
 -		hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS );
 -		SelectObject( sDC, hBitmap );
 -		DeleteDC( sDC );
 -	}
 -	else {
 -		BYTE *ptPixels = pt;
 -		hBitmap = CreateDIBSection(NULL,bi, DIB_RGB_COLORS, (void **)&ptPixels,  NULL, 0);
 -		memcpy(ptPixels,pt,bi->bmiHeader.biSizeImage);
 -	}
 -	GlobalFree( pDib );
 -	return hBitmap;
 -}
 -
 -static HBITMAP ske_LoadGlyphImageByDecoders(const TCHAR *tszFileName)
 -{
 -	// Loading image from file by imgdecoder...
 -	HBITMAP hBitmap = NULL;
 -	TCHAR ext[5];
 -	BYTE f = 0;
 -	LPVOID pImg = NULL;
 -
 -	BITMAP bmpInfo;
 -	{
 -		int l = lstrlen(tszFileName);
 -		lstrcpyn(ext, tszFileName+(l-4),5);
 -	}
 -	if (!_tcschr(tszFileName,'%') && !PathFileExists(tszFileName))
 -		return NULL;
 -
 -	if (mir_bool_tstrcmpi(ext, _T(".tga"))) {
 -		hBitmap = ske_LoadGlyphImage_TGA(tszFileName);
 -		f = 1;
 -	}
 -	else if ( ServiceExists("Image/Png2Dib") && mir_bool_tstrcmpi(ext, _T(".png"))) {
 -		hBitmap = ske_LoadGlyphImage_Png2Dib(tszFileName);
 -		GetObject(hBitmap, sizeof(BITMAP), &bmpInfo);
 -		f = (bmpInfo.bmBits != NULL);
 -	}
 -	else if (!mir_bool_tstrcmpi(ext, _T(".png"))) {
 -		hBitmap = (HBITMAP)CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)tszFileName);
 -	}
 -
 -	if (hBitmap) {
 -		GetObject(hBitmap, sizeof(BITMAP), &bmpInfo);
 -		if (bmpInfo.bmBitsPixel == 32)
 -			ske_PreMultiplyChanells(hBitmap,f);
 -		else {
 -			HDC dc24,dc32;
 -			HBITMAP hBitmap32,obmp24,obmp32;
 -			dc32 = CreateCompatibleDC(NULL);
 -			dc24 = CreateCompatibleDC(NULL);
 -			hBitmap32 = ske_CreateDIB32(bmpInfo.bmWidth,bmpInfo.bmHeight);
 -			obmp24 = (HBITMAP)SelectObject(dc24,hBitmap);
 -			obmp32 = (HBITMAP)SelectObject(dc32,hBitmap32);
 -			BitBlt(dc32, 0, 0, bmpInfo.bmWidth,bmpInfo.bmHeight,dc24, 0, 0, SRCCOPY);
 -			SelectObject(dc24,obmp24);
 -			SelectObject(dc32,obmp32);
 -			DeleteDC(dc24);
 -			DeleteDC(dc32);
 -			DeleteObject(hBitmap);
 -			hBitmap = hBitmap32;
 -			ske_PreMultiplyChanells(hBitmap,0);
 -		}
 -	}
 -	return hBitmap;
 -}
 -
 -static HBITMAP ske_skinLoadGlyphImage(const TCHAR *tszFileName)
 -{
 -	if (!wildcmpit(tszFileName, _T("*.tga")))
 -		return GDIPlus_LoadGlyphImage(tszFileName);
 -
 -	return ske_LoadGlyphImageByDecoders(tszFileName);
 -}
 -
 -HBITMAP ske_LoadGlyphImage(const TCHAR *tszFileName)
 -{
 -	// try to find image in loaded
 -	DWORD i;
 -	HBITMAP hbmp;
 -	TCHAR szFile [MAX_PATH] = {0};
 -	ske_GetFullFilename(szFile, tszFileName, g_SkinObjectList.szSkinPlace, TRUE);
 -	ske_LockSkin();
 -	if (pLoadedImages) {
 -		for (i=0; i < dwLoadedImagesCount; i++) {
 -			if (mir_bool_tstrcmpi(pLoadedImages[i].szFileName, szFile)) {
 -				pLoadedImages[i].dwLoadedTimes++;
 -				ske_UnlockSkin();
 -				return pLoadedImages[i].hGlyph;
 -			}
 -		}
 -	}
 -	// load new image
 -	hbmp = ske_skinLoadGlyphImage(szFile);
 -	if (hbmp == NULL)
 -	{
 -		ske_UnlockSkin();
 -		return NULL;
 -	}
 -	// add to loaded list
 -	if (dwLoadedImagesCount+1>dwLoadedImagesAlocated)
 -	{
 -		pLoadedImages = (GLYPHIMAGE*)mir_realloc(pLoadedImages,sizeof(GLYPHIMAGE)*(dwLoadedImagesCount+1));
 -		if (pLoadedImages) dwLoadedImagesAlocated++;
 -		else
 -		{
 -			ske_UnlockSkin();
 -			return NULL;
 -		}
 -	}
 -	pLoadedImages[dwLoadedImagesCount].dwLoadedTimes = 1;
 -	pLoadedImages[dwLoadedImagesCount].hGlyph = hbmp;
 -	pLoadedImages[dwLoadedImagesCount].szFileName = mir_tstrdup(szFile);
 -	dwLoadedImagesCount++;
 -	ske_UnlockSkin();
 -	return hbmp;
 -}
 -
 -int ske_UnloadGlyphImage(HBITMAP hbmp)
 -{
 -	DWORD i;
 -	for (i=0; i < dwLoadedImagesCount; i++)
 -	{
 -		if (hbmp == pLoadedImages[i].hGlyph)
 -		{
 -			pLoadedImages[i].dwLoadedTimes--;
 -			if (pLoadedImages[i].dwLoadedTimes == 0)
 -			{
 -				LPGLYPHIMAGE gl = &(pLoadedImages[i]);
 -				mir_free_and_nil(gl->szFileName);
 -				memmove(&(pLoadedImages[i]),&(pLoadedImages[i+1]),sizeof(GLYPHIMAGE)*(dwLoadedImagesCount-i-1));
 -				dwLoadedImagesCount--;
 -				DeleteObject(hbmp);
 -				if (pLoadedImages && dwLoadedImagesCount == 0)
 -				{
 -					dwLoadedImagesAlocated = 0;
 -					mir_free_and_nil(pLoadedImages);
 -				}
 -			}
 -			return 0;
 -		}
 -
 -	}
 -	DeleteObject(hbmp);
 -	return 0;
 -}
 -
 -int ske_UnloadSkin(SKINOBJECTSLIST * Skin)
 -{
 -	DWORD i;
 -	ske_LockSkin();
 -	ClearMaskList(Skin->pMaskList);
 -
 -	//clear font list
 -	if (gl_plSkinFonts && gl_plSkinFonts->realCount > 0) {
 -		for (int i=0; i < gl_plSkinFonts->realCount; i++) {
 -			SKINFONT * sf = (SKINFONT *)gl_plSkinFonts->items[i];
 -			if (sf) {
 -				mir_free(sf->szFontID);
 -				DeleteObject(sf->hFont);
 -				mir_free(sf);
 -			}
 -		}
 -		List_Destroy(gl_plSkinFonts);
 -		mir_free_and_nil(gl_plSkinFonts);
 -	}
 -
 -	mir_free_and_nil(Skin->szSkinPlace);
 -	if (Skin->pTextList) List_Destroy(Skin->pTextList);
 -	mir_free_and_nil(Skin->pTextList);
 -	ModernSkinButtonDeleteAll();
 -	if (Skin->dwObjLPAlocated == 0) { ske_UnlockSkin(); return 0;}
 -	for (i=0; i < Skin->dwObjLPAlocated; i++)
 -	{
 -		switch(Skin->pObjects[i].bType)
 -		{
 -		case OT_GLYPHOBJECT:
 -			{
 -				GLYPHOBJECT * dt;
 -				dt = (GLYPHOBJECT*)Skin->pObjects[i].Data;
 -				if (dt->hGlyph && dt->hGlyph != (HBITMAP)-1)
 -					ske_UnloadGlyphImage(dt->hGlyph);
 -				dt->hGlyph = NULL;
 -				mir_free_and_nil(dt->szFileName);
 -				{// delete texts
 -					int i;
 -					if (dt->plTextList && dt->plTextList->realCount>0)
 -					{
 -						for (i=0; i < dt->plTextList->realCount; i++)
 -						{
 -							GLYPHTEXT * gt = (GLYPHTEXT *)dt->plTextList->items[i];
 -							if (gt) {
 -								mir_free(gt->stText);
 -								mir_free(gt->stValueText);
 -								mir_free(gt->szFontID);
 -								mir_free(gt->szGlyphTextID);
 -								mir_free(gt);
 -							}
 -						}
 -						List_Destroy(dt->plTextList);
 -						mir_free(dt->plTextList);
 -					}
 -				}
 -				mir_free(dt);
 -			}
 -			break;
 -		}
 -		mir_free_and_nil(Skin->pObjects[i].szObjectID);
 -
 -	}
 -	mir_free_and_nil(Skin->pObjects);
 -	Skin->pTextList = NULL;
 -	Skin->dwObjLPAlocated = 0;
 -	Skin->dwObjLPReserved = 0;
 -	ske_UnlockSkin();
 -	return 0;
 -}
 -
 -static void RegisterMaskByParce(const char * szSetting, char * szValue, SKINOBJECTSLIST * pSkin)
 -{
 -	int i;
 -	DWORD ID=atoi(szSetting+1);
 -	for (i=0; i < mir_strlen(szValue); i++)  if (szValue[i] == ':') break;
 -	if (i < mir_strlen(szValue))
 -	{
 -		char * Obj, *Mask;
 -		int res;
 -		Mask = szValue+i+1;
 -		Obj = (char*)mir_alloc(i+1);
 -		strncpy(Obj,szValue,i);
 -		Obj[i] = '\0';
 -		res = AddStrModernMaskToList(ID,Mask,Obj,pSkin->pMaskList,pSkin);
 -		mir_free(Obj);
 -	}
 -}
 -
 -static int ske_ProcessLoadindString(const char * szSetting, char *szValue)
 -{
 -	if (!pCurrentSkin) return 0;
 -	if (szSetting[0] == '$')
 -		RegisterObjectByParce((char *)szSetting, szValue);
 -	else if (szSetting[0] == '#')
 -		RegisterButtonByParce((char *)szSetting,szValue);
 -	else if (szSetting[0] == '@')
 -		RegisterMaskByParce((char *)szSetting,  szValue, pCurrentSkin); ///
 -	else if (szSetting[0] == 't')
 -		ske_AddParseTextGlyphObject((char*)szSetting,szValue,pCurrentSkin);
 -	else if (szSetting[0] == 'f')
 -		ske_AddParseSkinFont((char*)szSetting,szValue,pCurrentSkin);
 -	else return 0;
 -	return 1;
 -}
 -static int ske_enumdb_SkinObjectsProc (const char *szSetting,LPARAM lParam)
 -{
 -	char *value;
 -	value = db_get_sa(NULL,SKIN,szSetting);
 -	ske_ProcessLoadindString(szSetting,value);
 -	mir_free_and_nil(value);
 -
 -	return 0;
 -}
 -
 -static int ske_SortTextGlyphObjectFunc(void * first, void * second)
 -{
 -	return strcmp(((GLYPHTEXT*)(((int*)first)[0]))->szGlyphTextID,((GLYPHTEXT*)(((int*)second)[0]))->szGlyphTextID);
 -}
 -
 -static void ske_LinkSkinObjects(SKINOBJECTSLIST * pObjectList)
 -{
 -	DWORD i;
 -	// LINK Mask with objects
 -	for (i=0; i < pObjectList->pMaskList->dwMaskCnt; i++)
 -	{
 -		MODERNMASK *mm = &(pObjectList->pMaskList->pl_Masks[i]);
 -		void * pObject = (void*) ske_FindObjectByName(mm->szObjectName, OT_ANY, (SKINOBJECTSLIST*) pObjectList);
 -		mir_free_and_nil(mm->szObjectName);
 -		mm->bObjectFound = TRUE;
 -		mm->pObject = pObject;
 -	}
 -
 -	if (pObjectList->pTextList)
 -	{
 -		int i;
 -		// LINK Text with objects
 -		for (i=0; i < pObjectList->pTextList->realCount; i++)
 -		{
 -			GLYPHTEXT * glText;
 -			GLYPHOBJECT *globj = NULL;
 -			SKINOBJECTDESCRIPTOR * lpobj;
 -			glText = (GLYPHTEXT *)pObjectList->pTextList->items[i];
 -			lpobj = ske_FindObjectByName(glText->szObjectName,OT_GLYPHOBJECT, pObjectList);
 -			mir_free_and_nil(glText->szObjectName);
 -			if (lpobj)
 -				globj = (GLYPHOBJECT*)lpobj->Data;
 -			if (globj)
 -			{
 -				if (!globj->plTextList)
 -				{
 -					globj->plTextList = List_Create(0, 1);
 -					globj->plTextList->sortFunc = ske_SortTextGlyphObjectFunc;
 -				}
 -				List_Insert(globj->plTextList,(void*)glText,globj->plTextList->realCount);
 -				qsort(globj->plTextList->items,globj->plTextList->realCount,sizeof(void*),(int(*)(const void*, const void*))globj->plTextList->sortFunc);
 -				pObjectList->pTextList->items[i] = NULL;
 -			}
 -			else
 -			{
 -				GLYPHTEXT *gt = glText;
 -				if (gt) {
 -					mir_free(gt->stText);
 -					mir_free(gt->stValueText);
 -					mir_free(gt->szFontID);
 -					mir_free(gt->szGlyphTextID);
 -					mir_free(gt);
 -				}
 -			}
 -		}
 -		List_Destroy(pObjectList->pTextList);
 -		mir_free_and_nil(pObjectList->pTextList);
 -	}
 -}
 -// Getting skin objects and masks from DB
 -static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin)
 -{
 -	if (Skin == NULL) return 0;
 -	ske_UnloadSkin(Skin);
 -	g_CluiData.fDisableSkinEngine = db_get_b(NULL,"ModernData","DisableEngine", SETTING_DISABLESKIN_DEFAULT);
 -	//window borders
 -	if (g_CluiData.fDisableSkinEngine) {
 -		g_CluiData.LeftClientMargin = 0;
 -		g_CluiData.RightClientMargin = 0;
 -		g_CluiData.TopClientMargin = 0;
 -		g_CluiData.BottomClientMargin = 0;
 -	} else {
 -		//window borders
 -		g_CluiData.LeftClientMargin = (int)db_get_b(NULL,"CLUI","LeftClientMargin",SETTING_LEFTCLIENTMARIGN_DEFAULT);
 -		g_CluiData.RightClientMargin = (int)db_get_b(NULL,"CLUI","RightClientMargin",SETTING_RIGHTCLIENTMARIGN_DEFAULT);
 -		g_CluiData.TopClientMargin = (int)db_get_b(NULL,"CLUI","TopClientMargin",SETTING_TOPCLIENTMARIGN_DEFAULT);
 -		g_CluiData.BottomClientMargin = (int)db_get_b(NULL,"CLUI","BottomClientMargin",SETTING_BOTTOMCLIENTMARIGN_DEFAULT);
 -	}
 -
 -	if (g_CluiData.fDisableSkinEngine) return 0;
 -
 -	Skin->pMaskList = (LISTMODERNMASK*)mir_alloc(sizeof(LISTMODERNMASK));
 -	memset(Skin->pMaskList, 0, sizeof(LISTMODERNMASK));
 -	Skin->szSkinPlace = db_get_tsa(NULL, SKIN, "SkinFolder");
 -	if (!Skin->szSkinPlace || (_tcschr(Skin->szSkinPlace, '%') && !db_get_b(NULL,SKIN,"Modified",0)))
 -	{
 -		BOOL bOnlyObjects = FALSE;
 -		if (Skin->szSkinPlace && _tcschr(Skin->szSkinPlace, '%'))
 -			bOnlyObjects = TRUE;
 -		mir_free(Skin->szSkinPlace);
 -		Skin->szSkinPlace = mir_tstrdup( _T("%Default%"));
 -		ske_LoadSkinFromResource( bOnlyObjects );
 -	}
 -	//Load objects
 -	{
 -		DBCONTACTENUMSETTINGS dbces;
 -		pCurrentSkin = Skin;
 -		dbces.pfnEnumProc = ske_enumdb_SkinObjectsProc;
 -		dbces.szModule = SKIN;
 -		dbces.ofsSettings = 0;
 -		CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces);
 -
 -		SortMaskList(pCurrentSkin->pMaskList);
 -		ske_LinkSkinObjects(pCurrentSkin);
 -	}
 -	//Load Masks
 -	return 0;
 -}
 -
 -//surrogate to be called from outside
 -void ske_LoadSkinFromDB(void)
 -{
 -	ske_GetSkinFromDB(SKIN,&g_SkinObjectList);
 -	g_CluiData.dwKeyColor = db_get_dw(NULL,"ModernSettings","KeyColor",(DWORD)SETTING_KEYCOLOR_DEFAULT);
 -}
 -
 -//
 -
 -static int ske_LoadSkinFromResource(BOOL bOnlyObjects)
 -{
 -	IniParser parser(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF", bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
 -	if (parser.CheckOK()) {
 -		ske_DeleteAllSettingInSection("ModernSkin");
 -		db_set_s(NULL, SKIN, "SkinFolder", "%Default%");
 -		db_set_s(NULL, SKIN, "SkinFile", "%Default%");
 -		parser.Parse(IniParser::WriteStrToDb, 0);
 -	}
 -	return 0;
 -}
 -
 -//Load data from ini file
 -int ske_LoadSkinFromIniFile(TCHAR *szFileName, BOOL bOnlyObjects)
 -{
 -	if (_tcschr(szFileName,_T('%')))
 -		return ske_LoadSkinFromResource( bOnlyObjects );
 -
 -	IniParser parser(szFileName, bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
 -	if (!parser.CheckOK())
 -		return 0;
 -
 -	ske_DeleteAllSettingInSection("ModernSkin");
 -
 -	TCHAR skinFolder[MAX_PATH], skinFile[MAX_PATH];
 -	IniParser::GetSkinFolder(szFileName, skinFolder);
 -	PathToRelativeT(szFileName, skinFile);
 -
 -	db_set_ts(NULL,SKIN,"SkinFolder", skinFolder);
 -	db_set_ts(NULL,SKIN,"SkinFile", skinFile);
 -
 -	parser.Parse(IniParser::WriteStrToDb, 1);
 -	return 0;
 -}
 -
 -static int ske_enumdb_SkinSectionDeletionProc (const char *szSetting,LPARAM lParam)
 -{
 -	if (szSetting == NULL)
 -		return 0;
 -
 -	nArrayLen++;
 -	pszSettingName = (char **)realloc(pszSettingName, nArrayLen*sizeof(char *));
 -	pszSettingName[nArrayLen-1] = _strdup(szSetting);
 -	return 0;
 -}
 -
 -static int ske_DeleteAllSettingInSection(char * SectionName)
 -{
 -	DBCONTACTENUMSETTINGS dbces;
 -	nArrayLen = 0;
 -	pszSettingName = NULL;
 -	dbces.pfnEnumProc = ske_enumdb_SkinSectionDeletionProc;
 -	dbces.szModule = SectionName;
 -	dbces.ofsSettings = 0;
 -
 -	CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces);
 -
 -	//delete all settings
 -	if (nArrayLen == 0)
 -		return 0;
 -
 -	for (int i=0; i < nArrayLen; i++) {
 -		db_unset(0, SectionName,pszSettingName[i]);
 -		free(pszSettingName[i]);
 -	}
 -	free(pszSettingName);
 -	pszSettingName = NULL;
 -	nArrayLen = 0;
 -	return 0;
 -}
 -
 -BOOL ske_TextOut(HDC hdc, int x, int y, LPCTSTR lpString, int nCount)
 -{
 -	SIZE sz;
 -	GetTextExtentPoint32(hdc, lpString, nCount, &sz);
 -	int ta = GetTextAlign(hdc);
 -
 -	RECT rc = { 0 };
 -	SetRect(&rc, x, y, x + sz.cx, y + sz.cy);
 -	ske_DrawText(hdc, lpString, nCount, &rc, DT_NOCLIP | DT_SINGLELINE | DT_LEFT);
 -	return 1;
 -}
 -
 -static INT_PTR ske_Service_AlphaTextOut(WPARAM wParam, LPARAM lParam)
 -{
 -	if (!wParam) return 0;
 -
 -	AlphaTextOutParams ap = *(AlphaTextOutParams*)wParam;
 -	return ske_AlphaTextOut(ap.hDC,ap.lpString,ap.nCount,ap.lpRect,ap.format,ap.ARGBcolor);
 -}
 -
 -static __inline void ske_SetMatrix( sbyte * matrix,
 -	sbyte a, sbyte b, sbyte c,
 -	sbyte d, sbyte e, sbyte f,
 -	sbyte g, sbyte h, sbyte i)
 -{
 -	matrix[0] = a;	matrix[1] = b;	matrix[2] = c;
 -	matrix[3] = d;	matrix[4] = e;	matrix[5] = f;
 -	matrix[6] = g;	matrix[7] = h;	matrix[8] = i;
 -}
 -
 -static void ske_SetTextEffect(BYTE EffectID, DWORD FirstColor, DWORD SecondColor)
 -{
 -	if (EffectID > MAXPREDEFINEDEFFECTS) return;
 -	if (EffectID == -1) meCurrentEffect.EffectID = -1;
 -	else {
 -		meCurrentEffect.EffectID = EffectID;
 -		meCurrentEffect.EffectMatrix = ModernEffectsEnum[EffectID];
 -		meCurrentEffect.EffectColor1 = FirstColor;
 -		meCurrentEffect.EffectColor2 = SecondColor;
 -	}
 -}
 -
 -bool ske_ResetTextEffect(HDC hdc)
 -{
 -	int idx = arEffectStack.getIndex((EFFECTSSTACKITEM*)&hdc);
 -	if (idx == -1)
 -		return false;
 -
 -	mir_free(arEffectStack[idx]);
 -	arEffectStack.remove(idx);
 -	return true;
 -}
 -
 -bool ske_SelectTextEffect(HDC hdc, BYTE EffectID, DWORD FirstColor, DWORD SecondColor)
 -{
 -	if (EffectID > MAXPREDEFINEDEFFECTS)
 -		return false;
 -
 -	if (EffectID == -1)
 -		return ske_ResetTextEffect(hdc);
 -
 -	EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc);
 -	if (effect == NULL) {
 -		effect = (EFFECTSSTACKITEM *)mir_alloc(sizeof(EFFECTSSTACKITEM));
 -		effect->hdc = hdc;
 -		arEffectStack.insert(effect);
 -	}
 -
 -	effect->EffectID = EffectID;
 -	effect->FirstColor = FirstColor;
 -	effect->SecondColor = SecondColor;
 -	return true;
 -}
 -
 -static bool ske_GetTextEffect(HDC hdc, MODERNEFFECT *modernEffect)
 -{
 -	if (!modernEffect)
 -		return false;
 -
 -	EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc);
 -	if (effect == NULL)
 -		return false;
 -
 -	modernEffect->EffectID = effect->EffectID;
 -	modernEffect->EffectColor1 = effect->FirstColor;
 -	modernEffect->EffectColor2 = effect->SecondColor;
 -	modernEffect->EffectMatrix = ModernEffectsEnum[effect->EffectID];
 -	return true;
 -}
 -
 -static bool ske_DrawTextEffect(BYTE* destPt, BYTE* maskPt, DWORD width, DWORD height, MODERNEFFECT *effect)
 -{
 -	sbyte *buf;
 -	sbyte *outbuf;
 -	sbyte *bufline, *buflineTop, *buflineMid;
 -	int sign = 0;
 -	BYTE *maskline,*destline;
 -	BYTE al,rl,gl,bl,ad,rd,gd,bd;
 -	int k = 0;
 -	DWORD x,y;
 -	sbyte *matrix;
 -	BYTE mcTopStart;
 -	BYTE mcBottomEnd;
 -	BYTE mcLeftStart;
 -	BYTE mcRightEnd;
 -	BYTE effectCount;
 -	int minX = width;
 -	int maxX = 0;
 -	int minY = height;
 -	int maxY = 0;
 -	if (effect->EffectID == 0xFF) return false;
 -	if (!width || !height) return false;
 -	if (!destPt) return false;
 -	buf = (sbyte*)malloc(width*height*sizeof(BYTE));
 -	{
 -		matrix = effect->EffectMatrix.matrix;
 -		mcTopStart = 2-effect->EffectMatrix.topEffect;
 -		mcBottomEnd = 3+effect->EffectMatrix.bottomEffect;
 -		mcLeftStart = 2-effect->EffectMatrix.leftEffect;
 -		mcRightEnd = 3+effect->EffectMatrix.rightEffect;
 -		effectCount = effect->EffectMatrix.cycleCount;
 -	}
 -	al = 255-((BYTE)(effect->EffectColor1>>24));
 -	rl = GetRValue(effect->EffectColor1);
 -	gl = GetGValue(effect->EffectColor1);
 -	bl = GetBValue(effect->EffectColor1);
 -	ad = 255-((BYTE)(effect->EffectColor2>>24));
 -	rd = GetRValue(effect->EffectColor2);
 -	gd = GetGValue(effect->EffectColor2);
 -	bd = GetBValue(effect->EffectColor2);
 -
 -	//Fill buffer by mid values of image
 -	for (y = 0; y < height; y++)
 -	{
 -		bufline = buf+y*width;
 -		maskline = maskPt+((y*width) << 2);
 -		for (x = 0; x < width; x++)
 -		{
 -			BYTE a = (sbyte)(DWORD)((maskline[0]+maskline[2]+maskline[1]+maskline[1])>>4);
 -			*bufline = a;
 -			if (a != 0)
 -			{
 -				minX = min((int)x,minX);
 -				minY = min((int)y,minY);
 -				maxX = max((int)x,maxX);
 -				maxY = max((int)y,maxY);
 -			}
 -			bufline++;
 -			maskline += 4;
 -		}
 -	}
 -	//Here perform effect on buffer and place results to outbuf
 -	for (k = 0; k < (effectCount&0x7F); k++)
 -	{
 -		minX = max( 0,         minX + mcLeftStart - 2 );
 -		minY = max( 0,         minY + mcTopStart  - 2 );
 -		maxX = min((int)width,  maxX + mcRightEnd  - 1 );
 -		maxY = min((int)height, maxY + mcBottomEnd - 1 );
 -
 -		outbuf = (sbyte*)malloc(width*height*sizeof(sbyte));
 -		memset(outbuf, 0, width*height*sizeof(sbyte));
 -		for (y = (DWORD)minY; y < (DWORD)maxY; y++)
 -		{
 -			int val;
 -			bufline = outbuf+y*width+minX;
 -			buflineMid = buf+y*width+minX;
 -			for (x = (DWORD)minX; x < (DWORD)maxX; x++)
 -			{
 -				int matrixHor,matrixVer;
 -				val = 0;
 -				for (matrixVer = mcTopStart; matrixVer < mcBottomEnd; matrixVer++)
 -				{
 -					int buflineStep = width*(matrixVer-2);
 -					int as = y+matrixVer-2;
 -					sbyte * buflineTopS = NULL;
 -					if (as >= 0 && (DWORD)as < height) buflineTopS = buflineMid+buflineStep;
 -
 -					for (matrixHor = mcLeftStart; matrixHor < mcRightEnd;matrixHor++)
 -					{
 -						buflineTop = buflineTopS;
 -						int a = x+matrixHor-2;
 -						if (buflineTop && a >= 0 && (DWORD)a < width) buflineTop += matrixHor-2;
 -						else buflineTop = NULL;
 -						if (buflineTop)
 -							val += ((*buflineTop)*matrix[matrixVer*5+matrixHor]);
 -					}
 -				}
 -				val = (val+1)>>5;
 -				*bufline = (sbyte)((val>127)?127:(val < -125)?-125:val);
 -				bufline++;
 -				buflineMid++;
 -			}
 -		}
 -		free(buf);
 -		buf = outbuf;
 -	}
 -	{
 -		BYTE r1,b1,g1,a1;
 -		b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1;
 -		//perform out to dest
 -		for (y = 0; y < height; y++)
 -		{
 -			bufline = buf+y*width;
 -			destline = destPt+((y*width) << 2);
 -			for (x = 0; x < width; x++)
 -			{
 -				sbyte val = *bufline;
 -				BYTE absVal = ((val < 0)?-val:val);
 -
 -				if (val != 0)
 -				{
 -					if (val>0 && sign < 0)
 -					{ b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1;}
 -					else if (val < 0 && sign>0)
 -					{ b1 = bd; r1 = rd; g1 = gd; a1 = ad; sign = -1;}
 -
 -					absVal = absVal*a1/255;
 -
 -					destline[0] = ((destline[0]*(128-absVal))+absVal*b1)>>7;
 -					destline[1] = ((destline[1]*(128-absVal))+absVal*g1)>>7;
 -					destline[2] = ((destline[2]*(128-absVal))+absVal*r1)>>7;
 -					destline[3] += ((255-destline[3])*(a1*absVal))/32640;
 -				}
 -				bufline++;
 -				destline += 4;
 -			}
 -		}
 -		free(buf);
 -	}
 -	return false;
 -}
 -
 -static int ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor)
 -{
 -	if (!(lpString && lpRect))
 -		return 0;
 -
 -	// Step first fill fast calc correction tables:
 -	static bool _tables_empty = true;
 -	static BYTE gammaTbl[256];			// Gamma correction table
 -	static WORD blueMulTbl[256];		// blue  coefficient multiplication table
 -	static WORD greenMulTbl[256];		// green coefficient multiplication table
 -	static WORD redMulTbl[256];			// red   coefficient multiplication table
 -	if ( _tables_empty )
 -	{
 -		// fill tables
 -		double gammaCfPw = 1000 / (double)DBGetContactSettingRangedWord(NULL,"ModernData","AlphaTextOutGamma", 700, 1, 5000 );
 -		BYTE blueCf    = db_get_b(NULL,"ModernData","AlphaTextOutBlueCorrection", 28 );
 -		BYTE redCf     = db_get_b(NULL,"ModernData","AlphaTextOutRed Correction", 77 );
 -		BYTE greenCf   = db_get_b(NULL,"ModernData","AlphaTextOutGreen Correction", 151 );
 -
 -		for ( int i=0; i < 256; i++ ) {
 -			gammaTbl[i] = (BYTE)( 255 * pow((double)i / 255, gammaCfPw ));
 -			blueMulTbl[i] = i * blueCf;
 -			redMulTbl[i] = i * redCf;
 -			greenMulTbl[i] = i * greenCf;
 -		}
 -	}
 -
 -	// Calc len of input string
 -	if (nCount == -1)
 -		nCount = lstrlen(lpString);
 -
 -	// retrieve destination bitmap bits
 -	HBITMAP hDestBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
 -	BITMAP  bmpDest;
 -	GetObject(hDestBitmap, sizeof(BITMAP), &bmpDest);
 -
 -	BOOL destHasNotDIB = FALSE;
 -	BYTE *pDestBits = NULL;
 -	if (bmpDest.bmBits == NULL) {
 -		destHasNotDIB = TRUE;
 -		pDestBits = (BYTE*) malloc ( bmpDest.bmHeight * bmpDest.bmWidthBytes );
 -		GetBitmapBits( hDestBitmap, bmpDest.bmHeight*bmpDest.bmWidthBytes, pDestBits );
 -	}
 -	else pDestBits = (BYTE*)bmpDest.bmBits;
 -
 -	BOOL isDest16bit = (bmpDest.bmBitsPixel) != 32;
 -
 -	// Creating offscreen buffer
 -	HDC hOffscreenDC = CreateCompatibleDC(hDC);
 -
 -	// Font to be used to draw text
 -	HFONT hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT);
 -	HFONT hOldOffscreenFont = (HFONT)SelectObject(hOffscreenDC, hFont);
 -
 -	// Calculating text geometric size
 -	RECT workRect = *lpRect;
 -	int workRectWidth = workRect.right - workRect.left;
 -	int workRectHeight = workRect.bottom - workRect.top;
 -	if (workRectWidth <= 0 || workRectHeight <= 0)
 -		return 0;
 -
 -	SIZE textSize;
 -	GetTextExtentPoint32( hOffscreenDC, lpString, nCount, &textSize );
 -
 -	LPCTSTR lpWorkString = lpString;
 -	BOOL bNeedFreeWorkString = FALSE;
 -
 -	// if we need to cut the text with ellipsis
 -	if ((format & DT_END_ELLIPSIS) && textSize.cx > workRectWidth) {
 -		// Calc geometric width of ellipsis
 -		SIZE szEllipsis;
 -		GetTextExtentPoint32A(hOffscreenDC,"...",3,&szEllipsis);
 -		szEllipsis.cx++;                                          // CORRECTION: some width correction
 -
 -		// Calc count of visible chars
 -		int visibleCharCount = nCount;
 -		if (workRectWidth > szEllipsis.cx)
 -			GetTextExtentExPoint(hOffscreenDC, lpString, nCount, workRectWidth - szEllipsis.cx, &visibleCharCount, NULL, &textSize);
 -		else
 -			GetTextExtentExPoint(hOffscreenDC, lpString, nCount, 0, &visibleCharCount, NULL, &textSize);
 -
 -		// replace end of string by elipsis
 -		bNeedFreeWorkString = TRUE;
 -		lpWorkString = (TCHAR*) malloc(( visibleCharCount + 4) * sizeof(TCHAR));
 -
 -		memcpy((void*) lpWorkString, lpString, visibleCharCount * sizeof(TCHAR));
 -		memcpy((void*) ( lpWorkString + visibleCharCount ), _T("..."), 4 * sizeof(TCHAR)); // 3 + 1
 -
 -		nCount = visibleCharCount + 3;
 -	}
 -
 -	// Calc sizes and offsets
 -
 -	textSize.cx += 2;             // CORRECTION: for italic
 -
 -	int drx = 0;                  // x-axis offset of draw point
 -
 -	if (workRectWidth > textSize.cx) {
 -		if ( format & ( DT_RIGHT | DT_RTLREADING ))
 -			drx = workRectWidth - textSize.cx;
 -		else if ( format & DT_CENTER )
 -			drx = ( workRectWidth - textSize.cx ) >> 1;
 -	}
 -	else textSize.cx = workRectWidth;
 -
 -	int dry = 0;                  // y-axis offset of draw point
 -
 -	if (workRectHeight > textSize.cy) {
 -		if (format & DT_BOTTOM)
 -			dry = workRectHeight - textSize.cy;
 -		else if (format & DT_VCENTER)
 -			dry = (workRectHeight - textSize.cy) >> 1;
 -	}
 -	else textSize.cy = workRectHeight;
 -
 -	textSize.cx += 4;    // CORRECTION: for effects ???
 -	textSize.cy += 4;	 // CORRECTION: for effects ???
 -
 -	if (textSize.cx > 0 && textSize.cy > 0) { // Ok we need to paint
 -		// probably here are mess ofscreen and temp buff dc
 -
 -		//Create bitmap image for offscreen
 -		BYTE *bits = NULL;
 -		HBITMAP hbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bits);
 -		if (bits != NULL) {
 -			HBITMAP holdbmp = (HBITMAP)SelectObject( hOffscreenDC, hbmp );
 -
 -			//Create buffer bitmap image for temp text
 -			BYTE *bufbits = NULL;
 -			HBITMAP bufbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bufbits);
 -			if ( bufbits != NULL ) {
 -				HDC     bufDC = CreateCompatibleDC(hDC);
 -				HBITMAP bufoldbmp = (HBITMAP)SelectObject(bufDC, bufbmp);
 -				HFONT   hOldBufFont = (HFONT)SelectObject(bufDC, hFont);
 -				SetBkColor(bufDC, RGB(0, 0, 0));
 -				SetTextColor(bufDC, RGB(255, 255, 255));
 -
 -				// Copy from destination to temp buffer
 -				BitBlt(hOffscreenDC, 0, 0, textSize.cx, textSize.cy, hDC, workRect.left + drx - 2, workRect.top + dry - 2, SRCCOPY);
 -
 -				//Draw text on offscreen bitmap
 -				TextOut(bufDC, 2, 2, lpWorkString, nCount);
 -
 -				MODERNEFFECT effect;
 -				if (ske_GetTextEffect(hDC, &effect))
 -					ske_DrawTextEffect(bits, bufbits, textSize.cx, textSize.cy, &effect);
 -
 -				// RenderText
 -				RECT drawRect;
 -				drawRect.left = 0; drawRect.top = 0;
 -				drawRect.right = textSize.cx;
 -				drawRect.bottom = textSize.cy;
 -
 -				DWORD width = textSize.cx;
 -				DWORD heigh = textSize.cy;
 -
 -				BYTE *pDestScanLine;
 -				BYTE *pBufScanLine;
 -				BYTE *pix;
 -				BYTE *bufpix;
 -
 -				BYTE al = 255 - ((BYTE)( ARGBcolor >> 24 ));
 -				BYTE r = GetRValue( ARGBcolor );
 -				BYTE g = GetGValue( ARGBcolor );
 -				BYTE b = GetBValue( ARGBcolor );
 -
 -				for (DWORD y = 2; y < heigh - 2; y++) {
 -					int lineBytes = y * (width << 2);
 -
 -					pDestScanLine = bits + lineBytes;
 -					pBufScanLine  = bufbits + lineBytes;
 -
 -					for (DWORD x = 2; x < width - 2; x++) {
 -						pix    = pDestScanLine + ( x << 2 );
 -						bufpix = pBufScanLine  + ( x << 2 );
 -
 -						// Monochromatic
 -						BYTE bx = gammaTbl[ bufpix[0] ];
 -						BYTE gx = gammaTbl[ bufpix[1] ];
 -						BYTE rx = gammaTbl[ bufpix[2] ];
 -
 -						if ( al != 255 ) {
 -							bx *= al/255;
 -							gx *= al/255;
 -							rx *= al/255;
 -						}
 -
 -						BYTE ax = (BYTE)(( (DWORD)rx*77 + (DWORD)gx * 151 + (DWORD)bx *28 + 128 ) / 256 );
 -						if (ax) {
 -							//Normalize components to gray
 -							BYTE axx = 255 - (( r + g + b ) >> 2 ) ; // Coefficient of grayance, more white font - more gray edges
 -							WORD atx = ax * (255 - axx);
 -							bx = ( atx + bx * axx )/255;
 -							gx = ( atx + gx * axx )/255;
 -							rx = ( atx + rx * axx )/255;
 -
 -							short brx = (short)((b - pix[0])*bx / 255);
 -							short grx = (short)((g - pix[1])*gx / 255);
 -							short rrx = (short)((r - pix[2])*rx / 255);
 -
 -							pix[0] += brx;
 -							pix[1] += grx;
 -							pix[2] += rrx;
 -							pix[3] = (BYTE)(ax+(BYTE)(255-ax)*pix[3]/255);
 -						}
 -					}
 -				}
 -
 -				// Blit to destination
 -				BitBlt(hDC, workRect.left + drx - 2, workRect.top + dry - 2, textSize.cx, textSize.cy, hOffscreenDC, 0, 0, SRCCOPY);
 -
 -				//free resources
 -				SelectObject(bufDC, bufoldbmp);
 -				DeleteObject(bufbmp);
 -				SelectObject(bufDC, hOldBufFont);
 -				DeleteDC(bufDC);
 -			}
 -			SelectObject(hOffscreenDC, holdbmp);
 -			DeleteObject(hbmp);
 -		}
 -	}
 -
 -	// Final cleanup
 -	SelectObject(hOffscreenDC, hOldOffscreenFont);
 -	DeleteDC(hOffscreenDC);
 -
 -	if (destHasNotDIB)
 -		free(pDestBits);
 -
 -	if (bNeedFreeWorkString)
 -		free((void*)lpWorkString);
 -
 -	return 0;
 -}
 -
 -static int ske_DrawTextWithEffectWorker( HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, MODERNFONTEFFECT * effect )
 -{
 -	if (format & DT_CALCRECT)
 -		return DrawText(hdc, lpString, nCount, lpRect, format);
 -
 -	if (format & DT_RTLREADING)
 -		SetTextAlign(hdc, TA_RTLREADING);
 -
 -	DWORD color = GetTextColor(hdc);
 -	RECT r = *lpRect;
 -	OffsetRect(&r, 1, 1);
 -	DWORD form = format;
 -	if (effect && effect->effectIndex)
 -		ske_SelectTextEffect(hdc, effect->effectIndex - 1, effect->baseColour, effect->secondaryColour);
 -
 -	int res = ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color);
 -
 -	if (effect && effect->effectIndex)
 -		ske_ResetTextEffect(hdc);
 -
 -	return res;
 -}
 -
 -INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam)
 -{
 -	DrawTextWithEffectParam *p = (DrawTextWithEffectParam *)wParam;
 -	if (p->cbSize != sizeof(DrawTextWithEffectParam))
 -		return FALSE;
 -	return ske_DrawTextWithEffectWorker(p->hdc, p->lpchText, p->cchText, p->lprc, p->dwDTFormat, p->pEffect);
 -}
 -
 -BOOL ske_DrawText(HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format)
 -{
 -	DWORD form = 0, color = 0;
 -	RECT r = *lpRect;
 -	OffsetRect(&r, 1, 1);
 -	if (format & DT_RTLREADING) SetTextAlign(hdc, TA_RTLREADING);
 -	if (format & DT_CALCRECT) return DrawText(hdc, lpString, nCount, lpRect, format);
 -	if (format & DT_FORCENATIVERENDER || g_CluiData.fDisableSkinEngine)
 -		return DrawText(hdc, lpString, nCount, lpRect, format&~DT_FORCENATIVERENDER);
 -
 -	form = format;
 -	color = GetTextColor(hdc);
 -	return ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color);
 -}
 -
 -HICON ske_ImageList_GetIcon(HIMAGELIST himl, int i, UINT fStyle)
 -{
 -	IMAGEINFO imi = {0};
 -	BITMAP bm = {0};
 -	if (i != -1) {
 -		ImageList_GetImageInfo(himl,i,&imi);
 -		GetObject(imi.hbmImage,sizeof(bm),&bm);
 -		if (bm.bmBitsPixel == 32) //stupid bug of Microsoft
 -			// Icons bitmaps are not premultiplied
 -			// So Imagelist_AddIcon - premultiply alpha
 -			// But incorrect - it is possible that alpha will
 -			// be less than color and
 -			// ImageList_GetIcon will return overflowed colors
 -			// TODO: Direct draw Icon from imagelist without
 -			// extracting of icon
 -		{
 -			BYTE *bits = (BYTE*)bm.bmBits;
 -			if (!bits) {
 -				bits = (BYTE*)malloc(bm.bmWidthBytes*bm.bmHeight);
 -				GetBitmapBits(imi.hbmImage,bm.bmWidthBytes*bm.bmHeight,bits);
 -			}
 -
 -			int wb = ((imi.rcImage.right - imi.rcImage.left)*bm.bmBitsPixel >> 3);
 -			BYTE *bcbits = bits + (bm.bmHeight - imi.rcImage.bottom)*bm.bmWidthBytes + (imi.rcImage.left*bm.bmBitsPixel >> 3);
 -			for (int iy = 0; iy < imi.rcImage.bottom - imi.rcImage.top; iy++) {
 -				int x;
 -				// Dummy microsoft fix - alpha can be less than r,g or b
 -				// Looks like color channels in icons should be non-premultiplied with alpha
 -				// But AddIcon store it premultiplied (incorrectly cause can be Alpha == 7F, but R,G or B == 80
 -				// So i check that alpha is 0x7F and set it to 0x80
 -				DWORD *c = ((DWORD*)bcbits);
 -				for (x = 0; x < imi.rcImage.right - imi.rcImage.left; x++) {
 -					DWORD val = *c;
 -					BYTE a = (BYTE)((val) >> 24);
 -					if (a != 0) {
 -						BYTE r = (BYTE)((val & 0xFF0000) >> 16);
 -						BYTE g = (BYTE)((val & 0xFF00) >> 8);
 -						BYTE b = (BYTE)(val & 0xFF);
 -						if (a < r || a < g || a < b)
 -						{
 -							a = max(max(r, g), b);
 -							val = a << 24 | r << 16 | g << 8 | b;
 -							*c = val;
 -						}
 -					}
 -					c++;
 -				}
 -				bcbits += bm.bmWidthBytes;
 -			}
 -
 -			if (!bm.bmBits) {
 -				SetBitmapBits(imi.hbmImage, bm.bmWidthBytes*bm.bmHeight, bits);
 -				free(bits);
 -			}
 -		}
 -	}
 -	return ImageList_GetIcon(himl,i,ILD_NORMAL);
 -}
 -
 -////////////////////////////////////////////////////////////////////////////
 -// This creates new dib image from Imagelist icon ready to alphablend it
 -
 -HBITMAP ske_ExtractDIBFromImagelistIcon( HIMAGELIST himl,int index, int * outWidth, int * outHeight)
 -{
 -	return NULL;
 -}
 -
 -BOOL ske_ImageList_DrawEx( HIMAGELIST himl,int i,HDC hdcDst,int x,int y,int dx,int dy,COLORREF rgbBk,COLORREF rgbFg,UINT fStyle)
 -{
 -	//the routine to directly draw icon from image list without creating icon from there - should be some faster
 -	if (i < 0)
 -		return FALSE;
 -
 -	if (g_CluiData.fDisableSkinEngine)
 -		return ImageList_DrawEx(himl, i, hdcDst, x, y, dx, dy, rgbBk, rgbFg, fStyle);
 -
 -	BYTE alpha;
 -	if (fStyle&ILD_BLEND25) alpha = 64;
 -	else if (fStyle&ILD_BLEND50) alpha = 128;
 -	else alpha = 255;
 -
 -	HICON hIcon = ske_ImageList_GetIcon(himl, i, ILD_NORMAL);
 -	if (hIcon == NULL)
 -		return FALSE;
 -
 -	ske_DrawIconEx(hdcDst, x, y, hIcon, dx ? dx : GetSystemMetrics(SM_CXSMICON), dy ? dy : GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | (alpha << 24));
 -	DestroyIcon(hIcon);
 -	return TRUE;
 -}
 -
 -static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, LPARAM lParam)
 -{
 -	DrawIconFixParam *p = (DrawIconFixParam*)wParam;
 -	if (!p)
 -		return 0;
 -
 -	return ske_DrawIconEx(p->hdc,p->xLeft,p->yTop,p->hIcon,p->cxWidth,p->cyWidth,p->istepIfAniCur,p->hbrFlickerFreeDraw,p->diFlags);
 -}
 -
 -
 -BOOL ske_DrawIconEx(HDC hdcDst,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags)
 -{
 -	ICONINFO ici;
 -	BYTE alpha = (BYTE)((diFlags&0xFF000000)>>24);
 -
 -
 -	HDC imDC;
 -	HBITMAP oldBmp, imBmp,tBmp;
 -	BITMAP imbt,immaskbt;
 -	BYTE * imbits;
 -	BYTE * imimagbits;
 -	BYTE * immaskbits;
 -	DWORD cx,cy,icy;
 -	BYTE *t1, *t2, *t3;
 -
 -	BOOL NoDIBImage = FALSE;
 -	//lockimagelist
 -	BYTE hasmask = FALSE;
 -	BYTE no32bit = FALSE;
 -	BYTE noMirrorMask = FALSE;
 -	BYTE hasalpha = FALSE;
 -	alpha = alpha?alpha:255;
 -
 -	if ( g_CluiData.fDisableSkinEngine && !(diFlags&0x80))
 -		return DrawIconEx(hdcDst,xLeft,yTop,hIcon,cxWidth,cyWidth,istepIfAniCur,hbrFlickerFreeDraw,diFlags&0xFFFF7F);
 -
 -	if (!GetIconInfo(hIcon, &ici))
 -		return 0;
 -
 -	GetObject(ici.hbmColor,sizeof(BITMAP),&imbt);
 -	if (imbt.bmWidth*imbt.bmHeight == 0) {
 -		DeleteObject(ici.hbmColor);
 -		DeleteObject(ici.hbmMask);
 -		return 0;
 -	}
 -	GetObject(ici.hbmMask,sizeof(BITMAP),&immaskbt);
 -	cy = imbt.bmHeight;
 -
 -	if (imbt.bmBitsPixel != 32) {
 -		HBITMAP otBmp;
 -		no32bit = TRUE;
 -		HDC tempDC1 = CreateCompatibleDC(hdcDst);
 -		tBmp = ske_CreateDIB32(imbt.bmWidth, imbt.bmHeight);
 -		if (tBmp) {
 -			GetObject(tBmp, sizeof(BITMAP), &imbt);
 -			otBmp = (HBITMAP)SelectObject(tempDC1, tBmp);
 -			DrawIconEx(tempDC1, 0, 0, hIcon, imbt.bmWidth, imbt.bmHeight, istepIfAniCur, hbrFlickerFreeDraw, DI_IMAGE);
 -			noMirrorMask = TRUE;
 -
 -		}
 -		SelectObject(tempDC1, otBmp);
 -		DeleteDC(tempDC1);
 -	}
 -
 -	if (imbt.bmBits == NULL) {
 -		NoDIBImage = TRUE;
 -		imimagbits = (BYTE*)malloc(cy*imbt.bmWidthBytes);
 -		GetBitmapBits(ici.hbmColor, cy*imbt.bmWidthBytes, (void*)imimagbits);
 -	}
 -	else imimagbits = (BYTE*)imbt.bmBits;
 -
 -	if (immaskbt.bmBits == NULL) {
 -		immaskbits = (BYTE*)malloc(cy*immaskbt.bmWidthBytes);
 -		GetBitmapBits(ici.hbmMask, cy*immaskbt.bmWidthBytes, (void*)immaskbits);
 -	}
 -	else immaskbits = (BYTE*)immaskbt.bmBits;
 -
 -	icy = imbt.bmHeight;
 -	cx = imbt.bmWidth;
 -	imDC = CreateCompatibleDC(hdcDst);
 -	imBmp = ske_CreateDIB32Point(cx, icy, (void**)&imbits);
 -	oldBmp = (HBITMAP)SelectObject(imDC, imBmp);
 -	if (imbits != NULL && imimagbits != NULL && immaskbits != NULL) {
 -		int x; int y;
 -		int bottom, right, top, h;
 -		int mwb, mwb2;
 -		mwb = immaskbt.bmWidthBytes;
 -		mwb2 = imbt.bmWidthBytes;
 -		bottom = icy;
 -		right = cx;
 -		top = 0;
 -		h = icy;
 -		for (y = top; (y < bottom) && !hasmask; y++) {
 -			t1 = immaskbits + y*mwb;
 -			for (x = 0; (x < mwb) && !hasmask; x++)
 -				hasmask |= (*(t1 + x) != 0);
 -		}
 -
 -		for (y = top; (y < bottom) && !hasalpha; y++) {
 -			t1 = imimagbits + (cy - y - 1)*mwb2;
 -			for (x = 0; (x < right) && !hasalpha; x++)
 -				hasalpha |= (*(t1+(x << 2)+3) != 0);
 -		}
 -
 -		for (y = 0; y < (int)icy; y++) {
 -			t1 = imimagbits+(h-y-1-top)*mwb2;
 -			t2 = imbits+(!no32bit?y:(icy-y-1))*mwb2;
 -			t3 = immaskbits+(noMirrorMask?y:(h-y-1-top))*mwb;
 -			for (x = 0; x < right; x++) {
 -				BYTE mask = 0;
 -				BYTE a = 0;
 -				DWORD *src = (DWORD*)(t1 + (x << 2));
 -				DWORD *dest = (DWORD*)(t2 + (x << 2));
 -				if (hasalpha && !hasmask)
 -					a = ((BYTE*)src)[3];
 -				else {
 -					mask = ((1 << (7 - x % 8))&(*(t3 + (x >> 3)))) != 0;
 -					if (mask) {
 -						if (!hasalpha) {
 -							*dest = 0;
 -							continue;
 -						}
 -
 -						if (((BYTE*)src)[3]>0 )
 -							a = ((BYTE*)src)[3];
 -						else
 -						    a = 0;
 -					}
 -					else if (hasalpha || hasmask)
 -						a = (((BYTE*)src)[3]>0?((BYTE*)src)[3]:255);
 -					else if (!hasalpha && !hasmask)
 -						a = 255;
 -					else {  *dest = 0; continue; }
 -				}
 -				if (a > 0) {
 -					((BYTE*)dest)[3] = a;
 -					((BYTE*)dest)[0] = ((BYTE*)src)[0] * a / 255;
 -					((BYTE*)dest)[1] = ((BYTE*)src)[1] * a / 255;
 -					((BYTE*)dest)[2] = ((BYTE*)src)[2] * a / 255;
 -				}
 -				else *dest = 0;
 -			}
 -		}
 -	}
 -
 -	BLENDFUNCTION bf = { AC_SRC_OVER, diFlags & 128, alpha, AC_SRC_ALPHA };
 -	ske_AlphaBlend(hdcDst, xLeft, yTop, cxWidth, cyWidth, imDC, 0, 0, cx, icy, bf);
 -
 -	if (immaskbt.bmBits == NULL) free(immaskbits);
 -	if (imbt.bmBits == NULL) free(imimagbits);
 -	SelectObject(imDC, oldBmp);
 -	DeleteObject(imBmp);
 -	if (no32bit)DeleteObject(tBmp);
 -	DeleteObject(ici.hbmColor);
 -	DeleteObject(ici.hbmMask);
 -	SelectObject(imDC, GetStockObject(DEFAULT_GUI_FONT));
 -	DeleteDC(imDC);
 -	return 1;
 -}
 -
 -int ske_PrepareImageButDontUpdateIt(RECT *r)
 -{
 -	if (!g_CluiData.fLayered)
 -		return ske_ReCreateBackImage(FALSE, r);
 -
 -	mutex_bLockUpdate = 1;
 -	ske_DrawNonFramedObjects(TRUE, r);
 -	ske_ValidateFrameImageProc(r);
 -	mutex_bLockUpdate = 0;
 -	return 0;
 -}
 -
 -int ske_RedrawCompleteWindow()
 -{
 -	if (g_CluiData.fLayered) {
 -		ske_DrawNonFramedObjects(TRUE,0);
 -		CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, 0, 0);
 -	}
 -	else RedrawWindow(pcli->hwndContactList,NULL,NULL,RDW_ALLCHILDREN|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME);
 -
 -	return 0;
 -}
 -
 -// Request to repaint frame or change/drop callback data
 -// wParam = hWnd of called frame
 -// lParam = pointer to sPaintRequest (or NULL to redraw all)
 -// return 2 - already queued, data updated, 1-have been queued, 0 - failure
 -
 -static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam)           // Immideately recall paint routines for frame and refresh image
 -{
 -	if ( MirandaLoading())
 -		return 0;
 -
 -	RECT wnd;
 -	FRAMEWND *frm;
 -	BOOL NoCancelPost = 0;
 -	BOOL IsAnyQueued = 0;
 -	if (!g_CluiData.mutexOnEdgeSizing)
 -		GetWindowRect(pcli->hwndContactList,&wnd);
 -	else
 -		wnd = g_rcEdgeSizingRect;
 -
 -	if (!g_CluiData.fLayered) {
 -		RedrawWindow((HWND)wParam,NULL,NULL,RDW_UPDATENOW|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME);
 -		return 0;
 -	}
 -
 -	if (g_pCachedWindow == NULL) ske_ValidateFrameImageProc(&wnd);
 -	else if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) ske_ValidateFrameImageProc(&wnd);
 -	else if (wParam == 0) ske_ValidateFrameImageProc(&wnd);
 -	else { // all Ok Update Single Frame
 -		// TO BE LOCKED OR PROXIED
 -		frm = FindFrameByItsHWND((HWND)wParam);
 -		if (!frm)
 -			ske_ValidateFrameImageProc(&wnd);
 -		// Validate frame, update window image and remove it from queue
 -		else {
 -			if (frm->UpdateRgn) {
 -				DeleteObject(frm->UpdateRgn);
 -				frm->UpdateRgn = 0;
 -			}
 -			ske_ValidateSingleFrameImage(frm, 0);
 -			ske_UpdateWindowImage();
 -			NoCancelPost = 1;
 -			//-- Remove frame from queue
 -			if (flag_bUpdateQueued) {
 -				frm->bQueued = 0;
 -				for (int i = 0; i < g_nFramesCount; i++)
 -					if (IsAnyQueued |= g_pfwFrames[i].bQueued)
 -						break;
 -			}
 -		}
 -	}
 -
 -	if ((!NoCancelPost || !IsAnyQueued) && flag_bUpdateQueued) { // no any queued updating cancel post or need to cancel post
 -		flag_bUpdateQueued = 0;
 -		g_flag_bPostWasCanceled = 1;
 -	}
 -	return 1;
 -}
 -static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam)       // Post request for updating
 -{
 -	if (MirandaLoading()) return 0;
 -
 -	if (wParam) {
 -		FRAMEWND *frm = FindFrameByItsHWND((HWND)wParam);
 -		sPaintRequest *pr = (sPaintRequest*)lParam;
 -		if (!g_CluiData.fLayered || (frm && frm->floating))
 -			return InvalidateRect((HWND)wParam, pr ? (RECT*)&(pr->rcUpdate) : NULL, FALSE);
 -
 -		if (frm) {
 -			if (frm->PaintCallbackProc != NULL) {
 -				frm->PaintData = (sPaintRequest *)pr;
 -				frm->bQueued = 1;
 -				if (pr) {
 -					HRGN r2;
 -					if (!IsRectEmpty(&pr->rcUpdate)) {
 -						RECT rcClient;
 -						RECT rcUpdate;
 -						GetClientRect(frm->hWnd, &rcClient);
 -						IntersectRect(&rcUpdate, &rcClient, &pr->rcUpdate);
 -						if (IsRectEmpty(&rcUpdate))
 -							return 0;
 -						r2 = CreateRectRgn(rcUpdate.left, rcUpdate.top, rcUpdate.right, rcUpdate.bottom);
 -					}
 -					else {
 -						RECT r;
 -						GetClientRect(frm->hWnd, &r);
 -						r2 = CreateRectRgn(r.left, r.top, r.right, r.bottom);
 -					}
 -
 -					if (!frm->UpdateRgn) {
 -						frm->UpdateRgn = CreateRectRgn(0, 0, 1, 1);
 -						CombineRgn(frm->UpdateRgn, r2, 0, RGN_COPY);
 -					}
 -					else CombineRgn(frm->UpdateRgn, frm->UpdateRgn, r2, RGN_OR);
 -					DeleteObject(r2);
 -				}
 -			}
 -		}
 -		else Sync(QueueAllFramesUpdating, 1);
 -	}
 -	else Sync(QueueAllFramesUpdating, 1);
 -
 -	if (!flag_bUpdateQueued || g_flag_bPostWasCanceled)
 -	if (PostMessage(pcli->hwndContactList, UM_UPDATE, 0, 0)) {
 -		flag_bUpdateQueued = 1;
 -		g_flag_bPostWasCanceled = 0;
 -	}
 -	return 1;
 -}
 -
 -static int ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting)                              // Calling frame paint proc
 -{
 -	if (!g_pCachedWindow) { TRACE("ske_ValidateSingleFrameImage calling without cached\n"); return 0;}
 -	if (Frame->hWnd == (HWND)-1 && !Frame->PaintCallbackProc)  { TRACE("ske_ValidateSingleFrameImage calling without FrameProc\n"); return 0;}
 -
 -	// if ok update image
 -	HDC hdc;
 -	HBITMAP o,n;
 -	RECT rcPaint,wnd;
 -	RECT ru = {0};
 -	int w,h,x,y;
 -	int w1,h1,x1,y1;
 -
 -	CLUI_SizingGetWindowRect(pcli->hwndContactList,&wnd);
 -	rcPaint = Frame->wndSize;
 -	{
 -		int dx,dy,bx,by;
 -		if (g_CluiData.mutexOnEdgeSizing)
 -		{
 -			dx = rcPaint.left-wnd.left;
 -			dy = rcPaint.top-wnd.top;
 -			bx = rcPaint.right-wnd.right;
 -			by = rcPaint.bottom-wnd.bottom;
 -			wnd = g_rcEdgeSizingRect;
 -			rcPaint.left = wnd.left+dx;
 -			rcPaint.top = wnd.top+dy;
 -			rcPaint.right = wnd.right+bx;
 -			rcPaint.bottom = wnd.bottom+by;
 -		}
 -	}
 -	//OffsetRect(&rcPaint,-wnd.left,-wnd.top);
 -	w = rcPaint.right-rcPaint.left;
 -	h = rcPaint.bottom-rcPaint.top;
 -	if (w <= 0 || h <= 0)
 -	{
 -		TRACE("Frame size smaller than 0\n");
 -		return 0;
 -	}
 -	x = rcPaint.left;
 -	y = rcPaint.top;
 -	hdc = CreateCompatibleDC(g_pCachedWindow->hImageDC);
 -	n = ske_CreateDIB32(w,h);
 -	o = (HBITMAP)SelectObject(hdc,n);
 -	{
 -		if (Frame->UpdateRgn && !SkipBkgBlitting)
 -		{
 -			GetRgnBox(Frame->UpdateRgn,&ru);
 -			{
 -				RECT rc;
 -				GetClientRect(Frame->hWnd,&rc);
 -				if (ru.top < 0) ru.top = 0;
 -				if (ru.left < 0) ru.left = 0;
 -				if (ru.right>rc.right) ru.right = rc.right;
 -				if (ru.bottom>rc.bottom) ru.bottom = rc.bottom;
 -			}
 -			if (!IsRectEmpty(&ru))
 -			{
 -				x1 = ru.left;
 -				y1 = ru.top;
 -				w1 = ru.right-ru.left;
 -				h1 = ru.bottom-ru.top;
 -			}
 -			else
 -			{x1 = 0; y1 = 0; w1 = w; h1 = h;}
 -			// copy image at hdc
 -			if (SkipBkgBlitting)  //image already at foreground
 -			{
 -				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY);
 -			}
 -			else
 -			{
 -				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY);
 -			}
 -			Frame->PaintCallbackProc(Frame->hWnd,hdc,&ru,Frame->UpdateRgn, Frame->dwFlags,Frame->PaintData);
 -		}
 -		else
 -		{
 -			   HRGN rgnUpdate;
 -			RECT r;
 -			GetClientRect(Frame->hWnd,&r);
 -			rgnUpdate = CreateRectRgn(r.left,r.top,r.right,r.bottom);
 -			ru = r;
 -			if (!IsRectEmpty(&ru))
 -			{
 -				x1 = ru.left;
 -				y1 = ru.top;
 -				w1 = ru.right-ru.left;
 -				h1 = ru.bottom-ru.top;
 -			}
 -			else
 -			{x1 = 0; y1 = 0; w1 = w; h1 = h;}
 -			// copy image at hdc
 -			if (SkipBkgBlitting)  //image already at foreground
 -			{
 -				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY);
 -			}
 -			else
 -			{
 -				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY);
 -			}
 -			Frame->PaintCallbackProc(Frame->hWnd,hdc,&r,rgnUpdate, Frame->dwFlags,Frame->PaintData);
 -			ru = r;
 -			   DeleteObject(rgnUpdate);
 -		}
 -		DeleteObject(Frame->UpdateRgn);
 -		Frame->UpdateRgn = 0;
 -	}
 -	if (!IsRectEmpty(&ru))
 -	{
 -		x1 = ru.left;
 -		y1 = ru.top;
 -		w1 = ru.right-ru.left;
 -		h1 = ru.bottom-ru.top;
 -	}
 -	else {
 -		x1 = 0; y1 = 0; w1 = w; h1 = h;
 -	}
 -
 -	BitBlt(g_pCachedWindow->hImageDC,x+x1,y+y1,w1,h1,hdc,x1,y1,SRCCOPY);
 -
 -	if (GetWindowLongPtr(Frame->hWnd, GWL_STYLE) & WS_VSCROLL) {
 -		//Draw vertical scroll bar
 -		//
 -		SCROLLBARINFO si = {0};
 -		si.cbSize = sizeof(SCROLLBARINFO);
 -		GetScrollBarInfo(Frame->hWnd, OBJID_VSCROLL, &si);
 -
 -		RECT rLine = (si.rcScrollBar);
 -		RECT rUpBtn = rLine;
 -		RECT rDnBtn = rLine;
 -		RECT rThumb = rLine;
 -
 -		rUpBtn.bottom = rUpBtn.top+si.dxyLineButton;
 -		rDnBtn.top = rDnBtn.bottom-si.dxyLineButton;
 -		rThumb.top = rLine.top+si.xyThumbTop;
 -		rThumb.bottom = rLine.top+si.xyThumbBottom;
 -
 -		int dx = Frame->wndSize.right-rLine.right;
 -		int dy = -rLine.top + Frame->wndSize.top;
 -
 -		OffsetRect(&rLine, dx, dy);
 -		OffsetRect(&rUpBtn, dx, dy);
 -		OffsetRect(&rDnBtn, dx, dy);
 -		OffsetRect(&rThumb, dx, dy);
 -		BitBlt(g_pCachedWindow->hImageDC, rLine.left, rLine.top, rLine.right - rLine.left, rLine.bottom - rLine.top, g_pCachedWindow->hBackDC, rLine.left, rLine.top, SRCCOPY);
 -
 -		char req[255];
 -		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Back", Frame->szName);
 -		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rLine,&rLine,req);
 -		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Thumb", Frame->szName);
 -		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rThumb,&rThumb,req);
 -		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar, Frame=%s,Part=UpLineButton", Frame->szName);
 -		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rUpBtn,&rUpBtn,req);
 -		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=DownLineButton", Frame->szName);
 -		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rDnBtn,&rDnBtn,req);
 -	}
 -
 -	SelectObject(hdc, o);
 -	DeleteObject(n);
 -	DeleteDC(hdc);
 -	return 1;
 -}
 -
 -int ske_BltBackImage (HWND destHWND, HDC destDC, RECT *BltClientRect)
 -{
 -	POINT ptMainWnd = {0};
 -	POINT ptChildWnd = {0};
 -	RECT from = {0};
 -	RECT w = {0};
 -	if (g_CluiData.fDisableSkinEngine) {
 -		FillRect(destDC,BltClientRect,GetSysColorBrush(COLOR_3DFACE));
 -		return 0;
 -	}
 -	ske_ReCreateBackImage(FALSE,NULL);
 -	if (BltClientRect) w = *BltClientRect;
 -	else GetClientRect(destHWND,&w);
 -	ptChildWnd.x = w.left;
 -	ptChildWnd.y = w.top;
 -	ClientToScreen(destHWND,&ptChildWnd);
 -	ClientToScreen(pcli->hwndContactList,&ptMainWnd);
 -	//TODO if main not relative to client area
 -	return BitBlt(destDC,w.left,w.top,(w.right-w.left),(w.bottom-w.top),g_pCachedWindow->hBackDC,(ptChildWnd.x-ptMainWnd.x),(ptChildWnd.y-ptMainWnd.y),SRCCOPY);
 -
 -}
 -int ske_ReCreateBackImage(BOOL Erase,RECT *w)
 -{
 -	HBITMAP hb2;
 -	RECT wnd = {0};
 -	BOOL IsNewCache = 0;
 -	if (g_CluiData.fDisableSkinEngine) return 0;
 -	GetClientRect(pcli->hwndContactList,&wnd);
 -	if (w) wnd = *w;
 -	//-- Check cached.
 -	if (g_pCachedWindow == NULL) {
 -		//-- Create New Cache
 -		g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
 -		g_pCachedWindow->hScreenDC = GetDC(NULL);
 -		g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
 -		g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
 -		g_pCachedWindow->Width = wnd.right-wnd.left;
 -		g_pCachedWindow->Height = wnd.bottom-wnd.top;
 -		if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) {
 -			g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
 -			g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
 -			g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB);
 -			g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB);
 -		}
 -		IsNewCache = 1;
 -	}
 -
 -	if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) {
 -		HBITMAP hb1 = NULL,hb2 = NULL;
 -		g_pCachedWindow->Width = wnd.right-wnd.left;
 -		g_pCachedWindow->Height = wnd.bottom-wnd.top;
 -		if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) {
 -			hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
 -			hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
 -			SelectObject(g_pCachedWindow->hImageDC,hb1);
 -			SelectObject(g_pCachedWindow->hBackDC,hb2);
 -		}
 -		else {
 -			SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld);
 -			SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld);
 -		}
 -		if (g_pCachedWindow->hImageDIB) DeleteObject(g_pCachedWindow->hImageDIB);
 -		if (g_pCachedWindow->hBackDIB) DeleteObject(g_pCachedWindow->hBackDIB);
 -		g_pCachedWindow->hImageDIB = hb1;
 -		g_pCachedWindow->hBackDIB = hb2;
 -		IsNewCache = 1;
 -	}
 -
 -	if ((Erase || IsNewCache ) &&  (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0)) {
 -		hb2 = ske_CreateDIB32(g_pCachedWindow->Width,g_pCachedWindow->Height);
 -		SelectObject(g_pCachedWindow->hBackDC,hb2);
 -		DeleteObject(g_pCachedWindow->hBackDIB);
 -		g_pCachedWindow->hBackDIB = hb2;
 -		FillRect(g_pCachedWindow->hBackDC,&wnd,GetSysColorBrush(COLOR_BTNFACE));
 -		SkinDrawGlyph(g_pCachedWindow->hBackDC,&wnd,&wnd,"Main,ID=Background,Opt=Non-Layered");
 -		ske_SetRectOpaque(g_pCachedWindow->hBackDC,&wnd);
 -	}
 -	return 1;
 -}
 -
 -int ske_DrawNonFramedObjects(BOOL Erase,RECT *r)
 -{
 -	RECT w, wnd;
 -	if (r) w = *r;
 -	else CLUI_SizingGetWindowRect(pcli->hwndContactList, &w);
 -	if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0);
 -	if (g_pCachedWindow == NULL)
 -		return ske_ValidateFrameImageProc(&w);
 -
 -	wnd = w;
 -	OffsetRect(&w, -w.left, -w.top);
 -	if (Erase) {
 -		HBITMAP hb2;
 -		hb2 = ske_CreateDIB32(g_pCachedWindow->Width, g_pCachedWindow->Height);
 -		SelectObject(g_pCachedWindow->hBackDC, hb2);
 -		DeleteObject(g_pCachedWindow->hBackDIB);
 -		g_pCachedWindow->hBackDIB = hb2;
 -	}
 -
 -	SkinDrawGlyph(g_pCachedWindow->hBackDC, &w, &w, "Main,ID=Background");
 -
 -	//--Draw frames captions
 -	for (int i = 0; i < g_nFramesCount; i++) {
 -		if (g_pfwFrames[i].TitleBar.ShowTitleBar && g_pfwFrames[i].visible && !g_pfwFrames[i].floating) {
 -			RECT rc;
 -			SetRect(&rc, g_pfwFrames[i].wndSize.left, g_pfwFrames[i].wndSize.top - g_nTitleBarHeight - g_CluiData.nGapBetweenTitlebar, g_pfwFrames[i].wndSize.right, g_pfwFrames[i].wndSize.top - g_CluiData.nGapBetweenTitlebar);
 -			Sync(DrawTitleBar, g_pCachedWindow->hBackDC, &rc, g_pfwFrames[i].id);
 -		}
 -	}
 -	g_mutex_bLockUpdating = 1;
 -
 -	flag_bJustDrawNonFramedObjects = 1;
 -	return 0;
 -}
 -
 -int ske_ValidateFrameImageProc(RECT *r)                                // Calling queued frame paint procs and refresh image
 -{
 -	RECT wnd = {0};
 -	BOOL IsNewCache = 0;
 -	BOOL IsForceAllPainting = 0;
 -	if (r) wnd = *r;
 -	else GetWindowRect(pcli->hwndContactList,&wnd);
 -	if (wnd.right-wnd.left == 0 || wnd.bottom-wnd.top == 0)
 -		return 0;
 -
 -	g_mutex_bLockUpdating = 1;
 -
 -	//-- Check cached.
 -	if (g_pCachedWindow == NULL) {
 -		//-- Create New Cache
 -		g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
 -		g_pCachedWindow->hScreenDC = GetDC(NULL);
 -		g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
 -		g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
 -		g_pCachedWindow->Width = wnd.right-wnd.left;
 -		g_pCachedWindow->Height = wnd.bottom-wnd.top;
 -		g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
 -		g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
 -		g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB);
 -		g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB);
 -		IsNewCache = 1;
 -	}
 -	if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) {
 -		HBITMAP hb1,hb2;
 -		g_pCachedWindow->Width = wnd.right-wnd.left;
 -		g_pCachedWindow->Height = wnd.bottom-wnd.top;
 -		hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
 -		hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
 -		SelectObject(g_pCachedWindow->hImageDC,hb1);
 -		SelectObject(g_pCachedWindow->hBackDC,hb2);
 -		DeleteObject(g_pCachedWindow->hImageDIB);
 -		DeleteObject(g_pCachedWindow->hBackDIB);
 -		g_pCachedWindow->hImageDIB = hb1;
 -		g_pCachedWindow->hBackDIB = hb2;
 -		IsNewCache = 1;
 -	}
 -	if (IsNewCache) {
 -		ske_DrawNonFramedObjects(0, &wnd);
 -		IsForceAllPainting = 1;
 -	}
 -	if (flag_bJustDrawNonFramedObjects) {
 -		IsForceAllPainting = 1;
 -		flag_bJustDrawNonFramedObjects = 0;
 -	}
 -	if (IsForceAllPainting) {
 -		BitBlt(g_pCachedWindow->hImageDC, 0, 0, g_pCachedWindow->Width,g_pCachedWindow->Height,g_pCachedWindow->hBackDC, 0, 0, SRCCOPY);
 -		Sync( QueueAllFramesUpdating, (BYTE)1 );
 -	}
 -	//-- Validating frames
 -	for (int i=0; i < g_nFramesCount; i++)
 -		if (g_pfwFrames[i].PaintCallbackProc && g_pfwFrames[i].visible && !g_pfwFrames[i].floating)
 -			if (g_pfwFrames[i].bQueued || IsForceAllPainting)
 -				ske_ValidateSingleFrameImage(&g_pfwFrames[i], IsForceAllPainting);
 -
 -	g_mutex_bLockUpdating = 1;
 -	ModernSkinButtonRedrawAll(0);
 -	g_mutex_bLockUpdating = 0;
 -	if (!mutex_bLockUpdate)
 -		ske_UpdateWindowImageRect(&wnd);
 -
 -	//-- Clear queue
 -	Sync(QueueAllFramesUpdating, 0);
 -	flag_bUpdateQueued = 0;
 -	g_flag_bPostWasCanceled = 0;
 -	return 1;
 -}
 -
 -int ske_UpdateWindowImage()
 -{
 -	if (MirandaExiting())
 -		return 0;
 -
 -	if (g_CluiData.fLayered) {
 -		RECT r;
 -		GetWindowRect(pcli->hwndContactList,&r);
 -		return ske_UpdateWindowImageRect(&r);
 -	}
 -	else ske_ReCreateBackImage(FALSE,0);
 -	ske_ApplyTranslucency();
 -	return 0;
 -}
 -
 -int ske_UpdateWindowImageRect(RECT *r)                                     // Update window with current image and
 -{
 -	//if not validity -> ValidateImageProc
 -	//else Update using current alpha
 -	RECT wnd = *r;
 -
 -	if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0);
 -	if (g_pCachedWindow == NULL) return ske_ValidateFrameImageProc(&wnd);
 -	if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) return ske_ValidateFrameImageProc(&wnd);
 -	if (g_flag_bFullRepaint) {
 -		g_flag_bFullRepaint = 0;
 -		return ske_ValidateFrameImageProc(&wnd);
 -	}
 -	ske_JustUpdateWindowImageRect(&wnd);
 -	return 0;
 -}
 -
 -void ske_ApplyTranslucency()
 -{
 -	int IsTransparancy;
 -	HWND hwnd = pcli->hwndContactList;
 -	BOOL layered = (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED)?TRUE:FALSE;
 -
 -	IsTransparancy = g_CluiData.fSmoothAnimation || g_bTransparentFlag;
 -	if (!g_bTransparentFlag && !g_CluiData.fSmoothAnimation && g_CluiData.bCurrentAlpha != 0)
 -		g_CluiData.bCurrentAlpha = 255;
 -
 -	if (!g_CluiData.fLayered && IsTransparancy) {
 -		if (!layered)
 -			SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
 -		SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE)g_CluiData.bCurrentAlpha, LWA_ALPHA);
 -	}
 -
 -	AniAva_RedrawAllAvatars(FALSE);
 -	return;
 -}
 -
 -int ske_JustUpdateWindowImage()
 -{
 -	RECT r;
 -	if (!g_CluiData.fLayered) {
 -		ske_ApplyTranslucency();
 -		return 0;
 -	}
 -	GetWindowRect(pcli->hwndContactList,&r);
 -	return ske_JustUpdateWindowImageRect(&r);
 -}
 -
 -// Update window image
 -int ske_JustUpdateWindowImageRect(RECT *rty)
 -{
 -	if (!g_CluiData.fLayered) {
 -		ske_ApplyTranslucency();
 -		return 0;
 -	}
 -	if (!pcli->hwndContactList)
 -		return 0;
 -
 -	RECT wnd = *rty;
 -	RECT rect = wnd;
 -	POINT dest = { 0 }, src = { 0 };
 -	dest.x = rect.left;
 -	dest.y = rect.top;
 -	SIZE sz = { rect.right - rect.left, rect.bottom - rect.top };
 -	if (g_CluiData.fLayered) {
 -		if (!(GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE)&WS_EX_LAYERED))
 -			SetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE, GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE) | WS_EX_LAYERED);
 -		Sync(SetAlpha, g_CluiData.bCurrentAlpha);
 -
 -		BLENDFUNCTION bf = { AC_SRC_OVER, 0, g_CluiData.bCurrentAlpha, AC_SRC_ALPHA };
 -		UpdateLayeredWindow(pcli->hwndContactList, g_pCachedWindow->hScreenDC, &dest, &sz, g_pCachedWindow->hImageDC, &src, RGB(1, 1, 1), &bf, ULW_ALPHA);
 -		g_CluiData.fAeroGlass = false;
 -		CLUI_UpdateAeroGlass();
 -	}
 -	else InvalidateRect(pcli->hwndContactList,NULL,TRUE);
 -	return 0;
 -}
 -
 -int ske_DrawImageAt(HDC hdc, RECT *rc)
 -{
 -	BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
 -	BitBlt(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,g_pCachedWindow->hBackDC,rc->left,rc->top,SRCCOPY);
 -	ske_AlphaBlend(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,hdc, 0, 0, rc->right-rc->left,rc->bottom-rc->top,bf);
 -	if (!g_mutex_bLockUpdating)
 -		ske_UpdateWindowImage();
 -	return 0;
 -}
 -
 -HBITMAP ske_GetCurrentWindowImage()
 -{
 -	return g_pCachedWindow->hImageDIB;
 -}
 -
 -/*
 -*  Glyph text routine
 -*/
 -
 -static DWORD ske_HexToARGB(char * Hex)
 -{
 -	char buf[10] = {0};
 -	char buf2[11] = {0};
 -	mir_snprintf(buf, SIZEOF(buf), "%s\n", Hex);
 -	if (buf[1] == 'x' || buf[1] == 'X')
 -		mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf+2);
 -	else
 -		mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf);
 -	buf2[10] = '\0';
 -
 -	char *st;
 -	DWORD AARRGGBB = strtoul(buf2, &st, 16);
 -	BYTE alpha = (BYTE)((AARRGGBB & 0xFF000000) >> 24);
 -	alpha = 255-((alpha == 0)?255:alpha);
 -	AARRGGBB = (alpha << 24)+((AARRGGBB&0x00FF0000)>>16)+((AARRGGBB&0x000000FF) << 16)+(AARRGGBB&0x0000FF00);
 -	return AARRGGBB;
 -}
 -
 -static TCHAR *ske_ReAppend(TCHAR *lfirst, TCHAR * lsecond, int len)
 -{
 -	int l1 = lfirst?lstrlen(lfirst):0;
 -	int l2 = (len?len:(lstrlen(lsecond)+1));
 -	TCHAR *buf = (TCHAR *)mir_alloc((l1+l2+1)*sizeof(TCHAR));
 -	if (lfirst) memmove(buf,lfirst,l1*sizeof(TCHAR));
 -	memmove(buf+l1,lsecond,l2*sizeof(TCHAR));
 -	mir_free(lfirst);
 -	if (len) buf[l1+l2] = _T('\0');
 -	return buf;
 -}
 -
 -TCHAR* ske_ReplaceVar(TCHAR *var)
 -{
 -	if (!var) return mir_tstrdup(_T(""));
 -	if (!lstrcmpi(var,_T("Profile"))) {
 -		char buf[MAX_PATH] = {0};
 -		CallService(MS_DB_GETPROFILENAME,(WPARAM)MAX_PATH,(LPARAM)buf);
 -
 -		int i = strlen(buf);
 -		while (buf[i] != '.' && i>0) i--;
 -		buf[i] = '\0';
 -
 -		mir_free(var);
 -		return mir_a2u(buf);
 -	}
 -
 -	mir_free(var);
 -	return mir_tstrdup(_T(""));
 -}
 -
 -TCHAR *ske_ParseText(TCHAR *stzText)
 -{
 -	int len = lstrlen(stzText);
 -	TCHAR *result = NULL;
 -	int stpos = 0;
 -	int curpos = 0;
 -
 -	while (curpos < len) {
 -		//1 find first %
 -		while (curpos < len && stzText[curpos] != (TCHAR)'%')
 -			curpos++;
 -		if (curpos < len) { //% found
 -			if (curpos-stpos>0)
 -				result = ske_ReAppend(result,stzText+stpos,curpos-stpos);
 -			stpos = curpos+1;
 -			curpos++;
 -			//3 find second %
 -			while(curpos < len && stzText[curpos] != (TCHAR)'%')
 -				curpos++;
 -			if (curpos >= len)
 -				break;
 -			if (curpos - stpos > 0) {
 -				TCHAR *var = (TCHAR *)mir_alloc((curpos - stpos + 1)*sizeof(TCHAR));
 -				memmove(var, stzText + stpos, (curpos - stpos)*sizeof(TCHAR));
 -				var[curpos - stpos] = (TCHAR)'\0';
 -				var = ske_ReplaceVar(var);
 -				result = ske_ReAppend(result, var, 0);
 -				mir_free(var);
 -			}
 -			else result = ske_ReAppend(result, _T("%"), 0);
 -
 -			curpos++;
 -			stpos = curpos;
 -		}
 -		else {
 -			if (curpos - stpos > 0)
 -				result = ske_ReAppend(result, stzText + stpos, curpos - stpos);
 -			break;
 -		}
 -	}
 -	return result;
 -}
 -/*
 -*   Parse text object string, find glyph object and add text to it.
 -*   szGlyphTextID and Define string is:
 -*   t[szGlyphTextID] = s[HostObjectID],[Left],[Top],[Right],[Bottom],[LTRBHV],[FontID],[Color1],[reservedforColor2],[Text]
 -*/
 -
 -static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin)
 -{
 -	char buf[255] = {0};
 -	GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE);
 -	if (buf[0] == 0)
 -		return;
 -
 -	GLYPHTEXT *glText = (GLYPHTEXT*)mir_calloc(sizeof(GLYPHTEXT));
 -	glText->szGlyphTextID = mir_strdup(szGlyphTextID);
 -	glText->szObjectName = mir_strdup(buf);
 -	glText->iLeft = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE));
 -	glText->iTop = atoi(GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE));
 -	glText->iRight = atoi(GetParamN(szDefineString,buf,sizeof(buf),3,',',TRUE));
 -	glText->iBottom = atoi(GetParamN(szDefineString,buf,sizeof(buf),4,',',TRUE));
 -	{
 -		memset(buf, 0, 6);
 -		GetParamN(szDefineString,buf,sizeof(buf),5,',',TRUE);
 -		buf[0] &= 95; buf[1] &= 95; buf[2] &= 95; buf[3] &= 95; buf[4] &= 95; buf[5] &= 95;   //to uppercase: &01011111 (0-95)
 -		glText->RelativeFlags =
 -			(buf[0] == 'C'?1:((buf[0] == 'R')?2:0))       //[BC][RC][BC][RC] --- Left relative
 -			|(buf[1] == 'C'?4:((buf[1] == 'B')?8:0))       //  |   |   |--------- Top relative
 -			|(buf[2] == 'C'?16:((buf[2] == 'R')?32:0))     //  |   |--------------Right relative
 -			|(buf[3] == 'C'?64:((buf[3] == 'B')?128:0));   //  |------------------Bottom relative
 -		glText->dwFlags = (buf[4] == 'C'?DT_CENTER:((buf[4] == 'R')?DT_RIGHT:DT_LEFT))
 -			|(buf[5] == 'C'?DT_VCENTER:((buf[5] == 'B')?DT_BOTTOM:DT_TOP));
 -	}
 -	glText->szFontID = mir_strdup(GetParamN(szDefineString,buf,sizeof(buf),6,',',TRUE));
 -
 -	glText->dwColor = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),7,',',TRUE));
 -	glText->dwShadow = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),8,',',TRUE));
 -	glText->stValueText = mir_a2u(GetParamN(szDefineString,buf,sizeof(buf),9,',',TRUE));
 -	glText->stText = ske_ParseText(glText->stValueText);
 -
 -	if (!Skin->pTextList)
 -		Skin->pTextList = List_Create(0, 1);
 -	List_InsertPtr(Skin->pTextList,glText);
 -}
 -
 -
 -/*
 -*   Parse font definition string.
 -*   szGlyphTextID and Define string is:
 -*   f[szFontID] = s[FontTypefaceName],[size],[BIU]
 -*/
 -static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin)
 -{
 -	SKINFONT *sf = (SKINFONT*)mir_calloc(sizeof(SKINFONT));
 -	if (!sf)
 -		return;
 -
 -	char buf[255];
 -	int fntSize = 0;
 -	BOOL fntBold = FALSE, fntItalic = FALSE, fntUnderline = FALSE;
 -	LOGFONTA logfont = {0};
 -	logfont.lfCharSet = DEFAULT_CHARSET;
 -	logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
 -	logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
 -	logfont.lfQuality = DEFAULT_QUALITY;
 -	logfont.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
 -
 -	strncpy(logfont.lfFaceName,GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE),32);
 -	logfont.lfHeight = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE));
 -	if (logfont.lfHeight < 0) {
 -		HDC hdc = CreateCompatibleDC(NULL);
 -		logfont.lfHeight = (long)-MulDiv(logfont.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
 -		DeleteDC(hdc);
 -	}
 -	logfont.lfHeight = -logfont.lfHeight;
 -	GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE);
 -	buf[0] &= 95; buf[1] &= 95; buf[2] &= 95;
 -	logfont.lfWeight = (buf[0] == 'B')?FW_BOLD:FW_NORMAL;
 -	logfont.lfItalic = (buf[1] == 'I')?1:0;
 -	logfont.lfUnderline = (buf[2] == 'U')?1:0;
 -
 -	sf->hFont = CreateFontIndirectA(&logfont);
 -	if (sf->hFont) {
 -		sf->szFontID = mir_strdup(szFontID);
 -		if (!gl_plSkinFonts)
 -			gl_plSkinFonts = List_Create(0, 1);
 -		if (gl_plSkinFonts)
 -			List_Insert(gl_plSkinFonts,(void*)sf,gl_plSkinFonts->realCount);
 -	}
 -}
 -
 -/*
 - *   ske_CheckHasAlfaChannel - checks if image has at least one BYTE in alpha chennel
 - *                  that is not a 0. (is image real 32 bit or just 24 bit)
 - */
 -static BOOL ske_CheckHasAlfaChannel(BYTE * from, int widthByte, int height)
 -{
 -	DWORD *pt = (DWORD*)from;
 -	for (int j = 0; j < height; j++) {
 -		BYTE *add = (BYTE*)pt+widthByte;
 -		while (pt < (DWORD*)add) {
 -			if ((*pt & 0xFF000000) != 0)
 -				return TRUE;
 -			pt++;
 -		}
 -		pt = (DWORD*)(from+widthByte*j);
 -	}
 -	return FALSE;
 -}
 -
 -/*
 - *   ske_CheckIconHasMask - checks if mask image has at least one that is not a 0.
 - *                  Not sure is ir required or not
 - */
 -static BOOL ske_CheckIconHasMask(BYTE * from)
 -{
 -	for (int i=0; i < 16*16/8; i++)
 -		if (from[i] != 0)
 -			return TRUE;
 -
 -	return FALSE;
 -}
 -
 -/*
 - *   ske_GetMaskBit - return value of apropriate mask bit in line at x position
 - */
 -static BOOL ske_GetMaskBit(BYTE *line, int x)
 -{
 -	return ((*(line+(x>>3)))&(0x01 << (7-(x&0x07)))) != 0;
 -}
 -
 -/*
 - *    ske_Blend  - alpha ske_Blend ARGB values of 2 pixels. X1 - underlaying,
 - *            X2 - overlaying points.
 - */
 -
 -static DWORD ske_Blend(DWORD X1,DWORD X2, BYTE alpha)
 -{
 -	BYTE a1 = (BYTE)(X1>>24);
 -	BYTE a2 = (BYTE)(((X2>>24)*alpha)>>8);
 -	BYTE r1 = (BYTE)(X1>>16);
 -	BYTE r2 = (BYTE)(X2>>16);
 -	BYTE g1 = (BYTE)(X1>>8);
 -	BYTE g2 = (BYTE)(X2>>8);
 -	BYTE b1 = (BYTE)(X1);
 -	BYTE b2 = (BYTE)(X2);
 -
 -	BYTE a_1 = ~a1;
 -	BYTE a_2 = ~a2;
 -	WORD am = (WORD)a1*a_2;
 -
 -	/*  it is possible to use >>8 instead of /255 but it is require additional
 -	*   checking of alphavalues
 -	*/
 -	WORD ar = a1+(((WORD)a_1*a2)/255);
 -	// if a2 more than 0 than result should be more
 -	// or equal (if a1 == 0) to a2, else in combination
 -	// with mask we can get here black points
 -
 -	ar = (a2>ar)?a2:ar;
 -
 -	if (ar == 0) return 0;
 -
 -	WORD arm = ar*255;
 -	WORD rr = (((WORD)r1*am+(WORD)r2*a2*255))/arm;
 -	WORD gr = (((WORD)g1*am+(WORD)g2*a2*255))/arm;
 -	WORD br = (((WORD)b1*am+(WORD)b2*a2*255))/arm;
 -	return (ar << 24)|(rr << 16)|(gr << 8)|br;
 -}
 -
 -/*
 - *    CreateJoinedIcon  - creates new icon by drawing hTop over hBottom.
 - */
 -
 -HICON ske_CreateJoinedIcon(HICON hBottom, HICON hTop, BYTE alpha)
 -{
 -	HBITMAP nMask;
 -	BITMAP bmp = { 0 };
 -	BYTE *ptPixels;
 -	ICONINFO iNew = { 0 };
 -	ICONINFO iciBottom = { 0 };
 -	ICONINFO iciTop = { 0 };
 -
 -	BITMAP bmp_top = { 0 };
 -	BITMAP bmp_top_mask = { 0 };
 -
 -	BITMAP bmp_bottom = { 0 };
 -	BITMAP bmp_bottom_mask = { 0 };
 -
 -	HDC tempDC = CreateCompatibleDC(NULL);
 -	HBITMAP nImage = ske_CreateDIB32Point(16, 16, (void**)&ptPixels);
 -	HBITMAP oImage = (HBITMAP)SelectObject(tempDC, nImage);
 -
 -	GetIconInfo(hBottom, &iciBottom);
 -	GetObject(iciBottom.hbmColor, sizeof(BITMAP), &bmp_bottom);
 -	GetObject(iciBottom.hbmMask, sizeof(BITMAP), &bmp_bottom_mask);
 -
 -	GetIconInfo(hTop, &iciTop);
 -	GetObject(iciTop.hbmColor, sizeof(BITMAP), &bmp_top);
 -	GetObject(iciTop.hbmMask, sizeof(BITMAP), &bmp_top_mask);
 -
 -	if (bmp_bottom.bmBitsPixel == 32 && bmp_top.bmBitsPixel == 32) {
 -		BYTE *BottomBuffer, *TopBuffer, *BottomMaskBuffer, *TopMaskBuffer;
 -		BYTE *bb, *tb, *bmb, *tmb;
 -		BYTE *db = ptPixels;
 -		int vstep_d = 16 * 4;
 -		int vstep_b = bmp_bottom.bmWidthBytes;
 -		int vstep_t = bmp_top.bmWidthBytes;
 -		int vstep_bm = bmp_bottom_mask.bmWidthBytes;
 -		int vstep_tm = bmp_top_mask.bmWidthBytes;
 -		alpha = alpha ? alpha : 255;
 -		if (bmp_bottom.bmBits) bb = BottomBuffer = (BYTE*)bmp_bottom.bmBits;
 -		else {
 -			BottomBuffer = (BYTE*)malloc(bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes);
 -			GetBitmapBits(iciBottom.hbmColor, bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes, BottomBuffer);
 -			bb = BottomBuffer + vstep_b*(bmp_bottom.bmHeight - 1);
 -			vstep_b = -vstep_b;
 -		}
 -
 -		if (bmp_top.bmBits) tb = TopBuffer = (BYTE*)bmp_top.bmBits;
 -		else {
 -			TopBuffer = (BYTE*)malloc(bmp_top.bmHeight*bmp_top.bmWidthBytes);
 -			GetBitmapBits(iciTop.hbmColor,bmp_top.bmHeight*bmp_top.bmWidthBytes,TopBuffer);
 -			tb = TopBuffer+vstep_t*(bmp_top.bmHeight-1);
 -			vstep_t = -vstep_t;
 -		}
 -
 -		if (bmp_bottom_mask.bmBits) {
 -			BottomMaskBuffer = (BYTE*)bmp_bottom_mask.bmBits;
 -			bmb = BottomMaskBuffer;
 -		}
 -		else {
 -			BottomMaskBuffer = (BYTE*)malloc(bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes);
 -			GetBitmapBits(iciBottom.hbmMask,bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes,BottomMaskBuffer);
 -			bmb = BottomMaskBuffer+vstep_bm*(bmp_bottom_mask.bmHeight-1);
 -			vstep_bm = -vstep_bm;
 -
 -		}
 -
 -		if (bmp_top_mask.bmBits) {
 -			TopMaskBuffer = (BYTE*)bmp_top_mask.bmBits;
 -			tmb = TopMaskBuffer;
 -		}
 -		else {
 -			TopMaskBuffer = (BYTE*)malloc(bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes);
 -			GetBitmapBits(iciTop.hbmMask,bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes,TopMaskBuffer);
 -			tmb = TopMaskBuffer+vstep_tm*(bmp_top_mask.bmHeight-1);
 -			vstep_tm = -vstep_tm;
 -		}
 -
 -		BOOL topHasAlpha = ske_CheckHasAlfaChannel(TopBuffer, bmp_top.bmWidthBytes, bmp_top.bmHeight);
 -		BOOL bottomHasAlpha = ske_CheckHasAlfaChannel(BottomBuffer, bmp_bottom.bmWidthBytes, bmp_bottom.bmHeight);
 -		BOOL topHasMask = ske_CheckIconHasMask(TopMaskBuffer);
 -		BOOL bottomHasMask = ske_CheckIconHasMask(BottomMaskBuffer);
 -		for (int y = 0; y < 16; y++) {
 -			for (int x = 0; x < 16; x++) {
 -				BOOL mask_b = ske_GetMaskBit(bmb, x);
 -				BOOL mask_t = ske_GetMaskBit(tmb, x);
 -				DWORD bottom_d = ((DWORD*)bb)[x];
 -				DWORD top_d = ((DWORD*)tb)[x];
 -				if (topHasMask) {
 -					if (mask_t == 1 && !topHasAlpha)  top_d &= 0xFFFFFF;
 -					else if (!topHasAlpha) top_d |= 0xFF000000;
 -				}
 -				if (bottomHasMask) {
 -					if (mask_b == 1 && !bottomHasAlpha) bottom_d &= 0xFFFFFF;
 -					else if (!bottomHasAlpha) bottom_d |= 0xFF000000;
 -				}
 -				((DWORD*)db)[x] = ske_Blend(bottom_d, top_d, alpha);
 -			}
 -			bb += vstep_b;
 -			tb += vstep_t;
 -			bmb += vstep_bm;
 -			tmb += vstep_tm;
 -			db += vstep_d;
 -		}
 -
 -		if (!bmp_bottom.bmBits) free(BottomBuffer);
 -		if (!bmp_top.bmBits) free(TopBuffer);
 -		if (!bmp_bottom_mask.bmBits) free(BottomMaskBuffer);
 -		if (!bmp_top_mask.bmBits) free(TopMaskBuffer);
 -	}
 -	else {
 -		ske_DrawIconEx(tempDC, 0, 0, hBottom,16,16, 0, NULL,DI_NORMAL);
 -		ske_DrawIconEx(tempDC, 0, 0, hTop,16,16, 0, NULL,DI_NORMAL|(alpha << 24));
 -	}
 -
 -	DeleteObject(iciBottom.hbmColor);
 -	DeleteObject(iciTop.hbmColor);
 -	DeleteObject(iciBottom.hbmMask);
 -	DeleteObject(iciTop.hbmMask);
 -
 -	SelectObject(tempDC,oImage);
 -	DeleteDC(tempDC);
 -
 -	BYTE p[32] = {0};
 -	nMask = CreateBitmap(16,16,1,1,(void*)&p);
 -	{
 -		HDC tempDC2 = CreateCompatibleDC(NULL);
 -		HDC tempDC3 = CreateCompatibleDC(NULL);
 -		HBITMAP hbm = CreateCompatibleBitmap(tempDC3,16,16);
 -		HBITMAP obmp = (HBITMAP)SelectObject(tempDC2,nMask);
 -		HBITMAP obmp2 = (HBITMAP)SelectObject(tempDC3,hbm);
 -		DrawIconEx(tempDC2, 0, 0, hBottom,16,16, 0, NULL,DI_MASK);
 -		DrawIconEx(tempDC3, 0, 0, hTop,16,16, 0, NULL,DI_MASK);
 -		BitBlt(tempDC2, 0, 0, 16,16,tempDC3, 0, 0, SRCAND);
 -		SelectObject(tempDC2,obmp);
 -		SelectObject(tempDC3,obmp2);
 -		DeleteObject(hbm);
 -		DeleteDC(tempDC2);
 -		DeleteDC(tempDC3);
 -	}
 -	iNew.fIcon = TRUE;
 -	iNew.hbmColor = nImage;
 -	iNew.hbmMask = nMask;
 -	HICON res = CreateIconIndirect(&iNew);
 -	DeleteObject(nImage);
 -	DeleteObject(nMask);
 -	return res;
 -}
 -
 -#define NEWJOINEDSTR( destination, first, separator, last)						\
 -	destination = (char*)alloca(strlen(first)+strlen(separator)+strlen(last)+1);	\
 -	if (destination) {													\
 -	*destination = '\0';												\
 -	strcat(destination,first);										\
 -	strcat(destination,separator);									\
 -	strcat(destination,last);										\
 -	}
 -
 -#define SKINSETSECTION "SkinnedSettings"
 -
 -BOOL SkinDBGetContactSetting(MCONTACT hContact, const char* szSection, const char*szKey, DBVARIANT * retdbv, BOOL * bSkinned )
 -{
 -	if (!hContact) {  //only for not contact settings
 -		char *szSkinKey;
 -		NEWJOINEDSTR(szSkinKey, szSection, "@", szKey);
 -		if (!db_get(hContact, SKINSETSECTION, szSkinKey, retdbv))	{
 -			if (bSkinned) *bSkinned = TRUE;
 -			return FALSE;
 -		}
 -	}
 -	// not skinned
 -	if (bSkinned) bSkinned = FALSE;
 -	return db_get(hContact, szSection, szKey, retdbv);
 -}
 -
 -BYTE SkinDBGetContactSettingByte(MCONTACT hContact, const char* szSection, const char*szKey, BYTE bDefault)
 -{
 -	DBVARIANT dbv = { 0 };
 -	BOOL bSkinned = FALSE;
 -	if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
 -		if (dbv.type == DBVT_BYTE) {
 -			BYTE retVal = dbv.bVal;
 -			db_free(&dbv);
 -			return retVal;
 -		}
 -		else {
 -			db_free(&dbv);
 -			if (!bSkinned)
 -				return db_get_b(hContact, szSection, szKey, bDefault);
 -		}
 -	}
 -	return bDefault;
 -}
 -
 -WORD SkinDBGetContactSettingWord(MCONTACT hContact, const char* szSection, const char*szKey, WORD wDefault)
 -{
 -	BOOL bSkinned = FALSE;
 -	DBVARIANT dbv = { 0 };
 -	if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
 -		if (dbv.type == DBVT_WORD)	{
 -			WORD retVal = dbv.wVal;
 -			db_free(&dbv);
 -			return retVal;
 -		}
 -		db_free(&dbv);
 -		if (!bSkinned)
 -			return db_get_w(hContact, szSection, szKey, wDefault);
 -	}
 -	return wDefault;
 -}
 -
 -DWORD SkinDBGetContactSettingDword(MCONTACT hContact, const char* szSection, const char*szKey, DWORD dwDefault)
 -{
 -	DBVARIANT dbv = { 0 };
 -	BOOL bSkinned = FALSE;
 -	if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
 -		if (dbv.type == DBVT_DWORD)	{
 -			DWORD retVal = dbv.dVal;
 -			db_free(&dbv);
 -			return retVal;
 -		}
 -		db_free(&dbv);
 -		if (!bSkinned)
 -			return db_get_dw(hContact, szSection, szKey, dwDefault);
 -	}
 -	return dwDefault;
 -}
 +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 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 +#include "hdr/modern_commonheaders.h" +#include <m_png.h> +#include "m_api/m_skin_eng.h" +#include "hdr/modern_skinselector.h" +#include "CLUIFrames/cluiframes.h" + +#define _EFFECTENUM_FULL_H +#include "hdr/modern_effectenum.h" +#undef _EFFECTENUM_FULL_H + +#include "hdr/modern_skinengine.h" +#include "hdr/modern_commonprototypes.h" +#include "hdr/modern_sync.h" +//Implementation + +/* Global variables */ + +SKINOBJECTSLIST g_SkinObjectList = {0}; +CURRWNDIMAGEDATA *g_pCachedWindow = NULL; + +BOOL g_flag_bPostWasCanceled  = FALSE; +BOOL g_flag_bFullRepaint      = FALSE; +BOOL g_mutex_bLockUpdating    = FALSE; + +SortedList *gl_plGlyphTexts = NULL; +SortedList *gl_plSkinFonts  = NULL; + +/* Private module variables */ + +static HANDLE  hSkinLoadedEvent; + +static GLYPHIMAGE *pLoadedImages = NULL; +static DWORD dwLoadedImagesCount = 0; +static DWORD dwLoadedImagesAlocated = 0; + +static BOOL flag_bUpdateQueued = FALSE; +static BOOL	flag_bJustDrawNonFramedObjects = FALSE; +static BOOL mutex_bLockUpdate = FALSE; + +static LIST<EFFECTSSTACKITEM> arEffectStack(10, HandleKeySortT); +static SKINOBJECTSLIST *pCurrentSkin = NULL; +static char  **pszSettingName = NULL; +static int   nArrayLen = 0; + +static BYTE  pbGammaWeight[256] = {0}; +static BYTE  pbGammaWeightAdv[256] = {0}; +static BOOL  bGammaWeightFilled = FALSE; + +static CRITICAL_SECTION cs_SkinChanging = {0}; + +static LISTMODERNMASK *MainModernMaskList = NULL; + +/* Private module procedures */ +static BOOL ske_GetMaskBit(BYTE *line, int x); +static INT_PTR  ske_Service_AlphaTextOut(WPARAM wParam, LPARAM lParam); +static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, LPARAM lParam); + +static int  ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor); +static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin); +static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin); +static int  ske_DeleteAllSettingInSection(char * SectionName); +static int  ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin); +static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType,SKINOBJECTSLIST* Skin); +static int  ske_LoadSkinFromResource(BOOL bOnlyObjects); +static void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult); +static int  ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting); +static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam); +static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam); +static INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam); + +static MODERNEFFECT meCurrentEffect = {-1,{0}, 0, 0}; + + +////////////////////////////////////////////////////////////////////////// +// Ini file parser +////////////////////////////////////////////////////////////////////////// +IniParser::IniParser(TCHAR * tcsFileName, BYTE flags) : _Flags(flags) +{ +	_DoInit(); +	if (!tcsFileName) return; + +	if (tcsFileName[0] == _T('%')) +	{ +		//TODO: Add parser of resource filename here +		_LoadResourceIni(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF"); +		return; +	} + +	_hFile = _tfopen(tcsFileName, _T("r")); + +	if (_hFile != NULL) +	{ +		_eType = IT_FILE; +		_isValid = true; +	} +} + +IniParser::IniParser(HINSTANCE hInst, const char *  resourceName, const char * resourceType, BYTE flags) : _Flags(flags) +{ +	_DoInit(); +	_LoadResourceIni(hInst, resourceName, resourceType); +} + +IniParser::~IniParser() +{ +	mir_free(_szSection); +	if (_hFile) fclose(_hFile); +	if (_hGlobalRes) { +		UnlockResource(_hGlobalRes); +		FreeResource(_hGlobalRes); +	} + +	_szSection = NULL; +	_hGlobalRes = NULL; +	_hFile = NULL; +	_isValid = false; +	_eType = IT_UNKNOWN; +} + +HRESULT IniParser::Parse(ParserCallback_t pLineCallBackProc, LPARAM SecCheck) +{ +	if (_isValid && pLineCallBackProc) +	{ +		_pLineCallBackProc = pLineCallBackProc; +		_SecCheck = SecCheck; +		switch (_eType) { +		case IT_FILE: +			return _DoParseFile(); +		case IT_RESOURCE: +			return _DoParseResource(); +		} +	} +	return E_FAIL; +} + +HRESULT IniParser::WriteStrToDb( const char * szSection, const char * szName, const char * szValue, IniParser * This ) +{ +	if ( This->_SecCheck) { +		//TODO check security here +		if ( wildcmp( szSection,"Skin_Description_Section")) +			return S_OK; +	} +	if (( This->_Flags == IniParser::FLAG_ONLY_OBJECTS ) && !wildcmp( szSection, DEFAULTSKINSECTION)) +		return S_OK;					 // skip not objects + +	switch (szValue[0]) { +	case 'b': +		db_set_b(NULL, szSection, szName, (BYTE)atoi(szValue + 1)); +		break; + +	case 'w': +		db_set_w(NULL, szSection, szName, (WORD)atoi(szValue + 1)); +		break; + +	case 'd': +		db_set_dw(NULL, szSection, szName, (DWORD)atoi(szValue + 1)); +		break; + +	case 's': +		db_set_s(NULL, szSection, szName, szValue + 1); +		break; +	} +	return S_OK; +} + +int IniParser::GetSkinFolder( IN const TCHAR * szFileName, OUT TCHAR * pszFolderName ) +{ +	TCHAR *szBuff = mir_tstrdup(szFileName); +	TCHAR *pszPos = szBuff + _tcslen(szBuff); +	while ( pszPos > szBuff && *pszPos != _T('.')) { pszPos--; } +	*pszPos = _T('\0'); +	_tcscpy( pszFolderName, szBuff ); + +	TCHAR custom_folder[MAX_PATH]; +	TCHAR cus[MAX_PATH]; +	TCHAR *b3; +	_tcscpy( custom_folder, pszFolderName ); +	b3 = custom_folder + _tcslen( custom_folder ); +	while ( b3 > custom_folder && *b3 != _T('\\')) { b3--; } +	*b3 = _T('\0'); + +	GetPrivateProfileString(_T("Skin_Description_Section"),_T("SkinFolder"),_T(""),cus,SIZEOF(custom_folder),szFileName); +	if (cus[0] != 0) +		mir_sntprintf(pszFolderName, MAX_PATH, _T("%s\\%s"), custom_folder, cus); + +	mir_free(szBuff); +	PathToRelativeT(pszFolderName, pszFolderName); +	return 0; +} + +void IniParser::_DoInit() +{ +	_isValid = false; +	_eType = IT_UNKNOWN; +	_szSection = NULL; +	_hFile = NULL; +	_hGlobalRes = NULL; +	_dwSizeOfRes = 0; +	_pPosition = NULL; +	_pLineCallBackProc = NULL; +	_SecCheck = 0; +} + +void IniParser::_LoadResourceIni( HINSTANCE hInst,  const char *  resourceName, const char * resourceType ) +{ +	if (_eType != IT_UNKNOWN) +		return; + +	HRSRC hRSrc = FindResourceA(hInst, resourceName, resourceType); +	if (!hRSrc) +		return; + +	_hGlobalRes = LoadResource(hInst, hRSrc); +	if (!_hGlobalRes) +		return; + +	_dwSizeOfRes = SizeofResource(hInst, hRSrc); +	_pPosition = (char*)LockResource(_hGlobalRes); + +	_isValid = true; +	_eType = IT_RESOURCE; +} + +HRESULT IniParser::_DoParseFile() +{ +	char szLine[MAX_LINE_LEN]; +	_nLine = 0; +	while (fgets(szLine, SIZEOF(szLine), _hFile) != NULL) { +		size_t len = 0; +		char * pLine = (char*)_RemoveTailings(szLine, len); +		if (len > 0) { +			pLine[len] = '\0'; +			if (!_DoParseLine(pLine))	return E_FAIL; +		} +		else _nLine++; +	}; + +	return S_OK; +} + +HRESULT IniParser::_DoParseResource() +{ +	_nLine = 0; +	char szLine[MAX_LINE_LEN]; +	char * pos = (char*)_pPosition; + +	while (pos < _pPosition + _dwSizeOfRes) { +		int i = 0; +		while (pos < _pPosition + _dwSizeOfRes && *pos != '\n' && *pos != '\0' && i < MAX_LINE_LEN - 1) { +			if ((*pos) != '\r') +				szLine[i++] = *pos; +			pos++; +		} +		szLine[i] = '\0'; +		pos++; + +		size_t len = 0; +		char * pLine = (char*)_RemoveTailings(szLine, len); +		if (len > 0) { +			pLine[len] = '\0'; +			if (!_DoParseLine(pLine))	return E_FAIL; +		} +		else _nLine++; +	} +	return S_OK; +} + +const char * IniParser::_RemoveTailings( const char * szLine, size_t& len ) +{ +	const char * pStart = szLine; +	while (*pStart == ' ' || *pStart == '\t') +		pStart++; //skip spaces at begin +	const char * pEnd = pStart + strlen(pStart); +	while (pEnd > pStart && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n' || *pEnd == '\r')) +		pEnd--; + +	len = pEnd - pStart; +	return pStart; +} + +BOOL IniParser::_DoParseLine( char * szLine ) +{ +	_nLine++; +	DWORD len = strlen( szLine ); + +	if (len == 0)	return TRUE; + +	switch( szLine[0] ) { +	case ';': +		return TRUE; // start of comment is found + +	case '[': +		//New section start here +		mir_free(_szSection); +		_szSection = NULL; +		{ +			char *tbuf = szLine + 1;	// skip [ + +			char *ebuf = tbuf; + +			while (*ebuf != ']' && *ebuf != '\0') ebuf++; +			if (*ebuf == '\0') +				return FALSE; // no close bracket + +			DWORD sectionLen = ebuf - tbuf; +			_szSection = (char*)mir_alloc(sectionLen + 1); +			strncpy(_szSection, tbuf, sectionLen); +			_szSection[sectionLen] = '\0'; +		} +		return TRUE; + +	default: +		if (!_szSection ) +			return TRUE;  //param found out of section + +		char *keyName = szLine; +		char *keyValue = szLine; + +		DWORD eqPlace = 0; +		DWORD len2 = strlen(keyName); + +		while ( eqPlace < len2 && keyName[ eqPlace ] != '=' ) +			eqPlace++; //find '=' + +		if (eqPlace == 0 || eqPlace == len2) +			return TRUE; // = not found or no key name //say false + +		keyName[eqPlace] = '\0'; + +		keyValue = keyName + eqPlace + 1; + +		//remove tail spaces in Name +		{ +			DWORD len3 = strlen(keyName); +			int j = len3-1; +			while (j>0 && (keyName[j] == ' ' || keyName[j] == '\t')) j--; +			if (j >= 0) keyName[j+1] = '\0'; +		} +		//remove start spaces in Value +		{ +			DWORD len3 = strlen(keyValue); +			DWORD j = 0; +			while (j < len3 && (keyValue[j] == ' ' || keyValue[j] == '\t')) j++; +			if (j < len3) keyValue += j; +		} +		//remove tail spaces in Value +		{ +			DWORD len3 = strlen(keyValue); +			int j = len3-1; +			while (j>0 && (keyValue[j] == ' ' || keyValue[j] == '\t' || keyValue[j] == '\n')) j--; +			if (j >= 0) keyValue[j+1] = '\0'; +		} +		_pLineCallBackProc( _szSection, keyName, keyValue, this ); +	} +	return TRUE; +} +////////////////////////////////////////////////////////////////////////// +// End of IniParser +////////////////////////////////////////////////////////////////////////// + +HRESULT SkinEngineLoadModule() +{ +	ModernSkinButtonLoadModule(); +	InitializeCriticalSection(&cs_SkinChanging); +	MainModernMaskList = (LISTMODERNMASK*)mir_calloc(sizeof(LISTMODERNMASK)); +	//init variables +	g_SkinObjectList.dwObjLPAlocated = 0; +	g_SkinObjectList.dwObjLPReserved = 0; +	g_SkinObjectList.pObjects = NULL; +	// Initialize GDI+ +	InitGdiPlus(); +	AniAva_InitModule(); +	//create services +	CreateServiceFunction(MS_SKIN_DRAWGLYPH,ske_Service_DrawGlyph); +	CreateServiceFunction(MS_SKINENG_UPTATEFRAMEIMAGE,ske_Service_UpdateFrameImage); +	CreateServiceFunction(MS_SKINENG_INVALIDATEFRAMEIMAGE,ske_Service_InvalidateFrameImage); +	CreateServiceFunction(MS_SKINENG_ALPHATEXTOUT,ske_Service_AlphaTextOut); +	CreateServiceFunction(MS_SKINENG_DRAWICONEXFIX,ske_Service_DrawIconEx); + +	CreateServiceFunction(MS_DRAW_TEXT_WITH_EFFECT,ske_Service_DrawTextWithEffect); + +	//create event handle +	hSkinLoadedEvent = HookEvent(ME_SKIN_SERVICESCREATED,CLUI_OnSkinLoad); +	NotifyEventHooks(g_CluiData.hEventSkinServicesCreated, 0, 0); +	return S_OK; +} + +int SkinEngineUnloadModule() +{ +	//unload services +	ModernSkinButtonUnloadModule(0, 0); +	ske_UnloadSkin(&g_SkinObjectList); + +	mir_free_and_nil(g_SkinObjectList.pObjects); +	mir_free_and_nil(g_SkinObjectList.pMaskList); +	mir_free_and_nil(MainModernMaskList); + +	for (int i=0; i < arEffectStack.getCount(); i++) +		mir_free(arEffectStack[i]); +	arEffectStack.destroy(); + +	if (g_pCachedWindow) { +		SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld); +		SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld); +		DeleteObject(g_pCachedWindow->hBackDIB); +		DeleteObject(g_pCachedWindow->hImageDIB); +		DeleteDC(g_pCachedWindow->hBackDC); +		DeleteDC(g_pCachedWindow->hImageDC); +		ReleaseDC(NULL,g_pCachedWindow->hScreenDC); +		mir_free_and_nil(g_pCachedWindow); +	} +	DeleteCriticalSection(&cs_SkinChanging); +	GdiFlush(); +	DestroyHookableEvent(g_CluiData.hEventSkinServicesCreated); +	AniAva_UnloadModule(); +	ShutdownGdiPlus(); +	//free variables +	return 1; +} + +BOOL ske_AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int nHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction) +{ +	if (g_CluiData.fDisableSkinEngine && !(blendFunction.BlendFlags&128)) +	{ +		if (nWidthDest != nWidthSrc || nHeightDest != nHeightSrc) +			return StretchBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc, SRCCOPY); +		else +			return BitBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc, SRCCOPY); +	} + +	if (blendFunction.BlendFlags&128) //Use gdi+ engine +	{ +		return GDIPlus_AlphaBlend( hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest, +			hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc, +			&blendFunction); +	} +	blendFunction.BlendFlags &= ~128; +	return AlphaBlend(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,blendFunction); +} + +static int ske_LockSkin() +{ +	EnterCriticalSection(&cs_SkinChanging); +	return 0; +} + +static int ske_UnlockSkin() +{ +	LeaveCriticalSection(&cs_SkinChanging); +	return 0; +} + +struct DCBUFFER +{ +	HDC hdcOwnedBy; +	int nUsageID; +	int width; +	int height; +	void* pImage; +	HDC hDC; +	HBITMAP oldBitmap; +	HBITMAP hBitmap; +	DWORD dwDestroyAfterTime; +}; + +static int SortBufferList(const DCBUFFER *buf1, const DCBUFFER *buf2) +{ +	if (buf1->hdcOwnedBy != buf2->hdcOwnedBy) return (int)(buf1->hdcOwnedBy < buf2->hdcOwnedBy); +	else if (buf1->nUsageID != buf2->nUsageID) return (int)(buf1->nUsageID < buf2->nUsageID); +	else return (int)(buf1->hDC < buf2->hDC); +} + +LIST<DCBUFFER> BufferList(2, SortBufferList); +CRITICAL_SECTION BufferListCS = {0}; + +enum +{ +	BUFFER_DRAWICON = 0, +	BUFFER_DRAWIMAGE +}; + +HDC ske_RequestBufferDC(HDC hdcOwner, int dcID, int width, int height, BOOL fClear) +{ +	mir_cslock lck(BufferListCS); +	//Try to find DC in buffer list +	DCBUFFER buf; +	buf.hdcOwnedBy = hdcOwner; +	buf.nUsageID = dcID; +	buf.hDC = NULL; +	DCBUFFER *pBuf = BufferList.find(&buf); +	if (!pBuf) { +		//if not found - allocate it +		pBuf = (DCBUFFER *)mir_alloc(sizeof(DCBUFFER)); +		*pBuf = buf; +		pBuf->width = width; +		pBuf->height = height; +		pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage)); +		pBuf->hDC = CreateCompatibleDC(hdcOwner); +		pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap); +		pBuf->dwDestroyAfterTime = 0; +		BufferList.insert(pBuf); +	} +	else +	{ +		if (pBuf->width != width || pBuf->height != height) +		{ +			//resize +			SelectObject(pBuf->hDC,pBuf->oldBitmap); +			DeleteObject(pBuf->hBitmap); +			pBuf->width = width; +			pBuf->height = height; +			pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage)); +			pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap); +		}  else	if (fClear) +			memset(pBuf->pImage, 0, width*height*sizeof(DWORD)); +	} +	pBuf->dwDestroyAfterTime = 0; +	return pBuf->hDC; +} + +int ske_ReleaseBufferDC(HDC hDC, int keepTime) +{ +	DWORD dwCurrentTime = GetTickCount(); + +	//Try to find DC in buffer list - set flag to be release after time; +	mir_cslock lck(BufferListCS); +	for (int i=0; i < BufferList.getCount(); i++) { +		DCBUFFER *pBuf = BufferList[i]; +		if (pBuf) { +			if (hDC != NULL && pBuf->hDC == hDC) { +				pBuf->dwDestroyAfterTime = dwCurrentTime+keepTime; +				break; +			} + +			if ((pBuf->dwDestroyAfterTime && pBuf->dwDestroyAfterTime < dwCurrentTime) || keepTime == -1) { +				SelectObject(pBuf->hDC,pBuf->oldBitmap); +				DeleteObject(pBuf->hBitmap); +				DeleteDC(pBuf->hDC); +				mir_free(pBuf); +				BufferList.remove(i); +				i--; +			} +		} +	} +	return 0; +} + +BOOL ske_SetRgnOpaque(HDC memdc,HRGN hrgn, BOOL force) +{ +	RGNDATA * rdata; +	DWORD rgnsz; +	DWORD d; +	RECT *rect; +	if (g_CluiData.fDisableSkinEngine && !force) return TRUE; +	rgnsz = GetRegionData(hrgn, 0, NULL); +	rdata = (RGNDATA *) mir_alloc(rgnsz); +	GetRegionData(hrgn,rgnsz,rdata); +	rect = (RECT *)rdata->Buffer; +	for (d = 0; d < rdata->rdh.nCount; d++) +	{ +		ske_SetRectOpaque(memdc,&rect[d], force); +	} +	mir_free(rdata); +	return TRUE; +} + + +BOOL ske_SetRectOpaque(HDC memdc,RECT *fr, BOOL force) +{ +	int f = 0; +	BYTE * bits; +	BITMAP bmp; +	HBITMAP hbmp; + +	if ( g_CluiData.fDisableSkinEngine && !force ) +		return TRUE; + +	hbmp = (HBITMAP)GetCurrentObject( memdc,OBJ_BITMAP ); +	GetObject( hbmp, sizeof(bmp), &bmp ); + +	if ( bmp.bmPlanes != 1 ) +		return FALSE; + +	if (!bmp.bmBits) +	{ +		f = 1; +		bits = (BYTE*)malloc(bmp.bmWidthBytes*bmp.bmHeight); +		GetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits); +	} +	else +		bits = (BYTE*)bmp.bmBits; + +	int sx  = ( fr->left > 0 ) ? fr->left : 0; +	int sy  = ( fr->top > 0 ) ? fr->top : 0; +	int ex  = ( fr->right < bmp.bmWidth ) ? fr->right : bmp.bmWidth; +	int ey  = ( fr->bottom < bmp.bmHeight) ? fr->bottom : bmp.bmHeight; + +	int width = ex-sx; + +	BYTE* pLine = ((BYTE*)bits) + (bmp.bmHeight-sy-1)*bmp.bmWidthBytes + (sx << 2) + 3; +	for ( int y = 0; y < (ey - sy); y++ ) +	{ +		BYTE * pColumn = pLine; +		for ( int x = 0; x < width; x++ ) +		{ +			*pColumn = 255; +			pColumn += 4; +		} +		pLine -= bmp.bmWidthBytes; +	} +	if (f) +	{ +		SetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits); +		free(bits); +	} +	// DeleteObject(hbmp); +	return 1; +} + +static BOOL ske_SkinFillRectByGlyph(HDC hDest, HDC hSource, RECT *rFill, RECT *rGlyph, RECT *rClip, BYTE mode, BYTE drawMode, int depth) +{ +	int destw = 0, desth = 0; +	int xstart = 0, xmax = 0; +	int ystart = 0, ymax = 0; +	BLENDFUNCTION bfa = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; +	BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + +	//initializations +	if (mode == FM_STRETCH) +	{ +		HDC mem2dc; +		HBITMAP mem2bmp, oldbmp; +		RECT wr; +		IntersectRect(&wr,rClip,rFill); +		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; +		if (drawMode != 2) +		{ +			mem2dc = CreateCompatibleDC(hDest); +			mem2bmp = ske_CreateDIB32(wr.right-wr.left,wr.bottom-wr.top); +			oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); + +		} + +		if (drawMode == 0 || drawMode == 2) +		{ +			if (drawMode == 0) +			{ +				ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top, +					hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf); +				ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf); +			} +			else +			{ +				ske_AlphaBlend(hDest,rFill->left,rFill->top,rFill->right-rFill->left,rFill->bottom-rFill->top, +					hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf); + +			} +		} +		else +		{ +			//            BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; +			ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top, +				hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf); +			ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf); +		} +		if (drawMode != 2) +		{ +			SelectObject(mem2dc,oldbmp); +			DeleteObject(mem2bmp); +			DeleteDC(mem2dc); +		} +		return 1; +	} +	else if (mode == FM_TILE_VERT && (rGlyph->bottom-rGlyph->top>0) &&  (rGlyph->right-rGlyph->left>0)) +	{ +		HDC mem2dc; +		HBITMAP mem2bmp,oldbmp; +		RECT wr; +		IntersectRect(&wr,rClip,rFill); +		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; +		mem2dc = CreateCompatibleDC(hDest); +		//SetStretchBltMode(mem2dc, HALFTONE); +		mem2bmp = ske_CreateDIB32(wr.right-wr.left, rGlyph->bottom-rGlyph->top); +		oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); +		if (!oldbmp) +			return 0; + +		/// draw here +		{ +			int  y = 0, sy = 0, maxy = 0; +			int w = rFill->right-rFill->left; +			int h = rGlyph->bottom-rGlyph->top; +			if (h>0 && (wr.bottom-wr.top)*(wr.right-wr.left) != 0) +			{ +				w = wr.right-wr.left; +				{ +					//                   BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; +					ske_AlphaBlend(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,bf); +					//StretchBlt(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,SRCCOPY); +				} +				if (drawMode == 0 || drawMode == 2) +				{ +					if (drawMode == 0 ) +					{ + +						int dy; +						dy = (wr.top-rFill->top)%h; +						if (dy >= 0) +						{ +							int ht; +							y = wr.top; +							ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top); +							BitBlt(hDest,wr.left,y,w,ht,mem2dc, 0, dy,SRCCOPY); +						} + +						y = wr.top+h-dy; +						while (y < wr.bottom-h){ +							BitBlt(hDest,wr.left,y,w,h,mem2dc, 0, 0, SRCCOPY); +							y += h; +						} +						if (y <= wr.bottom) +							BitBlt(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, SRCCOPY); + +					} +					else +					{ +						y = wr.top; +						while (y < wr.bottom-h) +						{ +							//                             BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; +							ske_AlphaBlend(hDest,wr.left,y,w,h, mem2dc, 0, 0, w,h,bf); +							y += h; +						} +						if (y <= wr.bottom) +						{ +							//                           BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; +							ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf); +						} +					} + +				} +				else +				{ +					int dy; + +					BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + +					dy = (wr.top-rFill->top)%h; + +					if (dy >= 0) +					{ +						int ht; +						y = wr.top; +						ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top); +						ske_AlphaBlend(hDest,wr.left,y,w,ht,mem2dc, 0, dy,w,ht,bf); +					} + +					y = wr.top+h-dy; +					while (y < wr.bottom-h) +					{ +						ske_AlphaBlend(hDest,wr.left,y,w,h,mem2dc, 0, 0, w,h,bf); +						y += h; +					} +					if (y <= wr.bottom) +						ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf); +				} +			} +		} +		SelectObject(mem2dc,oldbmp); +		DeleteObject(mem2bmp); +		DeleteDC(mem2dc); +	} +	else if (mode == FM_TILE_HORZ && (rGlyph->right-rGlyph->left>0) &&  (rGlyph->bottom-rGlyph->top>0) && (rFill->bottom-rFill->top)>0 && (rFill->right-rFill->left)>0) +	{ +		HDC mem2dc; +		RECT wr; +		HBITMAP mem2bmp,oldbmp; +		int w = rGlyph->right-rGlyph->left; +		int h = rFill->bottom-rFill->top; +		IntersectRect(&wr,rClip,rFill); +		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; +		h = wr.bottom-wr.top; +		mem2dc = CreateCompatibleDC(hDest); + +		mem2bmp = ske_CreateDIB32(w,h); +		oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); + +		if (!oldbmp) +			return 0; +		/// draw here +		{ +			int  x = 0, sy = 0, maxy = 0; +			{ +				//SetStretchBltMode(mem2dc, HALFTONE); +				//StretchBlt(mem2dc, 0, 0, w,h,hSource,rGlyph->left+(wr.left-rFill->left),rGlyph->top,w,h,SRCCOPY); + +				//                    BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 }; +				ske_AlphaBlend(mem2dc, 0, -(wr.top-rFill->top),w,rFill->bottom-rFill->top,hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf); +				if (drawMode == 0 || drawMode == 2) +				{ +					if (drawMode == 0) +					{ + +						int dx; +						dx = (wr.left-rFill->left)%w; +						if (dx >= 0) +						{ +							int wt; +							x = wr.left; +							wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); +							BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY); +						} +						x = wr.left+w-dx; +						while (x < wr.right-w){ +							BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY); +							x += w; +						} +						if (x <= wr.right) +						BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY); +					} +					else +					{ +						int dx; +						dx = (wr.left-rFill->left)%w; +						x = wr.left-dx; +						while (x < wr.right-w){ +							ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); +							x += w; +						} +						if (x <= wr.right) +							ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); +					} + +				} +				else +				{ +					BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; +					int dx; +					dx = (wr.left-rFill->left)%w; +					if (dx >= 0) +					{ +						int wt; +						x = wr.left; +						wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); +						ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf); +					} +					x = wr.left+w-dx; +					while (x < wr.right-w){ +						ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); +						x += w; +					} +					if (x <= wr.right) +						ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); + +				} +			} +		} +		SelectObject(mem2dc,oldbmp); +		DeleteObject(mem2bmp); +		DeleteDC(mem2dc); +	} +	else if (mode == FM_TILE_BOTH && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0)) +	{ +		HDC mem2dc; +		int w = rGlyph->right-rGlyph->left; +		int  x = 0, sy = 0, maxy = 0; +		int h = rFill->bottom-rFill->top; +		HBITMAP mem2bmp,oldbmp; +		RECT wr; +		IntersectRect(&wr,rClip,rFill); +		if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0; +		mem2dc = CreateCompatibleDC(hDest); +		mem2bmp = ske_CreateDIB32(w,wr.bottom-wr.top); +		h = wr.bottom-wr.top; +		oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp); +#ifdef _DEBUG +		if (!oldbmp) +			(NULL,"Tile bitmap not selected","ERROR", MB_OK); +#endif +		/// draw here +		{ + +			//fill temp bitmap +			{ +				int y; +				int dy; +				dy = (wr.top-rFill->top)%(rGlyph->bottom-rGlyph->top); +				y = -dy; +				while (y < wr.bottom-wr.top) +				{ + +					ske_AlphaBlend(mem2dc, 0, y,w,rGlyph->bottom-rGlyph->top, hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf); +					y += rGlyph->bottom-rGlyph->top; +				} + +				//-- +				//end temp bitmap +				if (drawMode == 0 || drawMode == 2) +				{ +					if (drawMode == 0) +					{ + +						int dx; +						dx = (wr.left-rFill->left)%w; +						if (dx >= 0) +						{ +							int wt; +							x = wr.left; +							wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); +							BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY); +						} +						x = wr.left+w-dx; +						while (x < wr.right-w){ +							BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY); +							x += w; +						} +						if (x <= wr.right) +						BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY); +					} +					else +					{ +						int dx; +						dx = (wr.left-rFill->left)%w; +						x = wr.left-dx; +						while (x < wr.right-w){ +							ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); +							x += w; +						} +						if (x <= wr.right) +							ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); +					} + +				} +				else +				{ +					BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + +					int dx; +					dx = (wr.left-rFill->left)%w; +					if (dx >= 0) +					{ +						int wt; +						x = wr.left; +						wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left); +						ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf); +					} +					x = wr.left+w-dx; +					while (x < wr.right-w){ +						ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf); +						x += w; +					} +					if (x <= wr.right) +						ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf); + +				} +			} + +		} +		SelectObject(mem2dc,oldbmp); +		DeleteObject(mem2bmp); +		DeleteDC(mem2dc); +	} +	return 1; + +} + +HBITMAP ske_CreateDIB32(int cx, int cy) +{ +	return ske_CreateDIB32Point(cx,cy,NULL); +} + +HBITMAP ske_CreateDIB32Point(int cx, int cy, void ** bits) +{ +	if (cx < 0 || cy < 0) +		return NULL; + +	BITMAPINFO RGB32BitsBITMAPINFO = { 0 }; +	RGB32BitsBITMAPINFO.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); +	RGB32BitsBITMAPINFO.bmiHeader.biWidth = cx;//bm.bmWidth; +	RGB32BitsBITMAPINFO.bmiHeader.biHeight = cy;//bm.bmHeight; +	RGB32BitsBITMAPINFO.bmiHeader.biPlanes = 1; +	RGB32BitsBITMAPINFO.bmiHeader.biBitCount = 32; +	// pointer used for direct Bitmap pixels access + +	UINT *ptPixels; +	HBITMAP DirectBitmap = CreateDIBSection(NULL, +		(BITMAPINFO *)&RGB32BitsBITMAPINFO, +		DIB_RGB_COLORS, +		(void **)&ptPixels, +		NULL, 0); +	if ((DirectBitmap == NULL || ptPixels == NULL) && cx != 0 && cy != 0) +	{ +#ifdef _DEBUG +		MessageBoxA(NULL,"Object not allocated. Check GDI object count","ERROR",MB_OK|MB_ICONERROR); +		DebugBreak(); +#endif +		; +	} +	else memset(ptPixels, 0, cx*cy*4); +	if (bits != NULL) *bits = ptPixels; +	return DirectBitmap; +} + +HRGN ske_CreateOpaqueRgn(BYTE Level, bool Opaque) +{ +	if (!g_pCachedWindow) +		return NULL; + +	RGBQUAD *buf = (RGBQUAD *) g_pCachedWindow->hImageDIBByte; +	if (buf == NULL) +		return NULL; + +	unsigned int cRect = 64; +	PRGNDATA pRgnData = (PRGNDATA)malloc(sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); +	memset(pRgnData, 0, sizeof(RGNDATAHEADER)); +	pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); +	pRgnData->rdh.iType = RDH_RECTANGLES; + +	for (int y = 0; y < g_pCachedWindow->Height; ++y) { +		bool inside = false; +		bool lastin = false; +		unsigned int entry = 0; + +		for (int x = 0; x < g_pCachedWindow->Width; ++x) { +			inside = Opaque ? (buf->rgbReserved > Level) : (buf->rgbReserved < Level); +			++buf; + +			if (inside != lastin) { +				if (inside) { +					lastin = true; +					entry = x; +				} +				else { +					if (pRgnData->rdh.nCount == cRect) { +						cRect = cRect + 64; +						pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); +					} +					SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, x, g_pCachedWindow->Height - y + 1); + +					pRgnData->rdh.nCount++; +					lastin = false; +				} +			} +		} + +		if (lastin) { +			if (pRgnData->rdh.nCount == cRect) { +				cRect = cRect + 64; +				pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT)); +			} +			SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, g_pCachedWindow->Width, g_pCachedWindow->Height - y + 1); + +			pRgnData->rdh.nCount++; +		} +	} +	 +	HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData); +	free(pRgnData); +	return hRgn; +} + +static int ske_DrawSkinObject(SKINDRAWREQUEST * preq, GLYPHOBJECT * pobj) +{ +	HDC memdc = NULL, glyphdc = NULL; +	int k = 0; +	//BITMAP bmp = {0}; +	HBITMAP membmp = 0, oldbmp = 0, oldglyph = 0; +	BYTE Is32Bit = 0; +	RECT PRect; +	POINT mode2offset = {0}; +	int depth = 0; +	int mode = 0; //0-FastDraw, 1-DirectAlphaDraw, 2-BufferedAlphaDraw + +	if (!(preq && pobj)) return -1; +	if ((!pobj->hGlyph || pobj->hGlyph == (HBITMAP)-1) && ((pobj->Style&7)  == ST_IMAGE  || (pobj->Style&7)  == ST_FRAGMENT ||  (pobj->Style&7)  == ST_SOLARIZE)) return 0; +	// Determine painting mode +	depth = GetDeviceCaps(preq->hDC,BITSPIXEL); +	depth = depth < 16?16:depth; +	Is32Bit = pobj->bmBitsPixel == 32; +	if ((!Is32Bit && pobj->dwAlpha == 255) &&  pobj->Style != ST_BRUSH) mode = 0; +	else if (pobj->dwAlpha == 255 && pobj->Style != ST_BRUSH) mode = 1; +	else mode = 2; +	// End painting mode + +	//force mode + +	if (preq->rcClipRect.bottom-preq->rcClipRect.top*preq->rcClipRect.right-preq->rcClipRect.left == 0) +		preq->rcClipRect = preq->rcDestRect; +	IntersectRect(&PRect,&preq->rcDestRect,&preq->rcClipRect); +	if (IsRectEmpty(&PRect)) +	{ +		return 0; +	} +	if (mode == 2) +	{ +		memdc = CreateCompatibleDC(preq->hDC); +		membmp = ske_CreateDIB32(PRect.right-PRect.left,PRect.bottom-PRect.top); +		oldbmp = (HBITMAP)SelectObject(memdc,membmp); +		if (oldbmp == NULL) +		{ +			if (mode == 2) +			{ +				SelectObject(memdc,oldbmp); +				DeleteDC(memdc); +				DeleteObject(membmp); +			} +			return 0; +		} +	} + +	if (mode != 2) memdc = preq->hDC; +	{ +		if (pobj->hGlyph && pobj->hGlyph != (HBITMAP)-1) +		{ +			glyphdc = CreateCompatibleDC(preq->hDC); +			if (!oldglyph) +				oldglyph = (HBITMAP)SelectObject(glyphdc,pobj->hGlyph); +			else +				SelectObject(glyphdc,pobj->hGlyph); +		} +		// Drawing +		{ +			RECT rFill, rGlyph, rClip; +			if ((pobj->Style&7)  == ST_BRUSH) +			{ +				HBRUSH br = CreateSolidBrush(pobj->dwColor); +				RECT fr; +				if (mode == 2) +				{ +					SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top); +					FillRect(memdc,&fr,br); +					ske_SetRectOpaque(memdc,&fr); +					// FillRectAlpha(memdc,&fr,pobj->dwColor|0xFF000000); +				} +				else +				{ +					fr = PRect; +					// SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top); +					FillRect(preq->hDC,&fr,br); +				} +				DeleteObject(br); +				k = -1; +			} +			else +			{ +				if (mode == 2) +				{ +					mode2offset.x = PRect.left; +					mode2offset.y = PRect.top; +					OffsetRect(&PRect,-mode2offset.x,-mode2offset.y); +				} +				rClip = (preq->rcClipRect); + +				{ +					int lft = 0; +					int top = 0; +					int rgh = pobj->bmWidth; +					int btm = pobj->bmHeight; +					if ((pobj->Style&7)  == ST_FRAGMENT) +					{ +						lft = pobj->clipArea.x; +						top = pobj->clipArea.y; +						rgh = min(rgh,lft+pobj->szclipArea.cx); +						btm = min(btm,top+pobj->szclipArea.cy); +					} + +					// Draw center... +					if (1) +					{ +						rFill.top = preq->rcDestRect.top+pobj->dwTop; +						rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom; +						rFill.left = preq->rcDestRect.left+pobj->dwLeft; +						rFill.right = preq->rcDestRect.right-pobj->dwRight; + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + +						rGlyph.top = top+pobj->dwTop; +						rGlyph.left = lft+pobj->dwLeft; +						rGlyph.right = rgh-pobj->dwRight; +						rGlyph.bottom = btm-pobj->dwBottom; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode,mode,depth); +					} + +					// Draw top side... +					if (1) +					{ +						rFill.top = preq->rcDestRect.top; +						rFill.bottom = preq->rcDestRect.top+pobj->dwTop; +						rFill.left = preq->rcDestRect.left+pobj->dwLeft; +						rFill.right = preq->rcDestRect.right-pobj->dwRight; + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + +						rGlyph.top = top+0; +						rGlyph.left = lft+pobj->dwLeft; +						rGlyph.right = rgh-pobj->dwRight; +						rGlyph.bottom = top+pobj->dwTop; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth); +					} +					// Draw bottom side... +					if (1) +					{ +						rFill.top = preq->rcDestRect.bottom-pobj->dwBottom; +						rFill.bottom = preq->rcDestRect.bottom; +						rFill.left = preq->rcDestRect.left+pobj->dwLeft; +						rFill.right = preq->rcDestRect.right-pobj->dwRight; + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + + +						rGlyph.top = btm-pobj->dwBottom; +						rGlyph.left = lft+pobj->dwLeft; +						rGlyph.right = rgh-pobj->dwRight; +						rGlyph.bottom = btm; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth); +					} +					// Draw left side... +					if (1) +					{ +						rFill.top = preq->rcDestRect.top+pobj->dwTop; +						rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom; +						rFill.left = preq->rcDestRect.left; +						rFill.right = preq->rcDestRect.left+pobj->dwLeft; + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + + +						rGlyph.top = top+pobj->dwTop; +						rGlyph.left = lft; +						rGlyph.right = lft+pobj->dwLeft; +						rGlyph.bottom = btm-pobj->dwBottom; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth); +					} + +					// Draw right side... +					if (1) +					{ +						rFill.top = preq->rcDestRect.top+pobj->dwTop; +						rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom; +						rFill.left = preq->rcDestRect.right-pobj->dwRight; +						rFill.right = preq->rcDestRect.right; + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + + +						rGlyph.top = top+pobj->dwTop; +						rGlyph.left = rgh-pobj->dwRight; +						rGlyph.right = rgh; +						rGlyph.bottom = btm-pobj->dwBottom; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth); +					} + + +					// Draw Top-Left corner... +					if (1) +					{ +						rFill.top = preq->rcDestRect.top; +						rFill.bottom = preq->rcDestRect.top+pobj->dwTop; +						rFill.left = preq->rcDestRect.left; +						rFill.right = preq->rcDestRect.left+pobj->dwLeft; + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + + +						rGlyph.top = top; +						rGlyph.left = lft; +						rGlyph.right = lft+pobj->dwLeft; +						rGlyph.bottom = top+pobj->dwTop; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); +					} +					// Draw Top-Right corner... +					if (1) +					{ +						rFill.top = preq->rcDestRect.top; +						rFill.bottom = preq->rcDestRect.top+pobj->dwTop; +						rFill.left = preq->rcDestRect.right-pobj->dwRight; +						rFill.right = preq->rcDestRect.right; + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + + +						rGlyph.top = top; +						rGlyph.left = rgh-pobj->dwRight; +						rGlyph.right = rgh; +						rGlyph.bottom = top+pobj->dwTop; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); +					} + +					// Draw Bottom-Left corner... +					if (1) +					{ +						rFill.top = preq->rcDestRect.bottom-pobj->dwBottom; +						rFill.bottom = preq->rcDestRect.bottom; +						rFill.left = preq->rcDestRect.left; +						rFill.right = preq->rcDestRect.left+pobj->dwLeft; + + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + + +						rGlyph.left = lft; +						rGlyph.right = lft+pobj->dwLeft; +						rGlyph.top = btm-pobj->dwBottom; +						rGlyph.bottom = btm; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); +					} +					// Draw Bottom-Right corner... +					if (1) +					{ +						rFill.top = preq->rcDestRect.bottom-pobj->dwBottom; +						rFill.bottom = preq->rcDestRect.bottom; +						rFill.left = preq->rcDestRect.right-pobj->dwRight; +						rFill.right = preq->rcDestRect.right; + + +						if (mode == 2) +							OffsetRect(&rFill,-mode2offset.x,-mode2offset.y); + +						rGlyph.left = rgh-pobj->dwRight; +						rGlyph.right = rgh; +						rGlyph.top = btm-pobj->dwBottom; +						rGlyph.bottom = btm; + +						k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth); +					} +				} + +			} + +			if ((k>0 || k == -1) && mode == 2) +			{ +				{ +					BLENDFUNCTION bf = {AC_SRC_OVER, 0, /*(bm.bmBitsPixel == 32)?255:*/pobj->dwAlpha, (pobj->bmBitsPixel == 32 && pobj->Style != ST_BRUSH)?AC_SRC_ALPHA:0}; +					if (mode == 2) +						OffsetRect(&PRect,mode2offset.x,mode2offset.y); +					ske_AlphaBlend( preq->hDC,PRect.left,PRect.top,PRect.right-PRect.left,PRect.bottom-PRect.top, +						memdc, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top,bf); +				} +			} +		} +		//free GDI resources +		//--++-- + +		//free GDI resources +		{ + +			if (oldglyph) SelectObject(glyphdc,oldglyph); +			if (glyphdc) DeleteDC(glyphdc); +		} +		if (mode == 2) +		{ +			SelectObject(memdc,oldbmp); +			DeleteDC(memdc); +			DeleteObject(membmp); +		} + +	} +	if (pobj->plTextList && pobj->plTextList->realCount>0) +	{ +		int i; +		HFONT hOldFont; +		for (i=0; i < pobj->plTextList->realCount; i++) +		{ +			GLYPHTEXT * gt = (GLYPHTEXT *)pobj->plTextList->items[i]; +			if (!gt->hFont) +			{ +				if (gl_plSkinFonts && gl_plSkinFonts->realCount>0) +				{ +					int j = 0; +					for (j = 0; j < gl_plSkinFonts->realCount; j++) +					{ +						SKINFONT * sf; +						sf = (SKINFONT*)gl_plSkinFonts->items[j]; +						if (sf->szFontID && !strcmp(sf->szFontID,gt->szFontID)) +						{ +							gt->hFont = sf->hFont; +							break; +						} +					} +				} +				if (!gt->hFont) gt->hFont = (HFONT)-1; +			} +			if (gt->hFont != (HFONT)-1) +			{ +				RECT rc = {0}; +				hOldFont = (HFONT)SelectObject(preq->hDC,gt->hFont); + + + +				if (gt->RelativeFlags&2) rc.left = preq->rcDestRect.right+gt->iLeft; +				else if (gt->RelativeFlags&1) rc.left = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iLeft; +				else rc.left = preq->rcDestRect.left+gt->iLeft; + +				if (gt->RelativeFlags&8) rc.top = preq->rcDestRect.bottom+gt->iTop; +				else if (gt->RelativeFlags&4) rc.top = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iTop; +				else rc.top = preq->rcDestRect.top+gt->iTop; + +				if (gt->RelativeFlags&32) rc.right = preq->rcDestRect.right+gt->iRight; +				else if (gt->RelativeFlags&16) rc.right = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iRight; +				else rc.right = preq->rcDestRect.left+gt->iRight; + +				if (gt->RelativeFlags&128) rc.bottom = preq->rcDestRect.bottom+gt->iBottom; +				else if (gt->RelativeFlags&64) rc.bottom = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iBottom; +				else rc.bottom = preq->rcDestRect.top+gt->iBottom; + +				ske_AlphaTextOut(preq->hDC, gt->stText, -1, &rc,gt->dwFlags, gt->dwColor); +				SelectObject(preq->hDC,hOldFont); +			} +		} +	} + +	return 0; +} + + + +int ske_AddDescriptorToSkinObjectList (LPSKINOBJECTDESCRIPTOR lpDescr, SKINOBJECTSLIST* Skin) +{ +	SKINOBJECTSLIST *sk; +	if (Skin) sk = Skin; else sk = &g_SkinObjectList; +	if (!sk) return 0; +	if (mir_bool_strcmpi(lpDescr->szObjectID,"_HEADER_")) return 0; +	{//check if new object allready presents. +		DWORD i=0; +		for (i=0; i < sk->dwObjLPAlocated; i++) +			if (!mir_strcmp(sk->pObjects[i].szObjectID,lpDescr->szObjectID)) return 0; +	} +	if (sk->dwObjLPAlocated+1>sk->dwObjLPReserved) +	{ // Realocated list to add space for new object + +		sk->pObjects = (SKINOBJECTDESCRIPTOR*)mir_realloc(sk->pObjects,sizeof(SKINOBJECTDESCRIPTOR)*(sk->dwObjLPReserved+1)/*alloc step*/); +		sk->dwObjLPReserved++; +	} +	{ //filling new objects field +		sk->pObjects[sk->dwObjLPAlocated].bType = lpDescr->bType; +		sk->pObjects[sk->dwObjLPAlocated].Data = NULL; +		sk->pObjects[sk->dwObjLPAlocated].szObjectID = mir_strdup(lpDescr->szObjectID); +		//  sk->Objects[sk->dwObjLPAlocated].szObjectName = mir_strdup(lpDescr->szObjectName); +		if (lpDescr->Data != NULL) +		{   //Copy defaults values +			switch (lpDescr->bType) +			{ +			case OT_GLYPHOBJECT: +				{ +					GLYPHOBJECT * obdat; +					GLYPHOBJECT * gl = (GLYPHOBJECT*)lpDescr->Data; +					sk->pObjects[sk->dwObjLPAlocated].Data = mir_alloc(sizeof(GLYPHOBJECT)); +					obdat = (GLYPHOBJECT*)sk->pObjects[sk->dwObjLPAlocated].Data; +					memcpy(obdat,gl,sizeof(GLYPHOBJECT)); +					if (gl->szFileName != NULL) +					{ +						obdat->szFileName = mir_strdup(gl->szFileName); +						mir_free_and_nil(gl->szFileName); +					} +					else obdat->szFileName = NULL; + +					obdat->hGlyph = NULL; +					break; +				} +			} + +		} +	} +	sk->dwObjLPAlocated++; +	return 1; +} + +static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin) +{ +	// DWORD i; +	SKINOBJECTSLIST* sk; +	sk = (Skin == NULL)?(&g_SkinObjectList):Skin; +	return skin_FindObjectByRequest((char *)szName,sk->pMaskList); +} + +static LPSKINOBJECTDESCRIPTOR ske_FindObjectByMask(MODERNMASK *pModernMask, BYTE objType, SKINOBJECTSLIST* Skin) +{ +	// DWORD i; +	SKINOBJECTSLIST* sk; +	sk = (Skin == NULL)?(&g_SkinObjectList):Skin; +	if (!sk->pMaskList) return NULL; +	return skin_FindObjectByMask(pModernMask,sk->pMaskList); +} + +LPSKINOBJECTDESCRIPTOR ske_FindObjectByName(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin) +{ +	DWORD i; +	SKINOBJECTSLIST* sk; +	sk = (Skin == NULL)?(&g_SkinObjectList):Skin; +	for (i=0; i < sk->dwObjLPAlocated; i++) +	{ +		if (sk->pObjects[i].bType == objType || objType == OT_ANY) +		{ +			if (!mir_strcmp(sk->pObjects[i].szObjectID,szName)) +				return &(sk->pObjects[i]); +		} +	} +	return NULL; +} + +////////////////////////////////////////////////////////////////////////// +// Paint glyph +// wParam - LPSKINDRAWREQUEST +// lParam - possible direct pointer to modern mask +////////////////////////////////////////////////////////////////////////// + +INT_PTR ske_Service_DrawGlyph(WPARAM wParam, LPARAM lParam) +{ +	LPSKINDRAWREQUEST preq; +	LPSKINOBJECTDESCRIPTOR pgl; +	LPGLYPHOBJECT gl; +	if (!wParam) return -1; +	ske_LockSkin(); +	__try +	{ +		preq = (LPSKINDRAWREQUEST)wParam; +		if (lParam) +			pgl = ske_FindObjectByMask((MODERNMASK*)lParam, OT_GLYPHOBJECT,NULL); +		else +			pgl = ske_FindObject(preq->szObjectID, OT_GLYPHOBJECT,NULL); +		if (pgl == NULL) return -1; +		if (pgl->Data == NULL) return -1; + +		gl = (LPGLYPHOBJECT)pgl->Data; +		int iStyle = gl->Style & 7; +		if (iStyle == ST_SKIP) +			return ST_SKIP; + +		if (gl->hGlyph == NULL && gl->hGlyph != (HBITMAP)-1 && (iStyle == ST_IMAGE || iStyle == ST_FRAGMENT || iStyle == ST_SOLARIZE)) +			if (gl->szFileName) { +				gl->hGlyph = ske_LoadGlyphImage( _A2T(gl->szFileName)); +				if (gl->hGlyph) { +					BITMAP bmp = {0}; +					GetObject(gl->hGlyph,sizeof(BITMAP),&bmp); +					gl->bmBitsPixel = (BYTE)bmp.bmBitsPixel; +					gl->bmHeight = bmp.bmHeight; +					gl->bmWidth = bmp.bmWidth; +				} +				else gl->hGlyph = (HBITMAP)-1; //invalid +			} +			return ske_DrawSkinObject(preq,gl); +	} +	__finally +	{ +		ske_UnlockSkin(); +	} +	return -1; +} + + +void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult) +{ +	BITMAP bmp; +	BOOL flag = FALSE; +	BYTE * pBitmapBits; +	DWORD Len; +	int bh,bw,y,x; + +	GetObject(hbmp, sizeof(BITMAP), (LPSTR)&bmp); +	bh = bmp.bmHeight; +	bw = bmp.bmWidth; +	Len = bh*bw*4; +	flag = (bmp.bmBits == NULL); +	if (flag) +	{ +		pBitmapBits = (LPBYTE)malloc(Len); +		GetBitmapBits(hbmp,Len,pBitmapBits); +	} +	else +		pBitmapBits = (BYTE*)bmp.bmBits; +	for (y = 0; y < bh; ++y) +	{ +		BYTE *pPixel = pBitmapBits + bw * 4 * y; + +		for (x = 0; x < bw ; ++x) +		{ +			if (Mult) +			{ +				pPixel[0] = pPixel[0]*pPixel[3]/255; +				pPixel[1] = pPixel[1]*pPixel[3]/255; +				pPixel[2] = pPixel[2]*pPixel[3]/255; +			} +			else +			{ +				pPixel[3] = 255; +			} +			pPixel += 4; +		} +	} +	if (flag) +	{ +		Len = SetBitmapBits(hbmp,Len,pBitmapBits); +		free (pBitmapBits); +	} +	return; +} + +int ske_GetFullFilename(TCHAR *buf, const TCHAR *file, TCHAR *skinfolder, BOOL madeAbsolute) +{ +	TCHAR *SkinPlace = db_get_tsa(NULL,SKIN,"SkinFolder"); +	if (SkinPlace == NULL) +		SkinPlace = mir_tstrdup( _T("\\Skin\\default")); + +	TCHAR b2[MAX_PATH]; +	if (file[0] != '\\' && file[1] != ':') +		mir_sntprintf(b2, MAX_PATH, _T("%s\\%s"), (skinfolder == NULL) ? SkinPlace : ((INT_PTR)skinfolder != -1) ? skinfolder : _T(""), file); +	else +		_tcsncpy(b2, file, SIZEOF(b2)); + +	if (madeAbsolute) { +		if (b2[0] == '\\' && b2[1] != '\\') +			PathToAbsoluteT(b2+1, buf); +		else +			PathToAbsoluteT(b2, buf); +	} +	else _tcsncpy(buf, b2, MAX_PATH); + +	mir_free(SkinPlace); +	return 0; +} + +/* +This function is required to load TGA to dib buffer myself +Major part of routines is from http://tfcduke.developpez.com/tutoriel/format/tga/fichiers/tga.c +*/ + +static BOOL ske_ReadTGAImageData(void * From, DWORD fromSize, BYTE * destBuf, DWORD bufSize, BOOL RLE) +{ +	BYTE * pos = destBuf; +	BYTE * from = fromSize?(BYTE*)From:NULL; +	FILE * fp = !fromSize?(FILE*)From:NULL; +	DWORD destCount = 0; +	DWORD fromCount = 0; +	if (!RLE) +	{ +		while (((from && fromCount < fromSize) || (fp &&  fromCount < bufSize)) +			 && (destCount < bufSize)) +		{ +			BYTE r = from?from[fromCount++]:(BYTE)fgetc(fp); +			BYTE g = from?from[fromCount++]:(BYTE)fgetc(fp); +			BYTE b = from?from[fromCount++]:(BYTE)fgetc(fp); +			BYTE a = from?from[fromCount++]:(BYTE)fgetc(fp); +			pos[destCount++] = r; +			pos[destCount++] = g; +			pos[destCount++] = b; +			pos[destCount++] = a; + +			if (destCount>bufSize) break; +			if (from) 	if (fromCount < fromSize) break; +		} +	} +	else +	{ +		BYTE rgba[4]; +		BYTE packet_header; +		BYTE *ptr = pos; +		BYTE size; +		int i; +		while (ptr < pos + bufSize) +		{ +			/* read first byte */ +			packet_header = from?from[fromCount]:(BYTE)fgetc(fp); +			if (from) from++; +			size = 1 + (packet_header & 0x7f); +			if (packet_header & 0x80) +			{ +				/* run-length packet */ +				if (from) +				{ +					*((DWORD*)rgba) = *((DWORD*)(from+fromCount)); +					fromCount += 4; +				} +				else fread (rgba, sizeof (BYTE), 4, fp); +				for (i=0; i < size; ++i, ptr += 4) +				{ +					ptr[2] = rgba[2]; +					ptr[1] = rgba[1]; +					ptr[0] = rgba[0]; +					ptr[3] = rgba[3]; +				} +			} +			else +			{	/* not run-length packet */ +				for (i=0; i < size; ++i, ptr += 4) +				{ +					ptr[0] = from? from[fromCount++]:(BYTE)fgetc (fp); +					ptr[1] = from? from[fromCount++]:(BYTE)fgetc (fp); +					ptr[2] = from? from[fromCount++]:(BYTE)fgetc (fp); +					ptr[3] = from? from[fromCount++]:(BYTE)fgetc (fp); +				} +			} +		} +	} +	return TRUE; +} + +static HBITMAP ske_LoadGlyphImage_TGA(const TCHAR *szFilename) +{ +	BYTE *colormap = NULL; +	int cx = 0, cy = 0; +	BOOL err = FALSE; +	tga_header_t header; +	if (!szFilename) return NULL; +	if (!wildcmpit(szFilename, _T("*\\*%.tga"))) { +		//Loading TGA image from file +		FILE *fp = _tfopen (szFilename, _T("rb")); +		if (!fp) { +			TRACEVAR("error: couldn't open \"%s\"!\n", szFilename); +			return NULL; +		} +		/* read header */ +		fread (&header, sizeof (tga_header_t), 1, fp); +		if ((header.pixel_depth != 32) || ((header.image_type != 10) && (header.image_type != 2))) { +			fclose(fp); +			return NULL; +		} + +		/*memory allocation */ +		colormap = (BYTE*)malloc(header.width*header.height*4); +		cx = header.width; +		cy = header.height; +		fseek (fp, header.id_lenght, SEEK_CUR); +		fseek (fp, header.cm_length, SEEK_CUR); +		err = !ske_ReadTGAImageData((void*)fp, 0, colormap, header.width*header.height*4,header.image_type == 10); +		fclose(fp); +	} +	else { +		/* reading from resources IDR_TGA_DEFAULT_SKIN */ +		DWORD size = 0; +		BYTE * mem; +		HGLOBAL hRes; +		HRSRC hRSrc = FindResourceA(g_hInst,MAKEINTRESOURCEA(IDR_TGA_DEFAULT_SKIN),"TGA"); +		if (!hRSrc) return NULL; +		hRes = LoadResource(g_hInst,hRSrc); +		if (!hRes) return NULL; +		size = SizeofResource(g_hInst,hRSrc); +		mem = (BYTE*) LockResource(hRes); +		if (size>sizeof(header)) +		{ +			tga_header_t * header = (tga_header_t *)mem; +			if (header->pixel_depth == 32 &&  (header->image_type == 2  || header->image_type == 10)) +			{ +				colormap = (BYTE*)malloc(header->width*header->height*4); +				cx = header->width; +				cy = header->height; +				ske_ReadTGAImageData((void*)(mem+sizeof(tga_header_t)+header->id_lenght+header->cm_length), size-(sizeof(tga_header_t)+header->id_lenght+header->cm_length), colormap, cx*cy*4,header->image_type == 10); +			} +		} +		FreeResource(hRes); +	} + +	if (colormap) { //create dib section +		BYTE * pt; +		HBITMAP hbmp = ske_CreateDIB32Point(cx,cy,(void**)&pt); +		if (hbmp) +			memcpy(pt,colormap,cx*cy*4); +		free(colormap); +		return hbmp; +	} +	return NULL; +} + + +//this function is required to load PNG to dib buffer myself +static HBITMAP ske_LoadGlyphImage_Png2Dib(const TCHAR *tszFilename) +{ +	HANDLE hFile, hMap = NULL; +	BYTE* ppMap = NULL; +	long  cbFileSize = 0; +	BITMAPINFOHEADER* pDib; +	BYTE* pDibBits; + +	if (!ServiceExists( MS_PNG2DIB )) { +		MessageBox( NULL, TranslateT("You need an image services plugin to process PNG images."), TranslateT("Error"), MB_OK ); +		return (HBITMAP)NULL; +	} + +	if ((hFile = CreateFile(tszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) +		if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL) +			if ((ppMap = ( BYTE* )MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL) +				cbFileSize = GetFileSize(hFile, NULL); + +	if (cbFileSize != 0) { +		PNG2DIB param; +		param.pSource = ppMap; +		param.cbSourceSize = cbFileSize; +		param.pResult = &pDib; +		if ( CallService(MS_PNG2DIB, 0, (LPARAM)¶m )) +			pDibBits = ( BYTE* )( pDib+1 ); +		else +			cbFileSize = 0; +	} + +	if ( ppMap != NULL )	UnmapViewOfFile( ppMap ); +	if ( hMap  != NULL )	CloseHandle( hMap ); +	if ( hFile != NULL ) CloseHandle( hFile ); + +	if ( cbFileSize == 0 ) +		return (HBITMAP)NULL; + +	HBITMAP hBitmap; +	BITMAPINFO* bi = ( BITMAPINFO* )pDib; +	BYTE *pt = (BYTE*)bi; +	pt += bi->bmiHeader.biSize; +	if (bi->bmiHeader.biBitCount != 32) { +		HDC sDC = GetDC( NULL ); +		hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS ); +		SelectObject( sDC, hBitmap ); +		DeleteDC( sDC ); +	} +	else { +		BYTE *ptPixels = pt; +		hBitmap = CreateDIBSection(NULL,bi, DIB_RGB_COLORS, (void **)&ptPixels,  NULL, 0); +		memcpy(ptPixels,pt,bi->bmiHeader.biSizeImage); +	} +	GlobalFree( pDib ); +	return hBitmap; +} + +static HBITMAP ske_LoadGlyphImageByDecoders(const TCHAR *tszFileName) +{ +	// Loading image from file by imgdecoder... +	HBITMAP hBitmap = NULL; +	TCHAR ext[5]; +	BYTE f = 0; +	LPVOID pImg = NULL; + +	BITMAP bmpInfo; +	{ +		int l = lstrlen(tszFileName); +		lstrcpyn(ext, tszFileName+(l-4),5); +	} +	if (!_tcschr(tszFileName,'%') && !PathFileExists(tszFileName)) +		return NULL; + +	if (mir_bool_tstrcmpi(ext, _T(".tga"))) { +		hBitmap = ske_LoadGlyphImage_TGA(tszFileName); +		f = 1; +	} +	else if ( ServiceExists("Image/Png2Dib") && mir_bool_tstrcmpi(ext, _T(".png"))) { +		hBitmap = ske_LoadGlyphImage_Png2Dib(tszFileName); +		GetObject(hBitmap, sizeof(BITMAP), &bmpInfo); +		f = (bmpInfo.bmBits != NULL); +	} +	else if (!mir_bool_tstrcmpi(ext, _T(".png"))) { +		hBitmap = (HBITMAP)CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)tszFileName); +	} + +	if (hBitmap) { +		GetObject(hBitmap, sizeof(BITMAP), &bmpInfo); +		if (bmpInfo.bmBitsPixel == 32) +			ske_PreMultiplyChanells(hBitmap,f); +		else { +			HDC dc24,dc32; +			HBITMAP hBitmap32,obmp24,obmp32; +			dc32 = CreateCompatibleDC(NULL); +			dc24 = CreateCompatibleDC(NULL); +			hBitmap32 = ske_CreateDIB32(bmpInfo.bmWidth,bmpInfo.bmHeight); +			obmp24 = (HBITMAP)SelectObject(dc24,hBitmap); +			obmp32 = (HBITMAP)SelectObject(dc32,hBitmap32); +			BitBlt(dc32, 0, 0, bmpInfo.bmWidth,bmpInfo.bmHeight,dc24, 0, 0, SRCCOPY); +			SelectObject(dc24,obmp24); +			SelectObject(dc32,obmp32); +			DeleteDC(dc24); +			DeleteDC(dc32); +			DeleteObject(hBitmap); +			hBitmap = hBitmap32; +			ske_PreMultiplyChanells(hBitmap,0); +		} +	} +	return hBitmap; +} + +static HBITMAP ske_skinLoadGlyphImage(const TCHAR *tszFileName) +{ +	if (!wildcmpit(tszFileName, _T("*.tga"))) +		return GDIPlus_LoadGlyphImage(tszFileName); + +	return ske_LoadGlyphImageByDecoders(tszFileName); +} + +HBITMAP ske_LoadGlyphImage(const TCHAR *tszFileName) +{ +	// try to find image in loaded +	DWORD i; +	HBITMAP hbmp; +	TCHAR szFile [MAX_PATH] = {0}; +	ske_GetFullFilename(szFile, tszFileName, g_SkinObjectList.szSkinPlace, TRUE); +	ske_LockSkin(); +	if (pLoadedImages) { +		for (i=0; i < dwLoadedImagesCount; i++) { +			if (mir_bool_tstrcmpi(pLoadedImages[i].szFileName, szFile)) { +				pLoadedImages[i].dwLoadedTimes++; +				ske_UnlockSkin(); +				return pLoadedImages[i].hGlyph; +			} +		} +	} +	// load new image +	hbmp = ske_skinLoadGlyphImage(szFile); +	if (hbmp == NULL) +	{ +		ske_UnlockSkin(); +		return NULL; +	} +	// add to loaded list +	if (dwLoadedImagesCount+1>dwLoadedImagesAlocated) +	{ +		pLoadedImages = (GLYPHIMAGE*)mir_realloc(pLoadedImages,sizeof(GLYPHIMAGE)*(dwLoadedImagesCount+1)); +		if (pLoadedImages) dwLoadedImagesAlocated++; +		else +		{ +			ske_UnlockSkin(); +			return NULL; +		} +	} +	pLoadedImages[dwLoadedImagesCount].dwLoadedTimes = 1; +	pLoadedImages[dwLoadedImagesCount].hGlyph = hbmp; +	pLoadedImages[dwLoadedImagesCount].szFileName = mir_tstrdup(szFile); +	dwLoadedImagesCount++; +	ske_UnlockSkin(); +	return hbmp; +} + +int ske_UnloadGlyphImage(HBITMAP hbmp) +{ +	DWORD i; +	for (i = 0; i < dwLoadedImagesCount && pLoadedImages; i ++) { +		if (hbmp != pLoadedImages[i].hGlyph) +			continue; +		pLoadedImages[i].dwLoadedTimes --; +		if (pLoadedImages[i].dwLoadedTimes == 0) { +			LPGLYPHIMAGE gl = &(pLoadedImages[i]); +			mir_free_and_nil(gl->szFileName); +			memmove(&(pLoadedImages[i]), &(pLoadedImages[i+1]), sizeof(GLYPHIMAGE)*(dwLoadedImagesCount-i-1)); +			dwLoadedImagesCount --; +			DeleteObject(hbmp); +			if (dwLoadedImagesCount == 0) { +				dwLoadedImagesAlocated = 0; +				mir_free_and_nil(pLoadedImages); +			} +		} +		return 0; +	} +	DeleteObject(hbmp); +	return 0; +} + +int ske_UnloadSkin(SKINOBJECTSLIST * Skin) +{ +	DWORD i; +	ske_LockSkin(); +	ClearMaskList(Skin->pMaskList); + +	//clear font list +	if (gl_plSkinFonts && gl_plSkinFonts->realCount > 0) { +		for (int i=0; i < gl_plSkinFonts->realCount; i++) { +			SKINFONT * sf = (SKINFONT *)gl_plSkinFonts->items[i]; +			if (sf) { +				mir_free(sf->szFontID); +				DeleteObject(sf->hFont); +				mir_free(sf); +			} +		} +		List_Destroy(gl_plSkinFonts); +		mir_free_and_nil(gl_plSkinFonts); +	} + +	mir_free_and_nil(Skin->szSkinPlace); +	if (Skin->pTextList) List_Destroy(Skin->pTextList); +	mir_free_and_nil(Skin->pTextList); +	ModernSkinButtonDeleteAll(); +	if (Skin->dwObjLPAlocated == 0) { ske_UnlockSkin(); return 0;} +	for (i=0; i < Skin->dwObjLPAlocated; i++) +	{ +		switch(Skin->pObjects[i].bType) +		{ +		case OT_GLYPHOBJECT: +			{ +				GLYPHOBJECT * dt; +				dt = (GLYPHOBJECT*)Skin->pObjects[i].Data; +				if (dt->hGlyph && dt->hGlyph != (HBITMAP)-1) +					ske_UnloadGlyphImage(dt->hGlyph); +				dt->hGlyph = NULL; +				mir_free_and_nil(dt->szFileName); +				{// delete texts +					int i; +					if (dt->plTextList && dt->plTextList->realCount>0) +					{ +						for (i=0; i < dt->plTextList->realCount; i++) +						{ +							GLYPHTEXT * gt = (GLYPHTEXT *)dt->plTextList->items[i]; +							if (gt) { +								mir_free(gt->stText); +								mir_free(gt->stValueText); +								mir_free(gt->szFontID); +								mir_free(gt->szGlyphTextID); +								mir_free(gt); +							} +						} +						List_Destroy(dt->plTextList); +						mir_free(dt->plTextList); +					} +				} +				mir_free(dt); +			} +			break; +		} +		mir_free_and_nil(Skin->pObjects[i].szObjectID); + +	} +	mir_free_and_nil(Skin->pObjects); +	Skin->pTextList = NULL; +	Skin->dwObjLPAlocated = 0; +	Skin->dwObjLPReserved = 0; +	ske_UnlockSkin(); +	return 0; +} + +static void RegisterMaskByParce(const char * szSetting, char * szValue, SKINOBJECTSLIST * pSkin) +{ +	int i; +	DWORD ID=atoi(szSetting+1); +	for (i=0; i < mir_strlen(szValue); i++)  if (szValue[i] == ':') break; +	if (i < mir_strlen(szValue)) +	{ +		char * Obj, *Mask; +		int res; +		Mask = szValue+i+1; +		Obj = (char*)mir_alloc(i+1); +		strncpy(Obj,szValue,i); +		Obj[i] = '\0'; +		res = AddStrModernMaskToList(ID,Mask,Obj,pSkin->pMaskList,pSkin); +		mir_free(Obj); +	} +} + +static int ske_ProcessLoadindString(const char * szSetting, char *szValue) +{ +	if (!pCurrentSkin) return 0; +	if (szSetting[0] == '$') +		RegisterObjectByParce((char *)szSetting, szValue); +	else if (szSetting[0] == '#') +		RegisterButtonByParce((char *)szSetting,szValue); +	else if (szSetting[0] == '@') +		RegisterMaskByParce((char *)szSetting,  szValue, pCurrentSkin); /// +	else if (szSetting[0] == 't') +		ske_AddParseTextGlyphObject((char*)szSetting,szValue,pCurrentSkin); +	else if (szSetting[0] == 'f') +		ske_AddParseSkinFont((char*)szSetting,szValue,pCurrentSkin); +	else return 0; +	return 1; +} +static int ske_enumdb_SkinObjectsProc (const char *szSetting,LPARAM lParam) +{ +	char *value; +	value = db_get_sa(NULL,SKIN,szSetting); +	ske_ProcessLoadindString(szSetting,value); +	mir_free_and_nil(value); + +	return 0; +} + +static int ske_SortTextGlyphObjectFunc(void * first, void * second) +{ +	return strcmp(((GLYPHTEXT*)(((int*)first)[0]))->szGlyphTextID,((GLYPHTEXT*)(((int*)second)[0]))->szGlyphTextID); +} + +static void ske_LinkSkinObjects(SKINOBJECTSLIST * pObjectList) +{ +	DWORD i; +	// LINK Mask with objects +	for (i=0; i < pObjectList->pMaskList->dwMaskCnt; i++) +	{ +		MODERNMASK *mm = &(pObjectList->pMaskList->pl_Masks[i]); +		void * pObject = (void*) ske_FindObjectByName(mm->szObjectName, OT_ANY, (SKINOBJECTSLIST*) pObjectList); +		mir_free_and_nil(mm->szObjectName); +		mm->bObjectFound = TRUE; +		mm->pObject = pObject; +	} + +	if (pObjectList->pTextList) +	{ +		int i; +		// LINK Text with objects +		for (i=0; i < pObjectList->pTextList->realCount; i++) +		{ +			GLYPHTEXT * glText; +			GLYPHOBJECT *globj = NULL; +			SKINOBJECTDESCRIPTOR * lpobj; +			glText = (GLYPHTEXT *)pObjectList->pTextList->items[i]; +			lpobj = ske_FindObjectByName(glText->szObjectName,OT_GLYPHOBJECT, pObjectList); +			mir_free_and_nil(glText->szObjectName); +			if (lpobj) +				globj = (GLYPHOBJECT*)lpobj->Data; +			if (globj) +			{ +				if (!globj->plTextList) +				{ +					globj->plTextList = List_Create(0, 1); +					globj->plTextList->sortFunc = ske_SortTextGlyphObjectFunc; +				} +				List_Insert(globj->plTextList,(void*)glText,globj->plTextList->realCount); +				qsort(globj->plTextList->items,globj->plTextList->realCount,sizeof(void*),(int(*)(const void*, const void*))globj->plTextList->sortFunc); +				pObjectList->pTextList->items[i] = NULL; +			} +			else +			{ +				GLYPHTEXT *gt = glText; +				if (gt) { +					mir_free(gt->stText); +					mir_free(gt->stValueText); +					mir_free(gt->szFontID); +					mir_free(gt->szGlyphTextID); +					mir_free(gt); +				} +			} +		} +		List_Destroy(pObjectList->pTextList); +		mir_free_and_nil(pObjectList->pTextList); +	} +} +// Getting skin objects and masks from DB +static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin) +{ +	if (Skin == NULL) return 0; +	ske_UnloadSkin(Skin); +	g_CluiData.fDisableSkinEngine = db_get_b(NULL,"ModernData","DisableEngine", SETTING_DISABLESKIN_DEFAULT); +	//window borders +	if (g_CluiData.fDisableSkinEngine) { +		g_CluiData.LeftClientMargin = 0; +		g_CluiData.RightClientMargin = 0; +		g_CluiData.TopClientMargin = 0; +		g_CluiData.BottomClientMargin = 0; +	} else { +		//window borders +		g_CluiData.LeftClientMargin = (int)db_get_b(NULL,"CLUI","LeftClientMargin",SETTING_LEFTCLIENTMARIGN_DEFAULT); +		g_CluiData.RightClientMargin = (int)db_get_b(NULL,"CLUI","RightClientMargin",SETTING_RIGHTCLIENTMARIGN_DEFAULT); +		g_CluiData.TopClientMargin = (int)db_get_b(NULL,"CLUI","TopClientMargin",SETTING_TOPCLIENTMARIGN_DEFAULT); +		g_CluiData.BottomClientMargin = (int)db_get_b(NULL,"CLUI","BottomClientMargin",SETTING_BOTTOMCLIENTMARIGN_DEFAULT); +	} + +	if (g_CluiData.fDisableSkinEngine) return 0; + +	Skin->pMaskList = (LISTMODERNMASK*)mir_alloc(sizeof(LISTMODERNMASK)); +	memset(Skin->pMaskList, 0, sizeof(LISTMODERNMASK)); +	Skin->szSkinPlace = db_get_tsa(NULL, SKIN, "SkinFolder"); +	if (!Skin->szSkinPlace || (_tcschr(Skin->szSkinPlace, '%') && !db_get_b(NULL,SKIN,"Modified",0))) +	{ +		BOOL bOnlyObjects = FALSE; +		if (Skin->szSkinPlace && _tcschr(Skin->szSkinPlace, '%')) +			bOnlyObjects = TRUE; +		mir_free(Skin->szSkinPlace); +		Skin->szSkinPlace = mir_tstrdup( _T("%Default%")); +		ske_LoadSkinFromResource( bOnlyObjects ); +	} +	//Load objects +	{ +		DBCONTACTENUMSETTINGS dbces; +		pCurrentSkin = Skin; +		dbces.pfnEnumProc = ske_enumdb_SkinObjectsProc; +		dbces.szModule = SKIN; +		dbces.ofsSettings = 0; +		CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces); + +		SortMaskList(pCurrentSkin->pMaskList); +		ske_LinkSkinObjects(pCurrentSkin); +	} +	//Load Masks +	return 0; +} + +//surrogate to be called from outside +void ske_LoadSkinFromDB(void) +{ +	ske_GetSkinFromDB(SKIN,&g_SkinObjectList); +	g_CluiData.dwKeyColor = db_get_dw(NULL,"ModernSettings","KeyColor",(DWORD)SETTING_KEYCOLOR_DEFAULT); +} + +// + +static int ske_LoadSkinFromResource(BOOL bOnlyObjects) +{ +	IniParser parser(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF", bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS); +	if (parser.CheckOK()) { +		ske_DeleteAllSettingInSection("ModernSkin"); +		db_set_s(NULL, SKIN, "SkinFolder", "%Default%"); +		db_set_s(NULL, SKIN, "SkinFile", "%Default%"); +		parser.Parse(IniParser::WriteStrToDb, 0); +	} +	return 0; +} + +//Load data from ini file +int ske_LoadSkinFromIniFile(TCHAR *szFileName, BOOL bOnlyObjects) +{ +	if (_tcschr(szFileName,_T('%'))) +		return ske_LoadSkinFromResource( bOnlyObjects ); + +	IniParser parser(szFileName, bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS); +	if (!parser.CheckOK()) +		return 0; + +	ske_DeleteAllSettingInSection("ModernSkin"); + +	TCHAR skinFolder[MAX_PATH], skinFile[MAX_PATH]; +	IniParser::GetSkinFolder(szFileName, skinFolder); +	PathToRelativeT(szFileName, skinFile); + +	db_set_ts(NULL,SKIN,"SkinFolder", skinFolder); +	db_set_ts(NULL,SKIN,"SkinFile", skinFile); + +	parser.Parse(IniParser::WriteStrToDb, 1); +	return 0; +} + +static int ske_enumdb_SkinSectionDeletionProc (const char *szSetting,LPARAM lParam) +{ +	if (szSetting == NULL) +		return 0; + +	nArrayLen++; +	pszSettingName = (char **)realloc(pszSettingName, nArrayLen*sizeof(char *)); +	pszSettingName[nArrayLen-1] = _strdup(szSetting); +	return 0; +} + +static int ske_DeleteAllSettingInSection(char * SectionName) +{ +	DBCONTACTENUMSETTINGS dbces; +	nArrayLen = 0; +	pszSettingName = NULL; +	dbces.pfnEnumProc = ske_enumdb_SkinSectionDeletionProc; +	dbces.szModule = SectionName; +	dbces.ofsSettings = 0; + +	CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces); + +	//delete all settings +	if (nArrayLen == 0) +		return 0; + +	for (int i=0; i < nArrayLen; i++) { +		db_unset(0, SectionName,pszSettingName[i]); +		free(pszSettingName[i]); +	} +	free(pszSettingName); +	pszSettingName = NULL; +	nArrayLen = 0; +	return 0; +} + +BOOL ske_TextOut(HDC hdc, int x, int y, LPCTSTR lpString, int nCount) +{ +	SIZE sz; +	GetTextExtentPoint32(hdc, lpString, nCount, &sz); +	int ta = GetTextAlign(hdc); + +	RECT rc = { 0 }; +	SetRect(&rc, x, y, x + sz.cx, y + sz.cy); +	ske_DrawText(hdc, lpString, nCount, &rc, DT_NOCLIP | DT_SINGLELINE | DT_LEFT); +	return 1; +} + +static INT_PTR ske_Service_AlphaTextOut(WPARAM wParam, LPARAM lParam) +{ +	if (!wParam) return 0; + +	AlphaTextOutParams ap = *(AlphaTextOutParams*)wParam; +	return ske_AlphaTextOut(ap.hDC,ap.lpString,ap.nCount,ap.lpRect,ap.format,ap.ARGBcolor); +} + +static __inline void ske_SetMatrix( sbyte * matrix, +	sbyte a, sbyte b, sbyte c, +	sbyte d, sbyte e, sbyte f, +	sbyte g, sbyte h, sbyte i) +{ +	matrix[0] = a;	matrix[1] = b;	matrix[2] = c; +	matrix[3] = d;	matrix[4] = e;	matrix[5] = f; +	matrix[6] = g;	matrix[7] = h;	matrix[8] = i; +} + +static void ske_SetTextEffect(BYTE EffectID, DWORD FirstColor, DWORD SecondColor) +{ +	if (EffectID > MAXPREDEFINEDEFFECTS) return; +	if (EffectID == -1) meCurrentEffect.EffectID = -1; +	else { +		meCurrentEffect.EffectID = EffectID; +		meCurrentEffect.EffectMatrix = ModernEffectsEnum[EffectID]; +		meCurrentEffect.EffectColor1 = FirstColor; +		meCurrentEffect.EffectColor2 = SecondColor; +	} +} + +bool ske_ResetTextEffect(HDC hdc) +{ +	int idx = arEffectStack.getIndex((EFFECTSSTACKITEM*)&hdc); +	if (idx == -1) +		return false; + +	mir_free(arEffectStack[idx]); +	arEffectStack.remove(idx); +	return true; +} + +bool ske_SelectTextEffect(HDC hdc, BYTE EffectID, DWORD FirstColor, DWORD SecondColor) +{ +	if (EffectID > MAXPREDEFINEDEFFECTS) +		return false; + +	if (EffectID == -1) +		return ske_ResetTextEffect(hdc); + +	EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc); +	if (effect == NULL) { +		effect = (EFFECTSSTACKITEM *)mir_alloc(sizeof(EFFECTSSTACKITEM)); +		effect->hdc = hdc; +		arEffectStack.insert(effect); +	} + +	effect->EffectID = EffectID; +	effect->FirstColor = FirstColor; +	effect->SecondColor = SecondColor; +	return true; +} + +static bool ske_GetTextEffect(HDC hdc, MODERNEFFECT *modernEffect) +{ +	if (!modernEffect) +		return false; + +	EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc); +	if (effect == NULL) +		return false; + +	modernEffect->EffectID = effect->EffectID; +	modernEffect->EffectColor1 = effect->FirstColor; +	modernEffect->EffectColor2 = effect->SecondColor; +	modernEffect->EffectMatrix = ModernEffectsEnum[effect->EffectID]; +	return true; +} + +static bool ske_DrawTextEffect(BYTE* destPt, BYTE* maskPt, DWORD width, DWORD height, MODERNEFFECT *effect) +{ +	sbyte *buf; +	sbyte *outbuf; +	sbyte *bufline, *buflineTop, *buflineMid; +	int sign = 0; +	BYTE *maskline,*destline; +	BYTE al,rl,gl,bl,ad,rd,gd,bd; +	int k = 0; +	DWORD x,y; +	sbyte *matrix; +	BYTE mcTopStart; +	BYTE mcBottomEnd; +	BYTE mcLeftStart; +	BYTE mcRightEnd; +	BYTE effectCount; +	int minX = width; +	int maxX = 0; +	int minY = height; +	int maxY = 0; +	if (effect->EffectID == 0xFF) return false; +	if (!width || !height) return false; +	if (!destPt) return false; +	buf = (sbyte*)malloc(width*height*sizeof(BYTE)); +	{ +		matrix = effect->EffectMatrix.matrix; +		mcTopStart = 2-effect->EffectMatrix.topEffect; +		mcBottomEnd = 3+effect->EffectMatrix.bottomEffect; +		mcLeftStart = 2-effect->EffectMatrix.leftEffect; +		mcRightEnd = 3+effect->EffectMatrix.rightEffect; +		effectCount = effect->EffectMatrix.cycleCount; +	} +	al = 255-((BYTE)(effect->EffectColor1>>24)); +	rl = GetRValue(effect->EffectColor1); +	gl = GetGValue(effect->EffectColor1); +	bl = GetBValue(effect->EffectColor1); +	ad = 255-((BYTE)(effect->EffectColor2>>24)); +	rd = GetRValue(effect->EffectColor2); +	gd = GetGValue(effect->EffectColor2); +	bd = GetBValue(effect->EffectColor2); + +	//Fill buffer by mid values of image +	for (y = 0; y < height; y++) +	{ +		bufline = buf+y*width; +		maskline = maskPt+((y*width) << 2); +		for (x = 0; x < width; x++) +		{ +			BYTE a = (sbyte)(DWORD)((maskline[0]+maskline[2]+maskline[1]+maskline[1])>>4); +			*bufline = a; +			if (a != 0) +			{ +				minX = min((int)x,minX); +				minY = min((int)y,minY); +				maxX = max((int)x,maxX); +				maxY = max((int)y,maxY); +			} +			bufline++; +			maskline += 4; +		} +	} +	//Here perform effect on buffer and place results to outbuf +	for (k = 0; k < (effectCount&0x7F); k++) +	{ +		minX = max( 0,         minX + mcLeftStart - 2 ); +		minY = max( 0,         minY + mcTopStart  - 2 ); +		maxX = min((int)width,  maxX + mcRightEnd  - 1 ); +		maxY = min((int)height, maxY + mcBottomEnd - 1 ); + +		outbuf = (sbyte*)malloc(width*height*sizeof(sbyte)); +		memset(outbuf, 0, width*height*sizeof(sbyte)); +		for (y = (DWORD)minY; y < (DWORD)maxY; y++) +		{ +			int val; +			bufline = outbuf+y*width+minX; +			buflineMid = buf+y*width+minX; +			for (x = (DWORD)minX; x < (DWORD)maxX; x++) +			{ +				int matrixHor,matrixVer; +				val = 0; +				for (matrixVer = mcTopStart; matrixVer < mcBottomEnd; matrixVer++) +				{ +					int buflineStep = width*(matrixVer-2); +					int as = y+matrixVer-2; +					sbyte * buflineTopS = NULL; +					if (as >= 0 && (DWORD)as < height) buflineTopS = buflineMid+buflineStep; + +					for (matrixHor = mcLeftStart; matrixHor < mcRightEnd;matrixHor++) +					{ +						buflineTop = buflineTopS; +						int a = x+matrixHor-2; +						if (buflineTop && a >= 0 && (DWORD)a < width) buflineTop += matrixHor-2; +						else buflineTop = NULL; +						if (buflineTop) +							val += ((*buflineTop)*matrix[matrixVer*5+matrixHor]); +					} +				} +				val = (val+1)>>5; +				*bufline = (sbyte)((val>127)?127:(val < -125)?-125:val); +				bufline++; +				buflineMid++; +			} +		} +		free(buf); +		buf = outbuf; +	} +	{ +		BYTE r1,b1,g1,a1; +		b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1; +		//perform out to dest +		for (y = 0; y < height; y++) +		{ +			bufline = buf+y*width; +			destline = destPt+((y*width) << 2); +			for (x = 0; x < width; x++) +			{ +				sbyte val = *bufline; +				BYTE absVal = ((val < 0)?-val:val); + +				if (val != 0) +				{ +					if (val>0 && sign < 0) +					{ b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1;} +					else if (val < 0 && sign>0) +					{ b1 = bd; r1 = rd; g1 = gd; a1 = ad; sign = -1;} + +					absVal = absVal*a1/255; + +					destline[0] = ((destline[0]*(128-absVal))+absVal*b1)>>7; +					destline[1] = ((destline[1]*(128-absVal))+absVal*g1)>>7; +					destline[2] = ((destline[2]*(128-absVal))+absVal*r1)>>7; +					destline[3] += ((255-destline[3])*(a1*absVal))/32640; +				} +				bufline++; +				destline += 4; +			} +		} +		free(buf); +	} +	return false; +} + +static int ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor) +{ +	if (!(lpString && lpRect)) +		return 0; + +	// Step first fill fast calc correction tables: +	static bool _tables_empty = true; +	static BYTE gammaTbl[256];			// Gamma correction table +	static WORD blueMulTbl[256];		// blue  coefficient multiplication table +	static WORD greenMulTbl[256];		// green coefficient multiplication table +	static WORD redMulTbl[256];			// red   coefficient multiplication table +	if ( _tables_empty ) +	{ +		// fill tables +		double gammaCfPw = 1000 / (double)DBGetContactSettingRangedWord(NULL,"ModernData","AlphaTextOutGamma", 700, 1, 5000 ); +		BYTE blueCf    = db_get_b(NULL,"ModernData","AlphaTextOutBlueCorrection", 28 ); +		BYTE redCf     = db_get_b(NULL,"ModernData","AlphaTextOutRed Correction", 77 ); +		BYTE greenCf   = db_get_b(NULL,"ModernData","AlphaTextOutGreen Correction", 151 ); + +		for ( int i=0; i < 256; i++ ) { +			gammaTbl[i] = (BYTE)( 255 * pow((double)i / 255, gammaCfPw )); +			blueMulTbl[i] = i * blueCf; +			redMulTbl[i] = i * redCf; +			greenMulTbl[i] = i * greenCf; +		} +	} + +	// Calc len of input string +	if (nCount == -1) +		nCount = lstrlen(lpString); + +	// retrieve destination bitmap bits +	HBITMAP hDestBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP); +	BITMAP  bmpDest; +	GetObject(hDestBitmap, sizeof(BITMAP), &bmpDest); + +	BOOL destHasNotDIB = FALSE; +	BYTE *pDestBits = NULL; +	if (bmpDest.bmBits == NULL) { +		destHasNotDIB = TRUE; +		pDestBits = (BYTE*) malloc ( bmpDest.bmHeight * bmpDest.bmWidthBytes ); +		GetBitmapBits( hDestBitmap, bmpDest.bmHeight*bmpDest.bmWidthBytes, pDestBits ); +	} +	else pDestBits = (BYTE*)bmpDest.bmBits; + +	BOOL isDest16bit = (bmpDest.bmBitsPixel) != 32; + +	// Creating offscreen buffer +	HDC hOffscreenDC = CreateCompatibleDC(hDC); + +	// Font to be used to draw text +	HFONT hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT); +	HFONT hOldOffscreenFont = (HFONT)SelectObject(hOffscreenDC, hFont); + +	// Calculating text geometric size +	RECT workRect = *lpRect; +	int workRectWidth = workRect.right - workRect.left; +	int workRectHeight = workRect.bottom - workRect.top; +	if (workRectWidth <= 0 || workRectHeight <= 0) +		return 0; + +	SIZE textSize; +	GetTextExtentPoint32( hOffscreenDC, lpString, nCount, &textSize ); + +	LPCTSTR lpWorkString = lpString; +	BOOL bNeedFreeWorkString = FALSE; + +	// if we need to cut the text with ellipsis +	if ((format & DT_END_ELLIPSIS) && textSize.cx > workRectWidth) { +		// Calc geometric width of ellipsis +		SIZE szEllipsis; +		GetTextExtentPoint32A(hOffscreenDC,"...",3,&szEllipsis); +		szEllipsis.cx++;                                          // CORRECTION: some width correction + +		// Calc count of visible chars +		int visibleCharCount = nCount; +		if (workRectWidth > szEllipsis.cx) +			GetTextExtentExPoint(hOffscreenDC, lpString, nCount, workRectWidth - szEllipsis.cx, &visibleCharCount, NULL, &textSize); +		else +			GetTextExtentExPoint(hOffscreenDC, lpString, nCount, 0, &visibleCharCount, NULL, &textSize); + +		// replace end of string by elipsis +		bNeedFreeWorkString = TRUE; +		lpWorkString = (TCHAR*) malloc(( visibleCharCount + 4) * sizeof(TCHAR)); + +		memcpy((void*) lpWorkString, lpString, visibleCharCount * sizeof(TCHAR)); +		memcpy((void*) ( lpWorkString + visibleCharCount ), _T("..."), 4 * sizeof(TCHAR)); // 3 + 1 + +		nCount = visibleCharCount + 3; +	} + +	// Calc sizes and offsets + +	textSize.cx += 2;             // CORRECTION: for italic + +	int drx = 0;                  // x-axis offset of draw point + +	if (workRectWidth > textSize.cx) { +		if ( format & ( DT_RIGHT | DT_RTLREADING )) +			drx = workRectWidth - textSize.cx; +		else if ( format & DT_CENTER ) +			drx = ( workRectWidth - textSize.cx ) >> 1; +	} +	else textSize.cx = workRectWidth; + +	int dry = 0;                  // y-axis offset of draw point + +	if (workRectHeight > textSize.cy) { +		if (format & DT_BOTTOM) +			dry = workRectHeight - textSize.cy; +		else if (format & DT_VCENTER) +			dry = (workRectHeight - textSize.cy) >> 1; +	} +	else textSize.cy = workRectHeight; + +	textSize.cx += 4;    // CORRECTION: for effects ??? +	textSize.cy += 4;	 // CORRECTION: for effects ??? + +	if (textSize.cx > 0 && textSize.cy > 0) { // Ok we need to paint +		// probably here are mess ofscreen and temp buff dc + +		//Create bitmap image for offscreen +		BYTE *bits = NULL; +		HBITMAP hbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bits); +		if (bits != NULL) { +			HBITMAP holdbmp = (HBITMAP)SelectObject( hOffscreenDC, hbmp ); + +			//Create buffer bitmap image for temp text +			BYTE *bufbits = NULL; +			HBITMAP bufbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bufbits); +			if ( bufbits != NULL ) { +				HDC     bufDC = CreateCompatibleDC(hDC); +				HBITMAP bufoldbmp = (HBITMAP)SelectObject(bufDC, bufbmp); +				HFONT   hOldBufFont = (HFONT)SelectObject(bufDC, hFont); +				SetBkColor(bufDC, RGB(0, 0, 0)); +				SetTextColor(bufDC, RGB(255, 255, 255)); + +				// Copy from destination to temp buffer +				BitBlt(hOffscreenDC, 0, 0, textSize.cx, textSize.cy, hDC, workRect.left + drx - 2, workRect.top + dry - 2, SRCCOPY); + +				//Draw text on offscreen bitmap +				TextOut(bufDC, 2, 2, lpWorkString, nCount); + +				MODERNEFFECT effect; +				if (ske_GetTextEffect(hDC, &effect)) +					ske_DrawTextEffect(bits, bufbits, textSize.cx, textSize.cy, &effect); + +				// RenderText +				RECT drawRect; +				drawRect.left = 0; drawRect.top = 0; +				drawRect.right = textSize.cx; +				drawRect.bottom = textSize.cy; + +				DWORD width = textSize.cx; +				DWORD heigh = textSize.cy; + +				BYTE *pDestScanLine; +				BYTE *pBufScanLine; +				BYTE *pix; +				BYTE *bufpix; + +				BYTE al = 255 - ((BYTE)( ARGBcolor >> 24 )); +				BYTE r = GetRValue( ARGBcolor ); +				BYTE g = GetGValue( ARGBcolor ); +				BYTE b = GetBValue( ARGBcolor ); + +				for (DWORD y = 2; y < heigh - 2; y++) { +					int lineBytes = y * (width << 2); + +					pDestScanLine = bits + lineBytes; +					pBufScanLine  = bufbits + lineBytes; + +					for (DWORD x = 2; x < width - 2; x++) { +						pix    = pDestScanLine + ( x << 2 ); +						bufpix = pBufScanLine  + ( x << 2 ); + +						// Monochromatic +						BYTE bx = gammaTbl[ bufpix[0] ]; +						BYTE gx = gammaTbl[ bufpix[1] ]; +						BYTE rx = gammaTbl[ bufpix[2] ]; + +						if ( al != 255 ) { +							bx *= al/255; +							gx *= al/255; +							rx *= al/255; +						} + +						BYTE ax = (BYTE)(( (DWORD)rx*77 + (DWORD)gx * 151 + (DWORD)bx *28 + 128 ) / 256 ); +						if (ax) { +							//Normalize components to gray +							BYTE axx = 255 - (( r + g + b ) >> 2 ) ; // Coefficient of grayance, more white font - more gray edges +							WORD atx = ax * (255 - axx); +							bx = ( atx + bx * axx )/255; +							gx = ( atx + gx * axx )/255; +							rx = ( atx + rx * axx )/255; + +							short brx = (short)((b - pix[0])*bx / 255); +							short grx = (short)((g - pix[1])*gx / 255); +							short rrx = (short)((r - pix[2])*rx / 255); + +							pix[0] += brx; +							pix[1] += grx; +							pix[2] += rrx; +							pix[3] = (BYTE)(ax+(BYTE)(255-ax)*pix[3]/255); +						} +					} +				} + +				// Blit to destination +				BitBlt(hDC, workRect.left + drx - 2, workRect.top + dry - 2, textSize.cx, textSize.cy, hOffscreenDC, 0, 0, SRCCOPY); + +				//free resources +				SelectObject(bufDC, bufoldbmp); +				DeleteObject(bufbmp); +				SelectObject(bufDC, hOldBufFont); +				DeleteDC(bufDC); +			} +			SelectObject(hOffscreenDC, holdbmp); +			DeleteObject(hbmp); +		} +	} + +	// Final cleanup +	SelectObject(hOffscreenDC, hOldOffscreenFont); +	DeleteDC(hOffscreenDC); + +	if (destHasNotDIB) +		free(pDestBits); + +	if (bNeedFreeWorkString) +		free((void*)lpWorkString); + +	return 0; +} + +static int ske_DrawTextWithEffectWorker( HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, MODERNFONTEFFECT * effect ) +{ +	if (format & DT_CALCRECT) +		return DrawText(hdc, lpString, nCount, lpRect, format); + +	if (format & DT_RTLREADING) +		SetTextAlign(hdc, TA_RTLREADING); + +	DWORD color = GetTextColor(hdc); +	RECT r = *lpRect; +	OffsetRect(&r, 1, 1); +	DWORD form = format; +	if (effect && effect->effectIndex) +		ske_SelectTextEffect(hdc, effect->effectIndex - 1, effect->baseColour, effect->secondaryColour); + +	int res = ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color); + +	if (effect && effect->effectIndex) +		ske_ResetTextEffect(hdc); + +	return res; +} + +INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam) +{ +	DrawTextWithEffectParam *p = (DrawTextWithEffectParam *)wParam; +	if (p->cbSize != sizeof(DrawTextWithEffectParam)) +		return FALSE; +	return ske_DrawTextWithEffectWorker(p->hdc, p->lpchText, p->cchText, p->lprc, p->dwDTFormat, p->pEffect); +} + +BOOL ske_DrawText(HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format) +{ +	DWORD form = 0, color = 0; +	RECT r = *lpRect; +	OffsetRect(&r, 1, 1); +	if (format & DT_RTLREADING) SetTextAlign(hdc, TA_RTLREADING); +	if (format & DT_CALCRECT) return DrawText(hdc, lpString, nCount, lpRect, format); +	if (format & DT_FORCENATIVERENDER || g_CluiData.fDisableSkinEngine) +		return DrawText(hdc, lpString, nCount, lpRect, format&~DT_FORCENATIVERENDER); + +	form = format; +	color = GetTextColor(hdc); +	return ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color); +} + +HICON ske_ImageList_GetIcon(HIMAGELIST himl, int i, UINT fStyle) +{ +	IMAGEINFO imi = {0}; +	BITMAP bm = {0}; +	if (i != -1) { +		ImageList_GetImageInfo(himl,i,&imi); +		GetObject(imi.hbmImage,sizeof(bm),&bm); +		if (bm.bmBitsPixel == 32) //stupid bug of Microsoft +			// Icons bitmaps are not premultiplied +			// So Imagelist_AddIcon - premultiply alpha +			// But incorrect - it is possible that alpha will +			// be less than color and +			// ImageList_GetIcon will return overflowed colors +			// TODO: Direct draw Icon from imagelist without +			// extracting of icon +		{ +			BYTE *bits = (BYTE*)bm.bmBits; +			if (!bits) { +				bits = (BYTE*)malloc(bm.bmWidthBytes*bm.bmHeight); +				GetBitmapBits(imi.hbmImage,bm.bmWidthBytes*bm.bmHeight,bits); +			} + +			int wb = ((imi.rcImage.right - imi.rcImage.left)*bm.bmBitsPixel >> 3); +			BYTE *bcbits = bits + (bm.bmHeight - imi.rcImage.bottom)*bm.bmWidthBytes + (imi.rcImage.left*bm.bmBitsPixel >> 3); +			for (int iy = 0; iy < imi.rcImage.bottom - imi.rcImage.top; iy++) { +				int x; +				// Dummy microsoft fix - alpha can be less than r,g or b +				// Looks like color channels in icons should be non-premultiplied with alpha +				// But AddIcon store it premultiplied (incorrectly cause can be Alpha == 7F, but R,G or B == 80 +				// So i check that alpha is 0x7F and set it to 0x80 +				DWORD *c = ((DWORD*)bcbits); +				for (x = 0; x < imi.rcImage.right - imi.rcImage.left; x++) { +					DWORD val = *c; +					BYTE a = (BYTE)((val) >> 24); +					if (a != 0) { +						BYTE r = (BYTE)((val & 0xFF0000) >> 16); +						BYTE g = (BYTE)((val & 0xFF00) >> 8); +						BYTE b = (BYTE)(val & 0xFF); +						if (a < r || a < g || a < b) +						{ +							a = max(max(r, g), b); +							val = a << 24 | r << 16 | g << 8 | b; +							*c = val; +						} +					} +					c++; +				} +				bcbits += bm.bmWidthBytes; +			} + +			if (!bm.bmBits) { +				SetBitmapBits(imi.hbmImage, bm.bmWidthBytes*bm.bmHeight, bits); +				free(bits); +			} +		} +	} +	return ImageList_GetIcon(himl,i,ILD_NORMAL); +} + +//////////////////////////////////////////////////////////////////////////// +// This creates new dib image from Imagelist icon ready to alphablend it + +HBITMAP ske_ExtractDIBFromImagelistIcon( HIMAGELIST himl,int index, int * outWidth, int * outHeight) +{ +	return NULL; +} + +BOOL ske_ImageList_DrawEx( HIMAGELIST himl,int i,HDC hdcDst,int x,int y,int dx,int dy,COLORREF rgbBk,COLORREF rgbFg,UINT fStyle) +{ +	//the routine to directly draw icon from image list without creating icon from there - should be some faster +	if (i < 0) +		return FALSE; + +	if (g_CluiData.fDisableSkinEngine) +		return ImageList_DrawEx(himl, i, hdcDst, x, y, dx, dy, rgbBk, rgbFg, fStyle); + +	BYTE alpha; +	if (fStyle&ILD_BLEND25) alpha = 64; +	else if (fStyle&ILD_BLEND50) alpha = 128; +	else alpha = 255; + +	HICON hIcon = ske_ImageList_GetIcon(himl, i, ILD_NORMAL); +	if (hIcon == NULL) +		return FALSE; + +	ske_DrawIconEx(hdcDst, x, y, hIcon, dx ? dx : GetSystemMetrics(SM_CXSMICON), dy ? dy : GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | (alpha << 24)); +	DestroyIcon(hIcon); +	return TRUE; +} + +static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, LPARAM lParam) +{ +	DrawIconFixParam *p = (DrawIconFixParam*)wParam; +	if (!p) +		return 0; + +	return ske_DrawIconEx(p->hdc,p->xLeft,p->yTop,p->hIcon,p->cxWidth,p->cyWidth,p->istepIfAniCur,p->hbrFlickerFreeDraw,p->diFlags); +} + + +BOOL ske_DrawIconEx(HDC hdcDst,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags) +{ +	ICONINFO ici; +	BYTE alpha = (BYTE)((diFlags&0xFF000000)>>24); + + +	HDC imDC; +	HBITMAP oldBmp, imBmp,tBmp; +	BITMAP imbt,immaskbt; +	BYTE * imbits; +	BYTE * imimagbits; +	BYTE * immaskbits; +	DWORD cx,cy,icy; +	BYTE *t1, *t2, *t3; + +	BOOL NoDIBImage = FALSE; +	//lockimagelist +	BYTE hasmask = FALSE; +	BYTE no32bit = FALSE; +	BYTE noMirrorMask = FALSE; +	BYTE hasalpha = FALSE; +	alpha = alpha?alpha:255; + +	if ( g_CluiData.fDisableSkinEngine && !(diFlags&0x80)) +		return DrawIconEx(hdcDst,xLeft,yTop,hIcon,cxWidth,cyWidth,istepIfAniCur,hbrFlickerFreeDraw,diFlags&0xFFFF7F); + +	if (!GetIconInfo(hIcon, &ici)) +		return 0; + +	GetObject(ici.hbmColor,sizeof(BITMAP),&imbt); +	if (imbt.bmWidth*imbt.bmHeight == 0) { +		DeleteObject(ici.hbmColor); +		DeleteObject(ici.hbmMask); +		return 0; +	} +	GetObject(ici.hbmMask,sizeof(BITMAP),&immaskbt); +	cy = imbt.bmHeight; + +	if (imbt.bmBitsPixel != 32) { +		HBITMAP otBmp; +		no32bit = TRUE; +		HDC tempDC1 = CreateCompatibleDC(hdcDst); +		tBmp = ske_CreateDIB32(imbt.bmWidth, imbt.bmHeight); +		if (tBmp) { +			GetObject(tBmp, sizeof(BITMAP), &imbt); +			otBmp = (HBITMAP)SelectObject(tempDC1, tBmp); +			DrawIconEx(tempDC1, 0, 0, hIcon, imbt.bmWidth, imbt.bmHeight, istepIfAniCur, hbrFlickerFreeDraw, DI_IMAGE); +			noMirrorMask = TRUE; + +		} +		SelectObject(tempDC1, otBmp); +		DeleteDC(tempDC1); +	} + +	if (imbt.bmBits == NULL) { +		NoDIBImage = TRUE; +		imimagbits = (BYTE*)malloc(cy*imbt.bmWidthBytes); +		GetBitmapBits(ici.hbmColor, cy*imbt.bmWidthBytes, (void*)imimagbits); +	} +	else imimagbits = (BYTE*)imbt.bmBits; + +	if (immaskbt.bmBits == NULL) { +		immaskbits = (BYTE*)malloc(cy*immaskbt.bmWidthBytes); +		GetBitmapBits(ici.hbmMask, cy*immaskbt.bmWidthBytes, (void*)immaskbits); +	} +	else immaskbits = (BYTE*)immaskbt.bmBits; + +	icy = imbt.bmHeight; +	cx = imbt.bmWidth; +	imDC = CreateCompatibleDC(hdcDst); +	imBmp = ske_CreateDIB32Point(cx, icy, (void**)&imbits); +	oldBmp = (HBITMAP)SelectObject(imDC, imBmp); +	if (imbits != NULL && imimagbits != NULL && immaskbits != NULL) { +		int x; int y; +		int bottom, right, top, h; +		int mwb, mwb2; +		mwb = immaskbt.bmWidthBytes; +		mwb2 = imbt.bmWidthBytes; +		bottom = icy; +		right = cx; +		top = 0; +		h = icy; +		for (y = top; (y < bottom) && !hasmask; y++) { +			t1 = immaskbits + y*mwb; +			for (x = 0; (x < mwb) && !hasmask; x++) +				hasmask |= (*(t1 + x) != 0); +		} + +		for (y = top; (y < bottom) && !hasalpha; y++) { +			t1 = imimagbits + (cy - y - 1)*mwb2; +			for (x = 0; (x < right) && !hasalpha; x++) +				hasalpha |= (*(t1+(x << 2)+3) != 0); +		} + +		for (y = 0; y < (int)icy; y++) { +			t1 = imimagbits+(h-y-1-top)*mwb2; +			t2 = imbits+(!no32bit?y:(icy-y-1))*mwb2; +			t3 = immaskbits+(noMirrorMask?y:(h-y-1-top))*mwb; +			for (x = 0; x < right; x++) { +				BYTE mask = 0; +				BYTE a = 0; +				DWORD *src = (DWORD*)(t1 + (x << 2)); +				DWORD *dest = (DWORD*)(t2 + (x << 2)); +				if (hasalpha && !hasmask) +					a = ((BYTE*)src)[3]; +				else { +					mask = ((1 << (7 - x % 8))&(*(t3 + (x >> 3)))) != 0; +					if (mask) { +						if (!hasalpha) { +							*dest = 0; +							continue; +						} + +						if (((BYTE*)src)[3]>0 ) +							a = ((BYTE*)src)[3]; +						else +						    a = 0; +					} +					else if (hasalpha || hasmask) +						a = (((BYTE*)src)[3]>0?((BYTE*)src)[3]:255); +					else if (!hasalpha && !hasmask) +						a = 255; +					else {  *dest = 0; continue; } +				} +				if (a > 0) { +					((BYTE*)dest)[3] = a; +					((BYTE*)dest)[0] = ((BYTE*)src)[0] * a / 255; +					((BYTE*)dest)[1] = ((BYTE*)src)[1] * a / 255; +					((BYTE*)dest)[2] = ((BYTE*)src)[2] * a / 255; +				} +				else *dest = 0; +			} +		} +	} + +	BLENDFUNCTION bf = { AC_SRC_OVER, diFlags & 128, alpha, AC_SRC_ALPHA }; +	ske_AlphaBlend(hdcDst, xLeft, yTop, cxWidth, cyWidth, imDC, 0, 0, cx, icy, bf); + +	if (immaskbt.bmBits == NULL) free(immaskbits); +	if (imbt.bmBits == NULL) free(imimagbits); +	SelectObject(imDC, oldBmp); +	DeleteObject(imBmp); +	if (no32bit)DeleteObject(tBmp); +	DeleteObject(ici.hbmColor); +	DeleteObject(ici.hbmMask); +	SelectObject(imDC, GetStockObject(DEFAULT_GUI_FONT)); +	DeleteDC(imDC); +	return 1; +} + +int ske_PrepareImageButDontUpdateIt(RECT *r) +{ +	if (!g_CluiData.fLayered) +		return ske_ReCreateBackImage(FALSE, r); + +	mutex_bLockUpdate = 1; +	ske_DrawNonFramedObjects(TRUE, r); +	ske_ValidateFrameImageProc(r); +	mutex_bLockUpdate = 0; +	return 0; +} + +int ske_RedrawCompleteWindow() +{ +	if (g_CluiData.fLayered) { +		ske_DrawNonFramedObjects(TRUE,0); +		CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, 0, 0); +	} +	else RedrawWindow(pcli->hwndContactList,NULL,NULL,RDW_ALLCHILDREN|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME); + +	return 0; +} + +// Request to repaint frame or change/drop callback data +// wParam = hWnd of called frame +// lParam = pointer to sPaintRequest (or NULL to redraw all) +// return 2 - already queued, data updated, 1-have been queued, 0 - failure + +static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam)           // Immideately recall paint routines for frame and refresh image +{ +	if ( MirandaLoading()) +		return 0; + +	RECT wnd; +	FRAMEWND *frm; +	BOOL NoCancelPost = 0; +	BOOL IsAnyQueued = 0; +	if (!g_CluiData.mutexOnEdgeSizing) +		GetWindowRect(pcli->hwndContactList,&wnd); +	else +		wnd = g_rcEdgeSizingRect; + +	if (!g_CluiData.fLayered) { +		RedrawWindow((HWND)wParam,NULL,NULL,RDW_UPDATENOW|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME); +		return 0; +	} + +	if (g_pCachedWindow == NULL) ske_ValidateFrameImageProc(&wnd); +	else if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) ske_ValidateFrameImageProc(&wnd); +	else if (wParam == 0) ske_ValidateFrameImageProc(&wnd); +	else { // all Ok Update Single Frame +		// TO BE LOCKED OR PROXIED +		frm = FindFrameByItsHWND((HWND)wParam); +		if (!frm) +			ske_ValidateFrameImageProc(&wnd); +		// Validate frame, update window image and remove it from queue +		else { +			if (frm->UpdateRgn) { +				DeleteObject(frm->UpdateRgn); +				frm->UpdateRgn = 0; +			} +			ske_ValidateSingleFrameImage(frm, 0); +			ske_UpdateWindowImage(); +			NoCancelPost = 1; +			//-- Remove frame from queue +			if (flag_bUpdateQueued) { +				frm->bQueued = 0; +				for (int i = 0; i < g_nFramesCount; i++) +					if (IsAnyQueued |= g_pfwFrames[i].bQueued) +						break; +			} +		} +	} + +	if ((!NoCancelPost || !IsAnyQueued) && flag_bUpdateQueued) { // no any queued updating cancel post or need to cancel post +		flag_bUpdateQueued = 0; +		g_flag_bPostWasCanceled = 1; +	} +	return 1; +} +static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam)       // Post request for updating +{ +	if (MirandaLoading()) return 0; + +	if (wParam) { +		FRAMEWND *frm = FindFrameByItsHWND((HWND)wParam); +		sPaintRequest *pr = (sPaintRequest*)lParam; +		if (!g_CluiData.fLayered || (frm && frm->floating)) +			return InvalidateRect((HWND)wParam, pr ? (RECT*)&(pr->rcUpdate) : NULL, FALSE); + +		if (frm) { +			if (frm->PaintCallbackProc != NULL) { +				frm->PaintData = (sPaintRequest *)pr; +				frm->bQueued = 1; +				if (pr) { +					HRGN r2; +					if (!IsRectEmpty(&pr->rcUpdate)) { +						RECT rcClient; +						RECT rcUpdate; +						GetClientRect(frm->hWnd, &rcClient); +						IntersectRect(&rcUpdate, &rcClient, &pr->rcUpdate); +						if (IsRectEmpty(&rcUpdate)) +							return 0; +						r2 = CreateRectRgn(rcUpdate.left, rcUpdate.top, rcUpdate.right, rcUpdate.bottom); +					} +					else { +						RECT r; +						GetClientRect(frm->hWnd, &r); +						r2 = CreateRectRgn(r.left, r.top, r.right, r.bottom); +					} + +					if (!frm->UpdateRgn) { +						frm->UpdateRgn = CreateRectRgn(0, 0, 1, 1); +						CombineRgn(frm->UpdateRgn, r2, 0, RGN_COPY); +					} +					else CombineRgn(frm->UpdateRgn, frm->UpdateRgn, r2, RGN_OR); +					DeleteObject(r2); +				} +			} +		} +		else Sync(QueueAllFramesUpdating, 1); +	} +	else Sync(QueueAllFramesUpdating, 1); + +	if (!flag_bUpdateQueued || g_flag_bPostWasCanceled) +	if (PostMessage(pcli->hwndContactList, UM_UPDATE, 0, 0)) { +		flag_bUpdateQueued = 1; +		g_flag_bPostWasCanceled = 0; +	} +	return 1; +} + +static int ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting)                              // Calling frame paint proc +{ +	if (!g_pCachedWindow) { TRACE("ske_ValidateSingleFrameImage calling without cached\n"); return 0;} +	if (Frame->hWnd == (HWND)-1 && !Frame->PaintCallbackProc)  { TRACE("ske_ValidateSingleFrameImage calling without FrameProc\n"); return 0;} + +	// if ok update image +	HDC hdc; +	HBITMAP o,n; +	RECT rcPaint,wnd; +	RECT ru = {0}; +	int w,h,x,y; +	int w1,h1,x1,y1; + +	CLUI_SizingGetWindowRect(pcli->hwndContactList,&wnd); +	rcPaint = Frame->wndSize; +	{ +		int dx,dy,bx,by; +		if (g_CluiData.mutexOnEdgeSizing) +		{ +			dx = rcPaint.left-wnd.left; +			dy = rcPaint.top-wnd.top; +			bx = rcPaint.right-wnd.right; +			by = rcPaint.bottom-wnd.bottom; +			wnd = g_rcEdgeSizingRect; +			rcPaint.left = wnd.left+dx; +			rcPaint.top = wnd.top+dy; +			rcPaint.right = wnd.right+bx; +			rcPaint.bottom = wnd.bottom+by; +		} +	} +	//OffsetRect(&rcPaint,-wnd.left,-wnd.top); +	w = rcPaint.right-rcPaint.left; +	h = rcPaint.bottom-rcPaint.top; +	if (w <= 0 || h <= 0) +	{ +		TRACE("Frame size smaller than 0\n"); +		return 0; +	} +	x = rcPaint.left; +	y = rcPaint.top; +	hdc = CreateCompatibleDC(g_pCachedWindow->hImageDC); +	n = ske_CreateDIB32(w,h); +	o = (HBITMAP)SelectObject(hdc,n); +	{ +		if (Frame->UpdateRgn && !SkipBkgBlitting) +		{ +			GetRgnBox(Frame->UpdateRgn,&ru); +			{ +				RECT rc; +				GetClientRect(Frame->hWnd,&rc); +				if (ru.top < 0) ru.top = 0; +				if (ru.left < 0) ru.left = 0; +				if (ru.right>rc.right) ru.right = rc.right; +				if (ru.bottom>rc.bottom) ru.bottom = rc.bottom; +			} +			if (!IsRectEmpty(&ru)) +			{ +				x1 = ru.left; +				y1 = ru.top; +				w1 = ru.right-ru.left; +				h1 = ru.bottom-ru.top; +			} +			else +			{x1 = 0; y1 = 0; w1 = w; h1 = h;} +			// copy image at hdc +			if (SkipBkgBlitting)  //image already at foreground +			{ +				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY); +			} +			else +			{ +				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY); +			} +			Frame->PaintCallbackProc(Frame->hWnd,hdc,&ru,Frame->UpdateRgn, Frame->dwFlags,Frame->PaintData); +		} +		else +		{ +			   HRGN rgnUpdate; +			RECT r; +			GetClientRect(Frame->hWnd,&r); +			rgnUpdate = CreateRectRgn(r.left,r.top,r.right,r.bottom); +			ru = r; +			if (!IsRectEmpty(&ru)) +			{ +				x1 = ru.left; +				y1 = ru.top; +				w1 = ru.right-ru.left; +				h1 = ru.bottom-ru.top; +			} +			else +			{x1 = 0; y1 = 0; w1 = w; h1 = h;} +			// copy image at hdc +			if (SkipBkgBlitting)  //image already at foreground +			{ +				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY); +			} +			else +			{ +				BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY); +			} +			Frame->PaintCallbackProc(Frame->hWnd,hdc,&r,rgnUpdate, Frame->dwFlags,Frame->PaintData); +			ru = r; +			   DeleteObject(rgnUpdate); +		} +		DeleteObject(Frame->UpdateRgn); +		Frame->UpdateRgn = 0; +	} +	if (!IsRectEmpty(&ru)) +	{ +		x1 = ru.left; +		y1 = ru.top; +		w1 = ru.right-ru.left; +		h1 = ru.bottom-ru.top; +	} +	else { +		x1 = 0; y1 = 0; w1 = w; h1 = h; +	} + +	BitBlt(g_pCachedWindow->hImageDC,x+x1,y+y1,w1,h1,hdc,x1,y1,SRCCOPY); + +	if (GetWindowLongPtr(Frame->hWnd, GWL_STYLE) & WS_VSCROLL) { +		//Draw vertical scroll bar +		// +		SCROLLBARINFO si = {0}; +		si.cbSize = sizeof(SCROLLBARINFO); +		GetScrollBarInfo(Frame->hWnd, OBJID_VSCROLL, &si); + +		RECT rLine = (si.rcScrollBar); +		RECT rUpBtn = rLine; +		RECT rDnBtn = rLine; +		RECT rThumb = rLine; + +		rUpBtn.bottom = rUpBtn.top+si.dxyLineButton; +		rDnBtn.top = rDnBtn.bottom-si.dxyLineButton; +		rThumb.top = rLine.top+si.xyThumbTop; +		rThumb.bottom = rLine.top+si.xyThumbBottom; + +		int dx = Frame->wndSize.right-rLine.right; +		int dy = -rLine.top + Frame->wndSize.top; + +		OffsetRect(&rLine, dx, dy); +		OffsetRect(&rUpBtn, dx, dy); +		OffsetRect(&rDnBtn, dx, dy); +		OffsetRect(&rThumb, dx, dy); +		BitBlt(g_pCachedWindow->hImageDC, rLine.left, rLine.top, rLine.right - rLine.left, rLine.bottom - rLine.top, g_pCachedWindow->hBackDC, rLine.left, rLine.top, SRCCOPY); + +		char req[255]; +		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Back", Frame->szName); +		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rLine,&rLine,req); +		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Thumb", Frame->szName); +		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rThumb,&rThumb,req); +		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar, Frame=%s,Part=UpLineButton", Frame->szName); +		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rUpBtn,&rUpBtn,req); +		mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=DownLineButton", Frame->szName); +		SkinDrawGlyph(g_pCachedWindow->hImageDC,&rDnBtn,&rDnBtn,req); +	} + +	SelectObject(hdc, o); +	DeleteObject(n); +	DeleteDC(hdc); +	return 1; +} + +int ske_BltBackImage (HWND destHWND, HDC destDC, RECT *BltClientRect) +{ +	POINT ptMainWnd = {0}; +	POINT ptChildWnd = {0}; +	RECT from = {0}; +	RECT w = {0}; +	if (g_CluiData.fDisableSkinEngine) { +		FillRect(destDC,BltClientRect,GetSysColorBrush(COLOR_3DFACE)); +		return 0; +	} +	ske_ReCreateBackImage(FALSE,NULL); +	if (BltClientRect) w = *BltClientRect; +	else GetClientRect(destHWND,&w); +	ptChildWnd.x = w.left; +	ptChildWnd.y = w.top; +	ClientToScreen(destHWND,&ptChildWnd); +	ClientToScreen(pcli->hwndContactList,&ptMainWnd); +	//TODO if main not relative to client area +	return BitBlt(destDC,w.left,w.top,(w.right-w.left),(w.bottom-w.top),g_pCachedWindow->hBackDC,(ptChildWnd.x-ptMainWnd.x),(ptChildWnd.y-ptMainWnd.y),SRCCOPY); + +} +int ske_ReCreateBackImage(BOOL Erase,RECT *w) +{ +	HBITMAP hb2; +	RECT wnd = {0}; +	BOOL IsNewCache = 0; +	if (g_CluiData.fDisableSkinEngine) return 0; +	GetClientRect(pcli->hwndContactList,&wnd); +	if (w) wnd = *w; +	//-- Check cached. +	if (g_pCachedWindow == NULL) { +		//-- Create New Cache +		g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA)); +		g_pCachedWindow->hScreenDC = GetDC(NULL); +		g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); +		g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); +		g_pCachedWindow->Width = wnd.right-wnd.left; +		g_pCachedWindow->Height = wnd.bottom-wnd.top; +		if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) { +			g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); +			g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); +			g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB); +			g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB); +		} +		IsNewCache = 1; +	} + +	if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) { +		HBITMAP hb1 = NULL,hb2 = NULL; +		g_pCachedWindow->Width = wnd.right-wnd.left; +		g_pCachedWindow->Height = wnd.bottom-wnd.top; +		if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) { +			hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); +			hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); +			SelectObject(g_pCachedWindow->hImageDC,hb1); +			SelectObject(g_pCachedWindow->hBackDC,hb2); +		} +		else { +			SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld); +			SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld); +		} +		if (g_pCachedWindow->hImageDIB) DeleteObject(g_pCachedWindow->hImageDIB); +		if (g_pCachedWindow->hBackDIB) DeleteObject(g_pCachedWindow->hBackDIB); +		g_pCachedWindow->hImageDIB = hb1; +		g_pCachedWindow->hBackDIB = hb2; +		IsNewCache = 1; +	} + +	if ((Erase || IsNewCache ) &&  (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0)) { +		hb2 = ske_CreateDIB32(g_pCachedWindow->Width,g_pCachedWindow->Height); +		SelectObject(g_pCachedWindow->hBackDC,hb2); +		DeleteObject(g_pCachedWindow->hBackDIB); +		g_pCachedWindow->hBackDIB = hb2; +		FillRect(g_pCachedWindow->hBackDC,&wnd,GetSysColorBrush(COLOR_BTNFACE)); +		SkinDrawGlyph(g_pCachedWindow->hBackDC,&wnd,&wnd,"Main,ID=Background,Opt=Non-Layered"); +		ske_SetRectOpaque(g_pCachedWindow->hBackDC,&wnd); +	} +	return 1; +} + +int ske_DrawNonFramedObjects(BOOL Erase,RECT *r) +{ +	RECT w, wnd; +	if (r) w = *r; +	else CLUI_SizingGetWindowRect(pcli->hwndContactList, &w); +	if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0); +	if (g_pCachedWindow == NULL) +		return ske_ValidateFrameImageProc(&w); + +	wnd = w; +	OffsetRect(&w, -w.left, -w.top); +	if (Erase) { +		HBITMAP hb2; +		hb2 = ske_CreateDIB32(g_pCachedWindow->Width, g_pCachedWindow->Height); +		SelectObject(g_pCachedWindow->hBackDC, hb2); +		DeleteObject(g_pCachedWindow->hBackDIB); +		g_pCachedWindow->hBackDIB = hb2; +	} + +	SkinDrawGlyph(g_pCachedWindow->hBackDC, &w, &w, "Main,ID=Background"); + +	//--Draw frames captions +	for (int i = 0; i < g_nFramesCount; i++) { +		if (g_pfwFrames[i].TitleBar.ShowTitleBar && g_pfwFrames[i].visible && !g_pfwFrames[i].floating) { +			RECT rc; +			SetRect(&rc, g_pfwFrames[i].wndSize.left, g_pfwFrames[i].wndSize.top - g_nTitleBarHeight - g_CluiData.nGapBetweenTitlebar, g_pfwFrames[i].wndSize.right, g_pfwFrames[i].wndSize.top - g_CluiData.nGapBetweenTitlebar); +			Sync(DrawTitleBar, g_pCachedWindow->hBackDC, &rc, g_pfwFrames[i].id); +		} +	} +	g_mutex_bLockUpdating = 1; + +	flag_bJustDrawNonFramedObjects = 1; +	return 0; +} + +int ske_ValidateFrameImageProc(RECT *r)                                // Calling queued frame paint procs and refresh image +{ +	RECT wnd = {0}; +	BOOL IsNewCache = 0; +	BOOL IsForceAllPainting = 0; +	if (r) wnd = *r; +	else GetWindowRect(pcli->hwndContactList,&wnd); +	if (wnd.right-wnd.left == 0 || wnd.bottom-wnd.top == 0) +		return 0; + +	g_mutex_bLockUpdating = 1; + +	//-- Check cached. +	if (g_pCachedWindow == NULL) { +		//-- Create New Cache +		g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA)); +		g_pCachedWindow->hScreenDC = GetDC(NULL); +		g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); +		g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC); +		g_pCachedWindow->Width = wnd.right-wnd.left; +		g_pCachedWindow->Height = wnd.bottom-wnd.top; +		g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); +		g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); +		g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB); +		g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB); +		IsNewCache = 1; +	} +	if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) { +		HBITMAP hb1,hb2; +		g_pCachedWindow->Width = wnd.right-wnd.left; +		g_pCachedWindow->Height = wnd.bottom-wnd.top; +		hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte)); +		hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte)); +		SelectObject(g_pCachedWindow->hImageDC,hb1); +		SelectObject(g_pCachedWindow->hBackDC,hb2); +		DeleteObject(g_pCachedWindow->hImageDIB); +		DeleteObject(g_pCachedWindow->hBackDIB); +		g_pCachedWindow->hImageDIB = hb1; +		g_pCachedWindow->hBackDIB = hb2; +		IsNewCache = 1; +	} +	if (IsNewCache) { +		ske_DrawNonFramedObjects(0, &wnd); +		IsForceAllPainting = 1; +	} +	if (flag_bJustDrawNonFramedObjects) { +		IsForceAllPainting = 1; +		flag_bJustDrawNonFramedObjects = 0; +	} +	if (IsForceAllPainting) { +		BitBlt(g_pCachedWindow->hImageDC, 0, 0, g_pCachedWindow->Width,g_pCachedWindow->Height,g_pCachedWindow->hBackDC, 0, 0, SRCCOPY); +		Sync( QueueAllFramesUpdating, (BYTE)1 ); +	} +	//-- Validating frames +	for (int i=0; i < g_nFramesCount; i++) +		if (g_pfwFrames[i].PaintCallbackProc && g_pfwFrames[i].visible && !g_pfwFrames[i].floating) +			if (g_pfwFrames[i].bQueued || IsForceAllPainting) +				ske_ValidateSingleFrameImage(&g_pfwFrames[i], IsForceAllPainting); + +	g_mutex_bLockUpdating = 1; +	ModernSkinButtonRedrawAll(0); +	g_mutex_bLockUpdating = 0; +	if (!mutex_bLockUpdate) +		ske_UpdateWindowImageRect(&wnd); + +	//-- Clear queue +	Sync(QueueAllFramesUpdating, 0); +	flag_bUpdateQueued = 0; +	g_flag_bPostWasCanceled = 0; +	return 1; +} + +int ske_UpdateWindowImage() +{ +	if (MirandaExiting()) +		return 0; + +	if (g_CluiData.fLayered) { +		RECT r; +		GetWindowRect(pcli->hwndContactList,&r); +		return ske_UpdateWindowImageRect(&r); +	} +	else ske_ReCreateBackImage(FALSE,0); +	ske_ApplyTranslucency(); +	return 0; +} + +int ske_UpdateWindowImageRect(RECT *r)                                     // Update window with current image and +{ +	//if not validity -> ValidateImageProc +	//else Update using current alpha +	RECT wnd = *r; + +	if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0); +	if (g_pCachedWindow == NULL) return ske_ValidateFrameImageProc(&wnd); +	if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) return ske_ValidateFrameImageProc(&wnd); +	if (g_flag_bFullRepaint) { +		g_flag_bFullRepaint = 0; +		return ske_ValidateFrameImageProc(&wnd); +	} +	ske_JustUpdateWindowImageRect(&wnd); +	return 0; +} + +void ske_ApplyTranslucency() +{ +	int IsTransparancy; +	HWND hwnd = pcli->hwndContactList; +	BOOL layered = (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED)?TRUE:FALSE; + +	IsTransparancy = g_CluiData.fSmoothAnimation || g_bTransparentFlag; +	if (!g_bTransparentFlag && !g_CluiData.fSmoothAnimation && g_CluiData.bCurrentAlpha != 0) +		g_CluiData.bCurrentAlpha = 255; + +	if (!g_CluiData.fLayered && IsTransparancy) { +		if (!layered) +			SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); +		SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE)g_CluiData.bCurrentAlpha, LWA_ALPHA); +	} + +	AniAva_RedrawAllAvatars(FALSE); +	return; +} + +int ske_JustUpdateWindowImage() +{ +	RECT r; +	if (!g_CluiData.fLayered) { +		ske_ApplyTranslucency(); +		return 0; +	} +	GetWindowRect(pcli->hwndContactList,&r); +	return ske_JustUpdateWindowImageRect(&r); +} + +// Update window image +int ske_JustUpdateWindowImageRect(RECT *rty) +{ +	if (!g_CluiData.fLayered) { +		ske_ApplyTranslucency(); +		return 0; +	} +	if (!pcli->hwndContactList) +		return 0; + +	RECT wnd = *rty; +	RECT rect = wnd; +	POINT dest = { 0 }, src = { 0 }; +	dest.x = rect.left; +	dest.y = rect.top; +	SIZE sz = { rect.right - rect.left, rect.bottom - rect.top }; +	if (g_CluiData.fLayered) { +		if (!(GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE)&WS_EX_LAYERED)) +			SetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE, GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE) | WS_EX_LAYERED); +		Sync(SetAlpha, g_CluiData.bCurrentAlpha); + +		BLENDFUNCTION bf = { AC_SRC_OVER, 0, g_CluiData.bCurrentAlpha, AC_SRC_ALPHA }; +		UpdateLayeredWindow(pcli->hwndContactList, g_pCachedWindow->hScreenDC, &dest, &sz, g_pCachedWindow->hImageDC, &src, RGB(1, 1, 1), &bf, ULW_ALPHA); +		g_CluiData.fAeroGlass = false; +		CLUI_UpdateAeroGlass(); +	} +	else InvalidateRect(pcli->hwndContactList,NULL,TRUE); +	return 0; +} + +int ske_DrawImageAt(HDC hdc, RECT *rc) +{ +	BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; +	BitBlt(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,g_pCachedWindow->hBackDC,rc->left,rc->top,SRCCOPY); +	ske_AlphaBlend(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,hdc, 0, 0, rc->right-rc->left,rc->bottom-rc->top,bf); +	if (!g_mutex_bLockUpdating) +		ske_UpdateWindowImage(); +	return 0; +} + +HBITMAP ske_GetCurrentWindowImage() +{ +	return g_pCachedWindow->hImageDIB; +} + +/* +*  Glyph text routine +*/ + +static DWORD ske_HexToARGB(char * Hex) +{ +	char buf[10] = {0}; +	char buf2[11] = {0}; +	mir_snprintf(buf, SIZEOF(buf), "%s\n", Hex); +	if (buf[1] == 'x' || buf[1] == 'X') +		mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf+2); +	else +		mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf); +	buf2[10] = '\0'; + +	char *st; +	DWORD AARRGGBB = strtoul(buf2, &st, 16); +	BYTE alpha = (BYTE)((AARRGGBB & 0xFF000000) >> 24); +	alpha = 255-((alpha == 0)?255:alpha); +	AARRGGBB = (alpha << 24)+((AARRGGBB&0x00FF0000)>>16)+((AARRGGBB&0x000000FF) << 16)+(AARRGGBB&0x0000FF00); +	return AARRGGBB; +} + +static TCHAR *ske_ReAppend(TCHAR *lfirst, TCHAR * lsecond, int len) +{ +	int l1 = lfirst?lstrlen(lfirst):0; +	int l2 = (len?len:(lstrlen(lsecond)+1)); +	TCHAR *buf = (TCHAR *)mir_alloc((l1+l2+1)*sizeof(TCHAR)); +	if (lfirst) memmove(buf,lfirst,l1*sizeof(TCHAR)); +	memmove(buf+l1,lsecond,l2*sizeof(TCHAR)); +	mir_free(lfirst); +	if (len) buf[l1+l2] = _T('\0'); +	return buf; +} + +TCHAR* ske_ReplaceVar(TCHAR *var) +{ +	if (!var) return mir_tstrdup(_T("")); +	if (!lstrcmpi(var,_T("Profile"))) { +		char buf[MAX_PATH] = {0}; +		CallService(MS_DB_GETPROFILENAME,(WPARAM)MAX_PATH,(LPARAM)buf); + +		int i = strlen(buf); +		while (buf[i] != '.' && i>0) i--; +		buf[i] = '\0'; + +		mir_free(var); +		return mir_a2u(buf); +	} + +	mir_free(var); +	return mir_tstrdup(_T("")); +} + +TCHAR *ske_ParseText(TCHAR *stzText) +{ +	int len = lstrlen(stzText); +	TCHAR *result = NULL; +	int stpos = 0; +	int curpos = 0; + +	while (curpos < len) { +		//1 find first % +		while (curpos < len && stzText[curpos] != (TCHAR)'%') +			curpos++; +		if (curpos < len) { //% found +			if (curpos-stpos>0) +				result = ske_ReAppend(result,stzText+stpos,curpos-stpos); +			stpos = curpos+1; +			curpos++; +			//3 find second % +			while(curpos < len && stzText[curpos] != (TCHAR)'%') +				curpos++; +			if (curpos >= len) +				break; +			if (curpos - stpos > 0) { +				TCHAR *var = (TCHAR *)mir_alloc((curpos - stpos + 1)*sizeof(TCHAR)); +				memmove(var, stzText + stpos, (curpos - stpos)*sizeof(TCHAR)); +				var[curpos - stpos] = (TCHAR)'\0'; +				var = ske_ReplaceVar(var); +				result = ske_ReAppend(result, var, 0); +				mir_free(var); +			} +			else result = ske_ReAppend(result, _T("%"), 0); + +			curpos++; +			stpos = curpos; +		} +		else { +			if (curpos - stpos > 0) +				result = ske_ReAppend(result, stzText + stpos, curpos - stpos); +			break; +		} +	} +	return result; +} +/* +*   Parse text object string, find glyph object and add text to it. +*   szGlyphTextID and Define string is: +*   t[szGlyphTextID] = s[HostObjectID],[Left],[Top],[Right],[Bottom],[LTRBHV],[FontID],[Color1],[reservedforColor2],[Text] +*/ + +static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin) +{ +	char buf[255] = {0}; +	GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE); +	if (buf[0] == 0) +		return; + +	GLYPHTEXT *glText = (GLYPHTEXT*)mir_calloc(sizeof(GLYPHTEXT)); +	glText->szGlyphTextID = mir_strdup(szGlyphTextID); +	glText->szObjectName = mir_strdup(buf); +	glText->iLeft = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE)); +	glText->iTop = atoi(GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE)); +	glText->iRight = atoi(GetParamN(szDefineString,buf,sizeof(buf),3,',',TRUE)); +	glText->iBottom = atoi(GetParamN(szDefineString,buf,sizeof(buf),4,',',TRUE)); +	{ +		memset(buf, 0, 6); +		GetParamN(szDefineString,buf,sizeof(buf),5,',',TRUE); +		buf[0] &= 95; buf[1] &= 95; buf[2] &= 95; buf[3] &= 95; buf[4] &= 95; buf[5] &= 95;   //to uppercase: &01011111 (0-95) +		glText->RelativeFlags = +			(buf[0] == 'C'?1:((buf[0] == 'R')?2:0))       //[BC][RC][BC][RC] --- Left relative +			|(buf[1] == 'C'?4:((buf[1] == 'B')?8:0))       //  |   |   |--------- Top relative +			|(buf[2] == 'C'?16:((buf[2] == 'R')?32:0))     //  |   |--------------Right relative +			|(buf[3] == 'C'?64:((buf[3] == 'B')?128:0));   //  |------------------Bottom relative +		glText->dwFlags = (buf[4] == 'C'?DT_CENTER:((buf[4] == 'R')?DT_RIGHT:DT_LEFT)) +			|(buf[5] == 'C'?DT_VCENTER:((buf[5] == 'B')?DT_BOTTOM:DT_TOP)); +	} +	glText->szFontID = mir_strdup(GetParamN(szDefineString,buf,sizeof(buf),6,',',TRUE)); + +	glText->dwColor = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),7,',',TRUE)); +	glText->dwShadow = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),8,',',TRUE)); +	glText->stValueText = mir_a2u(GetParamN(szDefineString,buf,sizeof(buf),9,',',TRUE)); +	glText->stText = ske_ParseText(glText->stValueText); + +	if (!Skin->pTextList) +		Skin->pTextList = List_Create(0, 1); +	List_InsertPtr(Skin->pTextList,glText); +} + + +/* +*   Parse font definition string. +*   szGlyphTextID and Define string is: +*   f[szFontID] = s[FontTypefaceName],[size],[BIU] +*/ +static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin) +{ +	SKINFONT *sf = (SKINFONT*)mir_calloc(sizeof(SKINFONT)); +	if (!sf) +		return; + +	char buf[255]; +	int fntSize = 0; +	BOOL fntBold = FALSE, fntItalic = FALSE, fntUnderline = FALSE; +	LOGFONTA logfont = {0}; +	logfont.lfCharSet = DEFAULT_CHARSET; +	logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; +	logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; +	logfont.lfQuality = DEFAULT_QUALITY; +	logfont.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; + +	strncpy(logfont.lfFaceName,GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE),32); +	logfont.lfHeight = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE)); +	if (logfont.lfHeight < 0) { +		HDC hdc = CreateCompatibleDC(NULL); +		logfont.lfHeight = (long)-MulDiv(logfont.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72); +		DeleteDC(hdc); +	} +	logfont.lfHeight = -logfont.lfHeight; +	GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE); +	buf[0] &= 95; buf[1] &= 95; buf[2] &= 95; +	logfont.lfWeight = (buf[0] == 'B')?FW_BOLD:FW_NORMAL; +	logfont.lfItalic = (buf[1] == 'I')?1:0; +	logfont.lfUnderline = (buf[2] == 'U')?1:0; + +	sf->hFont = CreateFontIndirectA(&logfont); +	if (sf->hFont) { +		sf->szFontID = mir_strdup(szFontID); +		if (!gl_plSkinFonts) +			gl_plSkinFonts = List_Create(0, 1); +		if (gl_plSkinFonts) +			List_Insert(gl_plSkinFonts,(void*)sf,gl_plSkinFonts->realCount); +	} +} + +/* + *   ske_CheckHasAlfaChannel - checks if image has at least one BYTE in alpha chennel + *                  that is not a 0. (is image real 32 bit or just 24 bit) + */ +static BOOL ske_CheckHasAlfaChannel(BYTE * from, int widthByte, int height) +{ +	DWORD *pt = (DWORD*)from; +	for (int j = 0; j < height; j++) { +		BYTE *add = (BYTE*)pt+widthByte; +		while (pt < (DWORD*)add) { +			if ((*pt & 0xFF000000) != 0) +				return TRUE; +			pt++; +		} +		pt = (DWORD*)(from+widthByte*j); +	} +	return FALSE; +} + +/* + *   ske_CheckIconHasMask - checks if mask image has at least one that is not a 0. + *                  Not sure is ir required or not + */ +static BOOL ske_CheckIconHasMask(BYTE * from) +{ +	for (int i=0; i < 16*16/8; i++) +		if (from[i] != 0) +			return TRUE; + +	return FALSE; +} + +/* + *   ske_GetMaskBit - return value of apropriate mask bit in line at x position + */ +static BOOL ske_GetMaskBit(BYTE *line, int x) +{ +	return ((*(line+(x>>3)))&(0x01 << (7-(x&0x07)))) != 0; +} + +/* + *    ske_Blend  - alpha ske_Blend ARGB values of 2 pixels. X1 - underlaying, + *            X2 - overlaying points. + */ + +static DWORD ske_Blend(DWORD X1,DWORD X2, BYTE alpha) +{ +	BYTE a1 = (BYTE)(X1>>24); +	BYTE a2 = (BYTE)(((X2>>24)*alpha)>>8); +	BYTE r1 = (BYTE)(X1>>16); +	BYTE r2 = (BYTE)(X2>>16); +	BYTE g1 = (BYTE)(X1>>8); +	BYTE g2 = (BYTE)(X2>>8); +	BYTE b1 = (BYTE)(X1); +	BYTE b2 = (BYTE)(X2); + +	BYTE a_1 = ~a1; +	BYTE a_2 = ~a2; +	WORD am = (WORD)a1*a_2; + +	/*  it is possible to use >>8 instead of /255 but it is require additional +	*   checking of alphavalues +	*/ +	WORD ar = a1+(((WORD)a_1*a2)/255); +	// if a2 more than 0 than result should be more +	// or equal (if a1 == 0) to a2, else in combination +	// with mask we can get here black points + +	ar = (a2>ar)?a2:ar; + +	if (ar == 0) return 0; + +	WORD arm = ar*255; +	WORD rr = (((WORD)r1*am+(WORD)r2*a2*255))/arm; +	WORD gr = (((WORD)g1*am+(WORD)g2*a2*255))/arm; +	WORD br = (((WORD)b1*am+(WORD)b2*a2*255))/arm; +	return (ar << 24)|(rr << 16)|(gr << 8)|br; +} + +/* + *    CreateJoinedIcon  - creates new icon by drawing hTop over hBottom. + */ + +HICON ske_CreateJoinedIcon(HICON hBottom, HICON hTop, BYTE alpha) +{ +	HBITMAP nMask; +	BITMAP bmp = { 0 }; +	BYTE *ptPixels; +	ICONINFO iNew = { 0 }; +	ICONINFO iciBottom = { 0 }; +	ICONINFO iciTop = { 0 }; + +	BITMAP bmp_top = { 0 }; +	BITMAP bmp_top_mask = { 0 }; + +	BITMAP bmp_bottom = { 0 }; +	BITMAP bmp_bottom_mask = { 0 }; + +	HDC tempDC = CreateCompatibleDC(NULL); +	HBITMAP nImage = ske_CreateDIB32Point(16, 16, (void**)&ptPixels); +	HBITMAP oImage = (HBITMAP)SelectObject(tempDC, nImage); + +	GetIconInfo(hBottom, &iciBottom); +	GetObject(iciBottom.hbmColor, sizeof(BITMAP), &bmp_bottom); +	GetObject(iciBottom.hbmMask, sizeof(BITMAP), &bmp_bottom_mask); + +	GetIconInfo(hTop, &iciTop); +	GetObject(iciTop.hbmColor, sizeof(BITMAP), &bmp_top); +	GetObject(iciTop.hbmMask, sizeof(BITMAP), &bmp_top_mask); + +	if (bmp_bottom.bmBitsPixel == 32 && bmp_top.bmBitsPixel == 32) { +		BYTE *BottomBuffer, *TopBuffer, *BottomMaskBuffer, *TopMaskBuffer; +		BYTE *bb, *tb, *bmb, *tmb; +		BYTE *db = ptPixels; +		int vstep_d = 16 * 4; +		int vstep_b = bmp_bottom.bmWidthBytes; +		int vstep_t = bmp_top.bmWidthBytes; +		int vstep_bm = bmp_bottom_mask.bmWidthBytes; +		int vstep_tm = bmp_top_mask.bmWidthBytes; +		alpha = alpha ? alpha : 255; +		if (bmp_bottom.bmBits) bb = BottomBuffer = (BYTE*)bmp_bottom.bmBits; +		else { +			BottomBuffer = (BYTE*)malloc(bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes); +			GetBitmapBits(iciBottom.hbmColor, bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes, BottomBuffer); +			bb = BottomBuffer + vstep_b*(bmp_bottom.bmHeight - 1); +			vstep_b = -vstep_b; +		} + +		if (bmp_top.bmBits) tb = TopBuffer = (BYTE*)bmp_top.bmBits; +		else { +			TopBuffer = (BYTE*)malloc(bmp_top.bmHeight*bmp_top.bmWidthBytes); +			GetBitmapBits(iciTop.hbmColor,bmp_top.bmHeight*bmp_top.bmWidthBytes,TopBuffer); +			tb = TopBuffer+vstep_t*(bmp_top.bmHeight-1); +			vstep_t = -vstep_t; +		} + +		if (bmp_bottom_mask.bmBits) { +			BottomMaskBuffer = (BYTE*)bmp_bottom_mask.bmBits; +			bmb = BottomMaskBuffer; +		} +		else { +			BottomMaskBuffer = (BYTE*)malloc(bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes); +			GetBitmapBits(iciBottom.hbmMask,bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes,BottomMaskBuffer); +			bmb = BottomMaskBuffer+vstep_bm*(bmp_bottom_mask.bmHeight-1); +			vstep_bm = -vstep_bm; + +		} + +		if (bmp_top_mask.bmBits) { +			TopMaskBuffer = (BYTE*)bmp_top_mask.bmBits; +			tmb = TopMaskBuffer; +		} +		else { +			TopMaskBuffer = (BYTE*)malloc(bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes); +			GetBitmapBits(iciTop.hbmMask,bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes,TopMaskBuffer); +			tmb = TopMaskBuffer+vstep_tm*(bmp_top_mask.bmHeight-1); +			vstep_tm = -vstep_tm; +		} + +		BOOL topHasAlpha = ske_CheckHasAlfaChannel(TopBuffer, bmp_top.bmWidthBytes, bmp_top.bmHeight); +		BOOL bottomHasAlpha = ske_CheckHasAlfaChannel(BottomBuffer, bmp_bottom.bmWidthBytes, bmp_bottom.bmHeight); +		BOOL topHasMask = ske_CheckIconHasMask(TopMaskBuffer); +		BOOL bottomHasMask = ske_CheckIconHasMask(BottomMaskBuffer); +		for (int y = 0; y < 16; y++) { +			for (int x = 0; x < 16; x++) { +				BOOL mask_b = ske_GetMaskBit(bmb, x); +				BOOL mask_t = ske_GetMaskBit(tmb, x); +				DWORD bottom_d = ((DWORD*)bb)[x]; +				DWORD top_d = ((DWORD*)tb)[x]; +				if (topHasMask) { +					if (mask_t == 1 && !topHasAlpha)  top_d &= 0xFFFFFF; +					else if (!topHasAlpha) top_d |= 0xFF000000; +				} +				if (bottomHasMask) { +					if (mask_b == 1 && !bottomHasAlpha) bottom_d &= 0xFFFFFF; +					else if (!bottomHasAlpha) bottom_d |= 0xFF000000; +				} +				((DWORD*)db)[x] = ske_Blend(bottom_d, top_d, alpha); +			} +			bb += vstep_b; +			tb += vstep_t; +			bmb += vstep_bm; +			tmb += vstep_tm; +			db += vstep_d; +		} + +		if (!bmp_bottom.bmBits) free(BottomBuffer); +		if (!bmp_top.bmBits) free(TopBuffer); +		if (!bmp_bottom_mask.bmBits) free(BottomMaskBuffer); +		if (!bmp_top_mask.bmBits) free(TopMaskBuffer); +	} +	else { +		ske_DrawIconEx(tempDC, 0, 0, hBottom,16,16, 0, NULL,DI_NORMAL); +		ske_DrawIconEx(tempDC, 0, 0, hTop,16,16, 0, NULL,DI_NORMAL|(alpha << 24)); +	} + +	DeleteObject(iciBottom.hbmColor); +	DeleteObject(iciTop.hbmColor); +	DeleteObject(iciBottom.hbmMask); +	DeleteObject(iciTop.hbmMask); + +	SelectObject(tempDC,oImage); +	DeleteDC(tempDC); + +	BYTE p[32] = {0}; +	nMask = CreateBitmap(16,16,1,1,(void*)&p); +	{ +		HDC tempDC2 = CreateCompatibleDC(NULL); +		HDC tempDC3 = CreateCompatibleDC(NULL); +		HBITMAP hbm = CreateCompatibleBitmap(tempDC3,16,16); +		HBITMAP obmp = (HBITMAP)SelectObject(tempDC2,nMask); +		HBITMAP obmp2 = (HBITMAP)SelectObject(tempDC3,hbm); +		DrawIconEx(tempDC2, 0, 0, hBottom,16,16, 0, NULL,DI_MASK); +		DrawIconEx(tempDC3, 0, 0, hTop,16,16, 0, NULL,DI_MASK); +		BitBlt(tempDC2, 0, 0, 16,16,tempDC3, 0, 0, SRCAND); +		SelectObject(tempDC2,obmp); +		SelectObject(tempDC3,obmp2); +		DeleteObject(hbm); +		DeleteDC(tempDC2); +		DeleteDC(tempDC3); +	} +	iNew.fIcon = TRUE; +	iNew.hbmColor = nImage; +	iNew.hbmMask = nMask; +	HICON res = CreateIconIndirect(&iNew); +	DeleteObject(nImage); +	DeleteObject(nMask); +	return res; +} + +#define NEWJOINEDSTR( destination, first, separator, last)						\ +	destination = (char*)alloca(strlen(first)+strlen(separator)+strlen(last)+1);	\ +	if (destination) {													\ +	*destination = '\0';												\ +	strcat(destination,first);										\ +	strcat(destination,separator);									\ +	strcat(destination,last);										\ +	} + +#define SKINSETSECTION "SkinnedSettings" + +BOOL SkinDBGetContactSetting(MCONTACT hContact, const char* szSection, const char*szKey, DBVARIANT * retdbv, BOOL * bSkinned ) +{ +	if (!hContact) {  //only for not contact settings +		char *szSkinKey; +		NEWJOINEDSTR(szSkinKey, szSection, "@", szKey); +		if (!db_get(hContact, SKINSETSECTION, szSkinKey, retdbv))	{ +			if (bSkinned) *bSkinned = TRUE; +			return FALSE; +		} +	} +	// not skinned +	if (bSkinned) bSkinned = FALSE; +	return db_get(hContact, szSection, szKey, retdbv); +} + +BYTE SkinDBGetContactSettingByte(MCONTACT hContact, const char* szSection, const char*szKey, BYTE bDefault) +{ +	DBVARIANT dbv = { 0 }; +	BOOL bSkinned = FALSE; +	if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) { +		if (dbv.type == DBVT_BYTE) { +			BYTE retVal = dbv.bVal; +			db_free(&dbv); +			return retVal; +		} +		else { +			db_free(&dbv); +			if (!bSkinned) +				return db_get_b(hContact, szSection, szKey, bDefault); +		} +	} +	return bDefault; +} + +WORD SkinDBGetContactSettingWord(MCONTACT hContact, const char* szSection, const char*szKey, WORD wDefault) +{ +	BOOL bSkinned = FALSE; +	DBVARIANT dbv = { 0 }; +	if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) { +		if (dbv.type == DBVT_WORD)	{ +			WORD retVal = dbv.wVal; +			db_free(&dbv); +			return retVal; +		} +		db_free(&dbv); +		if (!bSkinned) +			return db_get_w(hContact, szSection, szKey, wDefault); +	} +	return wDefault; +} + +DWORD SkinDBGetContactSettingDword(MCONTACT hContact, const char* szSection, const char*szKey, DWORD dwDefault) +{ +	DBVARIANT dbv = { 0 }; +	BOOL bSkinned = FALSE; +	if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) { +		if (dbv.type == DBVT_DWORD)	{ +			DWORD retVal = dbv.dVal; +			db_free(&dbv); +			return retVal; +		} +		db_free(&dbv); +		if (!bSkinned) +			return db_get_dw(hContact, szSection, szKey, dwDefault); +	} +	return dwDefault; +} diff --git a/plugins/Clist_modern/src/modern_skinopt.cpp b/plugins/Clist_modern/src/modern_skinopt.cpp index 024f044373..a6611a96c8 100644 --- a/plugins/Clist_modern/src/modern_skinopt.cpp +++ b/plugins/Clist_modern/src/modern_skinopt.cpp @@ -1,568 +1,568 @@ -/*
 -
 -Miranda NG: the free IM client for Microsoft* Windows*
 -
 -Copyright (c) 2012-14 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 "hdr/modern_commonheaders.h"
 -#include "hdr/modern_clist.h"
 -#include "hdr/modern_commonprototypes.h"
 -#include "hdr/modern_sync.h"
 -
 -/*******************************/
 -// Main skin selection routine //
 -/*******************************/
 -#define MAX_NAME 100
 -typedef struct _SkinListData
 -{
 -	TCHAR Name[MAX_NAME];
 -	TCHAR File[MAX_PATH];
 -} SkinListData;
 -
 -HBITMAP hPreviewBitmap = NULL;
 -HTREEITEM AddItemToTree( HWND hTree, TCHAR * folder, TCHAR * itemName, void * data );
 -HTREEITEM AddSkinToListFullName( HWND hwndDlg, TCHAR * fullName );
 -HTREEITEM AddSkinToList( HWND hwndDlg, TCHAR * path, TCHAR* file );
 -HTREEITEM FillAvailableSkinList( HWND hwndDlg );
 -
 -INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
 -
 -int SkinOptInit(WPARAM wParam, LPARAM lParam)
 -{
 -	if (!g_CluiData.fDisableSkinEngine) {
 -		//Tabbed settings
 -		OPTIONSDIALOGPAGE odp = { sizeof(odp) };
 -		odp.position = -200000000;
 -		odp.hInstance = g_hInst;
 -		odp.pfnDlgProc = DlgSkinOpts;
 -		odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SKIN);
 -		odp.ptszGroup = LPGENT("Skins");
 -		odp.ptszTitle = LPGENT("Contact list");
 -		odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
 -		Options_AddPage(wParam, &odp);
 -	}
 -	return 0;
 -}
 -
 -int ModernSkinOptInit(WPARAM wParam, LPARAM lParam)
 -{
 -	MODERNOPTOBJECT obj = {0};
 -	obj.cbSize = sizeof(obj);
 -	obj.dwFlags = MODEROPT_FLG_TCHAR;
 -	obj.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
 -	obj.hInstance = g_hInst;
 -	obj.iSection = MODERNOPT_PAGE_SKINS;
 -	obj.iType = MODERNOPT_TYPE_SELECTORPAGE;
 -	obj.lptzSubsection = _T("Contact list");
 -	obj.lpzThemeExtension = ".msf";
 -	obj.lpzThemeModuleName = "ModernSkinSel";
 -	CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
 -	return 0;
 -}
 -INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 -{
 -	switch ( msg )
 -	{
 -	case WM_DESTROY:
 -		{
 -			if ( hPreviewBitmap ) ske_UnloadGlyphImage( hPreviewBitmap );
 -			break;
 -		}
 -
 -	case WM_INITDIALOG:
 -		{
 -			TranslateDialogDefault(hwndDlg);
 -			SetWindowText(GetDlgItem(hwndDlg, IDC_SKINFOLDERLABEL), SkinsFolder);
 -			HTREEITEM it = FillAvailableSkinList(hwndDlg);
 -			HWND wnd = GetDlgItem(hwndDlg, IDC_TREE1);
 -			TreeView_SelectItem(wnd, it);
 -		}
 -		return 0;
 -	case WM_COMMAND:
 -		{
 -			int isLoad = 0;
 -			switch ( LOWORD(wParam )) {
 -			case IDC_COLOUR_MENUNORMAL:
 -			case IDC_COLOUR_MENUSELECTED:
 -			case IDC_COLOUR_FRAMES:
 -			case IDC_COLOUR_STATUSBAR:
 -				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
 -				break;
 -
 -			case IDC_BUTTON_INFO:
 -				{
 -					TCHAR Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
 -					SkinListData *sd = NULL;
 -					HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 ));
 -					if ( hti == 0 ) return 0;
 -					{
 -						TVITEM tvi = {0};
 -						tvi.hItem = hti;
 -						tvi.mask = TVIF_HANDLE|TVIF_PARAM;
 -						TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi );
 -						sd = ( SkinListData* )( tvi.lParam);
 -					}
 -					if (!sd ) return 0;
 -					if ( sd->File && !_tcschr( sd->File, _T('%')))
 -					{
 -						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Author"), 	TranslateT("( unknown )"), 	Author, 		SIZEOF( Author ), 		sd->File );
 -						GetPrivateProfileString( _T("Skin_Description_Section"), _T("URL"), 		_T(""), 						URL, 		SIZEOF( URL ), 		sd->File );
 -						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Contact"), 	_T(""), 						Contact, 	SIZEOF( Contact ), 	sd->File );
 -						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Description"), _T(""), 					Description, SIZEOF( Description ), sd->File );
 -						mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAuthor(s):\t %s\nContact:\t %s\nWeb:\t %s\n\nFile:\t %s"),
 -							sd->Name, Description, Author, Contact, URL, sd->File);
 -					}
 -					else
 -					{
 -						mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAuthor(s): %s\nContact:\t %s\nWeb:\t %s\n\nFile:\t %s"),
 -							TranslateT("reVista for Modern v0.5"),
 -							TranslateT("This is second default Modern Contact list skin in Vista Aero style"),
 -							TranslateT("Angeli-Ka (graphics), FYR (template)"),
 -							_T("JID: fyr@jabber.ru"),
 -							_T("fyr.mirandaim.ru"),
 -							TranslateT("Inside library"));
 -					}
 -					MessageBox( hwndDlg, text, TranslateT("Skin Information"), MB_OK|MB_ICONINFORMATION );
 -				}
 -				break;
 -			case IDC_BUTTON_APPLY_SKIN:
 -				if ( HIWORD(wParam ) == BN_CLICKED )
 -				{
 -					SkinListData *sd = NULL;
 -					HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 ));
 -					if ( hti == 0 ) return 0;
 -					{
 -						TVITEM tvi = {0};
 -						tvi.hItem = hti;
 -						tvi.mask = TVIF_HANDLE|TVIF_PARAM;
 -						TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi );
 -						sd = ( SkinListData* )( tvi.lParam);
 -					}
 -					if (!sd ) return 0;
 -					ske_LoadSkinFromIniFile( sd->File, FALSE );
 -					ske_LoadSkinFromDB();
 -					pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0 );
 -					Sync( CLUIFrames_OnClistResize_mod, 0, 0 );
 -					ske_RedrawCompleteWindow( );
 -					Sync( CLUIFrames_OnClistResize_mod, 0, 0 );
 -					{
 -						HWND hwnd = pcli->hwndContactList;
 -						RECT rc = {0};
 -						GetWindowRect( hwnd, &rc );
 -						Sync( CLUIFrames_OnMoving, hwnd, &rc );
 -					}
 -					if ( g_hCLUIOptionsWnd )
 -					{
 -						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT ));
 -						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT ));
 -						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT ));
 -						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT ));
 -					}
 -				}
 -				break;
 -			case IDC_BUTTON_RESCAN:
 -				if (HIWORD(wParam ) == BN_CLICKED)
 -				{
 -					HTREEITEM it = FillAvailableSkinList(hwndDlg);
 -					HWND wnd = GetDlgItem(hwndDlg, IDC_TREE1);
 -					TreeView_SelectItem(wnd, it);
 -				}
 -			}
 -			break;
 -		}
 -	case WM_DRAWITEM:
 -		if ( wParam == IDC_PREVIEW )
 -		{
 -			//TODO:Draw hPreviewBitmap here
 -			int mWidth, mHeight;
 -			HBRUSH hbr = CreateSolidBrush( GetSysColor( COLOR_3DFACE ));
 -			DRAWITEMSTRUCT *dis = ( DRAWITEMSTRUCT * )lParam;
 -			mWidth = dis->rcItem.right-dis->rcItem.left;
 -			mHeight = dis->rcItem.bottom-dis->rcItem.top;
 -			HDC memDC = CreateCompatibleDC( dis->hDC );
 -			HBITMAP hbmp = ske_CreateDIB32( mWidth, mHeight );
 -			HBITMAP holdbmp = ( HBITMAP )SelectObject( memDC, hbmp );
 -			RECT workRect = dis->rcItem;
 -			OffsetRect( &workRect, -workRect.left, -workRect.top );
 -			FillRect( memDC, &workRect, hbr );
 -			DeleteObject( hbr );
 -			if ( hPreviewBitmap )
 -			{
 -				//variables
 -				BITMAP bmp = {0};
 -				POINT imgPos = {0};
 -				float xScale = 1, yScale = 1;
 -				//GetSize
 -				GetObject( hPreviewBitmap, sizeof( BITMAP ), &bmp );
 -				int wWidth = workRect.right-workRect.left;
 -				int wHeight = workRect.bottom-workRect.top;
 -				if ( wWidth < bmp.bmWidth ) xScale = ( float )wWidth/bmp.bmWidth;
 -				if ( wHeight < bmp.bmHeight ) yScale = ( float )wHeight/bmp.bmHeight;
 -				xScale = min( xScale, yScale );
 -				yScale = xScale;
 -				int dWidth = ( int )( xScale*bmp.bmWidth );
 -				int dHeight = ( int )( yScale*bmp.bmHeight );
 -				//CalcPosition
 -				imgPos.x = workRect.left+(( wWidth-dWidth )>>1 );
 -				imgPos.y = workRect.top+(( wHeight-dHeight )>>1 );
 -				//DrawImage
 -				DrawAvatarImageWithGDIp( memDC, imgPos.x, imgPos.y, dWidth, dHeight, hPreviewBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, 8, 255 );
 -			}
 -			BitBlt( dis->hDC, dis->rcItem.left, dis->rcItem.top, mWidth, mHeight, memDC, 0, 0, SRCCOPY );
 -			SelectObject( memDC, holdbmp );
 -			DeleteObject( hbmp );
 -			DeleteDC( memDC );
 -		}
 -		break;
 -
 -	case WM_NOTIFY:
 -		switch (( ( LPNMHDR )lParam)->idFrom ) {
 -		case IDC_TREE1:
 -			{
 -				NMTREEVIEW * nmtv = ( NMTREEVIEW * ) lParam;
 -				if (nmtv == NULL)
 -					return 0;
 -
 -				if (nmtv->hdr.code == TVN_SELCHANGEDA || nmtv->hdr.code == TVN_SELCHANGEDW) {
 -					SkinListData * sd = NULL;
 -					if (hPreviewBitmap) {
 -						ske_UnloadGlyphImage( hPreviewBitmap );
 -						hPreviewBitmap = NULL;
 -					}
 -
 -					if (nmtv->itemNew.lParam) {
 -						sd = ( SkinListData* )nmtv->itemNew.lParam;
 -
 -						TCHAR buf[MAX_PATH];
 -						PathToRelativeT(sd->File, buf);
 -						SetDlgItemText(hwndDlg,IDC_EDIT_SKIN_FILENAME,buf);
 -
 -						TCHAR prfn[MAX_PATH] = {0}, imfn[MAX_PATH] = {0}, skinfolder[MAX_PATH] = {0};
 -						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Preview"), _T(""), imfn, SIZEOF( imfn ), sd->File );
 -						IniParser::GetSkinFolder( sd->File, skinfolder );
 -						mir_sntprintf(prfn, SIZEOF(prfn), _T("%s\\%s"), skinfolder, imfn);
 -						PathToAbsoluteT(prfn, imfn);
 -						hPreviewBitmap = ske_LoadGlyphImage(imfn);
 -
 -						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_APPLY_SKIN ), TRUE );
 -						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_INFO ), TRUE );
 -						if ( hPreviewBitmap )
 -							InvalidateRect( GetDlgItem( hwndDlg, IDC_PREVIEW ), NULL, TRUE );
 -						else { //prepare text
 -							TCHAR Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
 -							SkinListData* sd = NULL;
 -							HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 ));
 -							if ( hti == 0 ) return 0;
 -							{
 -								TVITEM tvi = {0};
 -								tvi.hItem = hti;
 -								tvi.mask = TVIF_HANDLE|TVIF_PARAM;
 -								TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi );
 -								sd = ( SkinListData* )( tvi.lParam);
 -							}
 -							if (!sd ) return 0;
 -
 -							if ( sd->File && !_tcschr( sd->File, _T('%')))
 -							{
 -								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Author"), 	TranslateT("( unknown )"), 	Author, 		SIZEOF( Author ), 		sd->File );
 -								GetPrivateProfileString( _T("Skin_Description_Section"), _T("URL"), 		_T(""), 						URL, 		SIZEOF( URL ), 		sd->File );
 -								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Contact"), 	_T(""), 						Contact, 	SIZEOF( Contact ), 	sd->File );
 -								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Description"), _T(""), 					Description, SIZEOF( Description ), sd->File );
 -								mir_sntprintf(text, SIZEOF(text), TranslateT("Preview is not available\n\n%s\n----------------------\n\n%s\n\nAUTHOR(S):\n%s\n\nCONTACT:\n%s\n\nHOMEPAGE:\n%s"),
 -									sd->Name, Description, Author, Contact, URL);
 -							}
 -							else
 -							{
 -								mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAUTHORS:\n%s\n\nCONTACT:\n%s\n\nWEB:\n%s\n\n\n"),
 -									TranslateT("reVista for Modern v0.5"),
 -									TranslateT("This is second default Modern Contact list skin in Vista Aero style"),
 -									TranslateT("graphics by Angeli-Ka\ntemplate by FYR"),
 -									_T("JID: fyr@jabber.ru"),
 -									_T("fyr.mirandaim.ru"));
 -							}
 -							ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), SW_HIDE );
 -							ShowWindow( GetDlgItem( hwndDlg, IDC_STATIC_INFO ), SW_SHOW );
 -							SetDlgItemText(hwndDlg, IDC_STATIC_INFO, text);
 -						}
 -					}
 -					else {
 -						//no selected
 -						SetDlgItemText(hwndDlg, IDC_EDIT_SKIN_FILENAME, TranslateT("Select skin from list"));
 -						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_APPLY_SKIN ), FALSE );
 -						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_INFO ), FALSE );
 -						SetDlgItemText(hwndDlg, IDC_STATIC_INFO, TranslateT("Please select skin to apply"));
 -						ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), SW_HIDE );
 -					}
 -					ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), hPreviewBitmap?SW_SHOW:SW_HIDE );
 -					return 0;
 -				}
 -				else if (nmtv->hdr.code == TVN_DELETEITEMA || nmtv->hdr.code == TVN_DELETEITEMW) {
 -					mir_free_and_nil( nmtv->itemOld.lParam);
 -					return 0;
 -				}
 -			}
 -			break;
 -
 -		case 0:
 -			switch (((LPNMHDR)lParam)->code) {
 -			case PSN_APPLY:
 -				pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0 );
 -				NotifyEventHooks( g_CluiData.hEventBkgrChanged, 0, 0 );
 -				pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0 );
 -				RedrawWindow( GetParent( pcli->hwndContactTree ), NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN );
 -			}
 -			break;
 -		}
 -	}
 -	return 0;
 -}
 -
 -int SearchSkinFiles( HWND hwndDlg, TCHAR * Folder )
 -{
 -	struct _tfinddata_t fd = {0};
 -	TCHAR mask[MAX_PATH];
 -	long hFile;
 -	mir_sntprintf(mask, SIZEOF(mask), _T("%s\\*.msf"), Folder);
 -	//fd.attrib = _A_SUBDIR;
 -	hFile = _tfindfirst( mask, &fd );
 -	if ( hFile != -1 )
 -	{
 -		do {
 -			AddSkinToList( hwndDlg, Folder, fd.name );
 -		}
 -			while (!_tfindnext( hFile, &fd ));
 -		_findclose( hFile );
 -	}
 -	mir_sntprintf(mask, SIZEOF(mask), _T("%s\\*"), Folder);
 -	hFile = _tfindfirst( mask, &fd );
 -	{
 -		do {
 -			if ( fd.attrib&_A_SUBDIR && !( _tcsicmp( fd.name, _T("."))  == 0  || _tcsicmp( fd.name, _T("..")) == 0 ))
 -			{//Next level of subfolders
 -				TCHAR path[MAX_PATH];
 -				mir_sntprintf(path, SIZEOF(path), _T("%s\\%s"), Folder, fd.name);
 -				SearchSkinFiles( hwndDlg, path );
 -			}
 -		}while (!_tfindnext( hFile, &fd ));
 -		_findclose( hFile );
 -	}
 -	return 0;
 -}
 -
 -HTREEITEM FillAvailableSkinList(HWND hwndDlg)
 -{
 -	struct _finddata_t fd = {0};
 -	//long hFile;
 -	HTREEITEM res = (HTREEITEM)-1;
 -	int attrib;
 -
 -	TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_TREE1));
 -	AddSkinToList(hwndDlg, TranslateT("Default Skin"), _T("%Default Skin%"));
 -	attrib = GetFileAttributes(SkinsFolder);
 -	if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY))
 -		SearchSkinFiles(hwndDlg, SkinsFolder);
 -	{
 -		TCHAR skinfull[MAX_PATH];
 -		ptrT skinfile( db_get_tsa( NULL, SKIN, "SkinFile"));
 -		if (skinfile) {
 -			PathToAbsoluteT(skinfile, skinfull);
 -			res = AddSkinToListFullName(hwndDlg, skinfull);
 -		}
 -	}
 -	return res;
 -}
 -HTREEITEM AddSkinToListFullName( HWND hwndDlg, TCHAR * fullName )
 -{
 -	TCHAR path[MAX_PATH] = {0};
 -	TCHAR file[MAX_PATH] = {0};
 -	TCHAR *buf;
 -	_tcsncpy( path, fullName, SIZEOF( path ));
 -	buf = path + _tcslen( path );
 -	while ( buf > path )
 -	{
 -		if ( *buf == _T( '\\' ))
 -		{
 -			*buf = _T( '\0' );
 -			break;
 -		}
 -		buf--;
 -	}
 -	buf++;
 -	_tcsncpy( file, buf, SIZEOF( file ));
 -	return AddSkinToList( hwndDlg, path, file );
 -}
 -
 -
 -HTREEITEM AddSkinToList( HWND hwndDlg, TCHAR * path, TCHAR* file )
 -{
 -	SkinListData *sd = ( SkinListData * )mir_alloc( sizeof( SkinListData ));
 -	if (!sd )
 -		return 0;
 -
 -	TCHAR fullName[MAX_PATH], defskinname[MAX_PATH];
 -	mir_sntprintf(fullName, SIZEOF(fullName), _T("%s\\%s"), path, file);
 -	memmove(defskinname, file, (_tcslen( file )-4) * sizeof(TCHAR));
 -	defskinname[_tcslen( file )+1] = _T('\0');
 -	if (!file || _tcschr( file, _T('%'))) {
 -		mir_sntprintf(sd->File, MAX_PATH, _T("%%Default Skin%%"));
 -		mir_sntprintf(sd->Name, 100, TranslateT("%Default Skin%"));
 -		_tcsncpy(fullName, TranslateT("Default Skin"), SIZEOF(fullName));
 -	}
 -	else {
 -		GetPrivateProfileString( _T("Skin_Description_Section"), _T("Name"), defskinname, sd->Name, SIZEOF( sd->Name ), fullName );
 -		_tcscpy(sd->File, fullName);
 -	}
 -	return AddItemToTree( GetDlgItem( hwndDlg, IDC_TREE1 ), fullName, sd->Name, sd );
 -}
 -
 -HTREEITEM FindChild( HWND hTree, HTREEITEM Parent, TCHAR * Caption, void * data )
 -{
 -	HTREEITEM res = NULL, tmp = NULL;
 -	if ( Parent )
 -		tmp = TreeView_GetChild( hTree, Parent );
 -	else
 -		tmp = TreeView_GetRoot( hTree );
 -
 -	while (tmp) {
 -		TVITEM tvi;
 -		TCHAR buf[255];
 -		tvi.hItem = tmp;
 -		tvi.mask = TVIF_TEXT|TVIF_HANDLE;
 -		tvi.pszText = (LPTSTR)&buf;
 -		tvi.cchTextMax = 254;
 -		TreeView_GetItem( hTree, &tvi );
 -		if ( _tcsicmp(Caption, tvi.pszText) == 0) {
 -			if (!data)
 -				return tmp;
 -
 -			TVITEM tvi = {0};
 -			tvi.hItem = tmp;
 -			tvi.mask = TVIF_HANDLE|TVIF_PARAM;
 -			TreeView_GetItem(hTree, &tvi);
 -			SkinListData *sd = (SkinListData*)tvi.lParam;
 -			if (sd)
 -				if (!_tcsicmp(sd->File, (( SkinListData* )data )->File))
 -					return tmp;
 -		}
 -		tmp = TreeView_GetNextSibling(hTree, tmp);
 -	}
 -	return tmp;
 -}
 -
 -HTREEITEM AddItemToTree(HWND hTree, TCHAR *folder, TCHAR *itemName, void *data)
 -{
 -	HTREEITEM cItem = NULL;
 -	//Insert item node
 -	cItem = FindChild( hTree, 0, itemName, data );
 -	if (!cItem) {
 -		TVINSERTSTRUCT tvis = {0};
 -		tvis.hInsertAfter = TVI_SORT;
 -		tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_PARAM;
 -		tvis.item.pszText = itemName;
 -		tvis.item.lParam = (LPARAM)data;
 -		return TreeView_InsertItem(hTree, &tvis);
 -	}
 -
 -	mir_free(data); //need to free otherwise memory leak
 -	return cItem;
 -}
 -
 -INT_PTR SvcActiveSkin(WPARAM wParam, LPARAM lParam)
 -{
 -	ptrT skinfile( db_get_tsa(NULL, SKIN, "SkinFile"));
 -	if (skinfile) {
 -		TCHAR skinfull[MAX_PATH];
 -		PathToAbsoluteT(skinfile, skinfull);
 -		return (INT_PTR)mir_tstrdup(skinfull);
 -	}
 -
 -	return NULL;
 -}
 -
 -INT_PTR SvcApplySkin(WPARAM wParam, LPARAM lParam)
 -{
 -	ske_LoadSkinFromIniFile((TCHAR *)lParam, FALSE);
 -	ske_LoadSkinFromDB( );
 -	pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0 );
 -	Sync( CLUIFrames_OnClistResize_mod, 0, 0 );
 -	ske_RedrawCompleteWindow( );
 -	Sync( CLUIFrames_OnClistResize_mod, 0, 0 );
 -
 -	HWND hwnd = pcli->hwndContactList;
 -	RECT rc = {0};
 -	GetWindowRect( hwnd, &rc );
 -	Sync( CLUIFrames_OnMoving, hwnd, &rc );
 -
 -	if (g_hCLUIOptionsWnd) {
 -		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT ));
 -		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT ));
 -		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT ));
 -		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT ));
 -	}
 -	return 0;
 -}
 -
 -INT_PTR SvcPreviewSkin(WPARAM wParam, LPARAM lParam)
 -{
 -	DRAWITEMSTRUCT *dis = ( DRAWITEMSTRUCT * )wParam;
 -	int mWidth = dis->rcItem.right-dis->rcItem.left;
 -	int mHeight = dis->rcItem.bottom-dis->rcItem.top;
 -	RECT workRect = dis->rcItem;
 -	OffsetRect( &workRect, -workRect.left, -workRect.top );
 -
 -	if (lParam) {
 -		TCHAR prfn[MAX_PATH] = {0};
 -		TCHAR imfn[MAX_PATH] = {0};
 -		TCHAR skinfolder[MAX_PATH] = {0};
 -		GetPrivateProfileString( _T("Skin_Description_Section"), _T("Preview"), _T(""), imfn, SIZEOF( imfn ), (LPCTSTR)lParam);
 -		IniParser::GetSkinFolder((LPCTSTR)lParam, skinfolder );
 -		mir_sntprintf(prfn, SIZEOF(prfn), _T("%s\\%s"), skinfolder, imfn);
 -		PathToAbsoluteT(prfn, imfn);
 -
 -		hPreviewBitmap = ske_LoadGlyphImage(imfn);
 -		if (hPreviewBitmap) {
 -			//variables
 -			BITMAP bmp = {0};
 -			POINT imgPos = {0};
 -			int wWidth, wHeight;
 -			int dWidth, dHeight;
 -			float xScale = 1, yScale = 1;
 -			//GetSize
 -			GetObject( hPreviewBitmap, sizeof( BITMAP ), &bmp );
 -			wWidth = workRect.right-workRect.left;
 -			wHeight = workRect.bottom-workRect.top;
 -			if ( wWidth < bmp.bmWidth ) xScale = ( float )wWidth/bmp.bmWidth;
 -			if ( wHeight < bmp.bmHeight ) yScale = ( float )wHeight/bmp.bmHeight;
 -			xScale = min( xScale, yScale );
 -			yScale = xScale;
 -			dWidth = ( int )( xScale*bmp.bmWidth );
 -			dHeight = ( int )( yScale*bmp.bmHeight );
 -			//CalcPosition
 -			imgPos.x = workRect.left+(( wWidth-dWidth )>>1 );
 -			imgPos.y = workRect.top+(( wHeight-dHeight )>>1 );
 -			//DrawImage
 -			DrawAvatarImageWithGDIp( dis->hDC, imgPos.x, imgPos.y, dWidth, dHeight, hPreviewBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, 8, 255 );
 -			ske_UnloadGlyphImage(hPreviewBitmap);
 -		}
 -	}
 -
 -	return 0;
 -}
 +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-14 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 "hdr/modern_commonheaders.h" +#include "hdr/modern_clist.h" +#include "hdr/modern_commonprototypes.h" +#include "hdr/modern_sync.h" + +/*******************************/ +// Main skin selection routine // +/*******************************/ +#define MAX_NAME 100 +typedef struct _SkinListData +{ +	TCHAR Name[MAX_NAME]; +	TCHAR File[MAX_PATH]; +} SkinListData; + +HBITMAP hPreviewBitmap = NULL; +HTREEITEM AddItemToTree( HWND hTree, TCHAR * folder, TCHAR * itemName, void * data ); +HTREEITEM AddSkinToListFullName( HWND hwndDlg, TCHAR * fullName ); +HTREEITEM AddSkinToList( HWND hwndDlg, TCHAR * path, TCHAR* file ); +HTREEITEM FillAvailableSkinList( HWND hwndDlg ); + +INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +int SkinOptInit(WPARAM wParam, LPARAM lParam) +{ +	if (!g_CluiData.fDisableSkinEngine) { +		//Tabbed settings +		OPTIONSDIALOGPAGE odp = { sizeof(odp) }; +		odp.position = -200000000; +		odp.hInstance = g_hInst; +		odp.pfnDlgProc = DlgSkinOpts; +		odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SKIN); +		odp.ptszGroup = LPGENT("Skins"); +		odp.ptszTitle = LPGENT("Contact list"); +		odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; +		Options_AddPage(wParam, &odp); +	} +	return 0; +} + +int ModernSkinOptInit(WPARAM wParam, LPARAM lParam) +{ +	MODERNOPTOBJECT obj = {0}; +	obj.cbSize = sizeof(obj); +	obj.dwFlags = MODEROPT_FLG_TCHAR; +	obj.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA); +	obj.hInstance = g_hInst; +	obj.iSection = MODERNOPT_PAGE_SKINS; +	obj.iType = MODERNOPT_TYPE_SELECTORPAGE; +	obj.lptzSubsection = _T("Contact list"); +	obj.lpzThemeExtension = ".msf"; +	obj.lpzThemeModuleName = "ModernSkinSel"; +	CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj); +	return 0; +} +INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ +	switch ( msg ) +	{ +	case WM_DESTROY: +		{ +			if ( hPreviewBitmap ) ske_UnloadGlyphImage( hPreviewBitmap ); +			break; +		} + +	case WM_INITDIALOG: +		{ +			TranslateDialogDefault(hwndDlg); +			SetWindowText(GetDlgItem(hwndDlg, IDC_SKINFOLDERLABEL), SkinsFolder); +			HTREEITEM it = FillAvailableSkinList(hwndDlg); +			HWND wnd = GetDlgItem(hwndDlg, IDC_TREE1); +			TreeView_SelectItem(wnd, it); +		} +		return 0; +	case WM_COMMAND: +		{ +			int isLoad = 0; +			switch ( LOWORD(wParam )) { +			case IDC_COLOUR_MENUNORMAL: +			case IDC_COLOUR_MENUSELECTED: +			case IDC_COLOUR_FRAMES: +			case IDC_COLOUR_STATUSBAR: +				SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); +				break; + +			case IDC_BUTTON_INFO: +				{ +					TCHAR Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000]; +					SkinListData *sd = NULL; +					HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 )); +					if ( hti == 0 ) return 0; +					{ +						TVITEM tvi = {0}; +						tvi.hItem = hti; +						tvi.mask = TVIF_HANDLE|TVIF_PARAM; +						TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi ); +						sd = ( SkinListData* )( tvi.lParam); +					} +					if (!sd ) return 0; +					if ( sd->File && !_tcschr( sd->File, _T('%'))) +					{ +						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Author"), 	TranslateT("( unknown )"), 	Author, 		SIZEOF( Author ), 		sd->File ); +						GetPrivateProfileString( _T("Skin_Description_Section"), _T("URL"), 		_T(""), 						URL, 		SIZEOF( URL ), 		sd->File ); +						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Contact"), 	_T(""), 						Contact, 	SIZEOF( Contact ), 	sd->File ); +						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Description"), _T(""), 					Description, SIZEOF( Description ), sd->File ); +						mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAuthor(s):\t %s\nContact:\t %s\nWeb:\t %s\n\nFile:\t %s"), +							sd->Name, Description, Author, Contact, URL, sd->File); +					} +					else +					{ +						mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAuthor(s): %s\nContact:\t %s\nWeb:\t %s\n\nFile:\t %s"), +							TranslateT("reVista for Modern v0.5"), +							TranslateT("This is second default Modern Contact list skin in Vista Aero style"), +							TranslateT("Angeli-Ka (graphics), FYR (template)"), +							_T("JID: fyr@jabber.ru"), +							_T("fyr.mirandaim.ru"), +							TranslateT("Inside library")); +					} +					MessageBox( hwndDlg, text, TranslateT("Skin Information"), MB_OK|MB_ICONINFORMATION ); +				} +				break; +			case IDC_BUTTON_APPLY_SKIN: +				if ( HIWORD(wParam ) == BN_CLICKED ) +				{ +					SkinListData *sd = NULL; +					HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 )); +					if ( hti == 0 ) return 0; +					{ +						TVITEM tvi = {0}; +						tvi.hItem = hti; +						tvi.mask = TVIF_HANDLE|TVIF_PARAM; +						TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi ); +						sd = ( SkinListData* )( tvi.lParam); +					} +					if (!sd ) return 0; +					ske_LoadSkinFromIniFile( sd->File, FALSE ); +					ske_LoadSkinFromDB(); +					pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0 ); +					Sync( CLUIFrames_OnClistResize_mod, 0, 0 ); +					ske_RedrawCompleteWindow( ); +					Sync( CLUIFrames_OnClistResize_mod, 0, 0 ); +					{ +						HWND hwnd = pcli->hwndContactList; +						RECT rc = {0}; +						GetWindowRect( hwnd, &rc ); +						Sync( CLUIFrames_OnMoving, hwnd, &rc ); +					} +					if ( g_hCLUIOptionsWnd ) +					{ +						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT )); +						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT )); +						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT )); +						SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT )); +					} +				} +				break; +			case IDC_BUTTON_RESCAN: +				if (HIWORD(wParam ) == BN_CLICKED) +				{ +					HTREEITEM it = FillAvailableSkinList(hwndDlg); +					HWND wnd = GetDlgItem(hwndDlg, IDC_TREE1); +					TreeView_SelectItem(wnd, it); +				} +			} +			break; +		} +	case WM_DRAWITEM: +		if ( wParam == IDC_PREVIEW ) +		{ +			//TODO:Draw hPreviewBitmap here +			int mWidth, mHeight; +			HBRUSH hbr = CreateSolidBrush( GetSysColor( COLOR_3DFACE )); +			DRAWITEMSTRUCT *dis = ( DRAWITEMSTRUCT * )lParam; +			mWidth = dis->rcItem.right-dis->rcItem.left; +			mHeight = dis->rcItem.bottom-dis->rcItem.top; +			HDC memDC = CreateCompatibleDC( dis->hDC ); +			HBITMAP hbmp = ske_CreateDIB32( mWidth, mHeight ); +			HBITMAP holdbmp = ( HBITMAP )SelectObject( memDC, hbmp ); +			RECT workRect = dis->rcItem; +			OffsetRect( &workRect, -workRect.left, -workRect.top ); +			FillRect( memDC, &workRect, hbr ); +			DeleteObject( hbr ); +			if ( hPreviewBitmap ) +			{ +				//variables +				BITMAP bmp = {0}; +				POINT imgPos = {0}; +				float xScale = 1, yScale = 1; +				//GetSize +				GetObject( hPreviewBitmap, sizeof( BITMAP ), &bmp ); +				int wWidth = workRect.right-workRect.left; +				int wHeight = workRect.bottom-workRect.top; +				if ( wWidth < bmp.bmWidth ) xScale = ( float )wWidth/bmp.bmWidth; +				if ( wHeight < bmp.bmHeight ) yScale = ( float )wHeight/bmp.bmHeight; +				xScale = min( xScale, yScale ); +				yScale = xScale; +				int dWidth = ( int )( xScale*bmp.bmWidth ); +				int dHeight = ( int )( yScale*bmp.bmHeight ); +				//CalcPosition +				imgPos.x = workRect.left+(( wWidth-dWidth )>>1 ); +				imgPos.y = workRect.top+(( wHeight-dHeight )>>1 ); +				//DrawImage +				DrawAvatarImageWithGDIp( memDC, imgPos.x, imgPos.y, dWidth, dHeight, hPreviewBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, 8, 255 ); +			} +			BitBlt( dis->hDC, dis->rcItem.left, dis->rcItem.top, mWidth, mHeight, memDC, 0, 0, SRCCOPY ); +			SelectObject( memDC, holdbmp ); +			DeleteObject( hbmp ); +			DeleteDC( memDC ); +		} +		break; + +	case WM_NOTIFY: +		switch (( ( LPNMHDR )lParam)->idFrom ) { +		case IDC_TREE1: +			{ +				NMTREEVIEW * nmtv = ( NMTREEVIEW * ) lParam; +				if (nmtv == NULL) +					return 0; + +				if (nmtv->hdr.code == TVN_SELCHANGEDA || nmtv->hdr.code == TVN_SELCHANGEDW) { +					SkinListData * sd = NULL; +					if (hPreviewBitmap) { +						ske_UnloadGlyphImage( hPreviewBitmap ); +						hPreviewBitmap = NULL; +					} + +					if (nmtv->itemNew.lParam) { +						sd = ( SkinListData* )nmtv->itemNew.lParam; + +						TCHAR buf[MAX_PATH]; +						PathToRelativeT(sd->File, buf); +						SetDlgItemText(hwndDlg,IDC_EDIT_SKIN_FILENAME,buf); + +						TCHAR prfn[MAX_PATH] = {0}, imfn[MAX_PATH] = {0}, skinfolder[MAX_PATH] = {0}; +						GetPrivateProfileString( _T("Skin_Description_Section"), _T("Preview"), _T(""), imfn, SIZEOF( imfn ), sd->File ); +						IniParser::GetSkinFolder( sd->File, skinfolder ); +						mir_sntprintf(prfn, SIZEOF(prfn), _T("%s\\%s"), skinfolder, imfn); +						PathToAbsoluteT(prfn, imfn); +						hPreviewBitmap = ske_LoadGlyphImage(imfn); + +						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_APPLY_SKIN ), TRUE ); +						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_INFO ), TRUE ); +						if ( hPreviewBitmap ) +							InvalidateRect( GetDlgItem( hwndDlg, IDC_PREVIEW ), NULL, TRUE ); +						else { //prepare text +							TCHAR Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000]; +							SkinListData* sd = NULL; +							HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg, IDC_TREE1 )); +							if ( hti == 0 ) return 0; +							{ +								TVITEM tvi = {0}; +								tvi.hItem = hti; +								tvi.mask = TVIF_HANDLE|TVIF_PARAM; +								TreeView_GetItem( GetDlgItem( hwndDlg, IDC_TREE1 ), &tvi ); +								sd = ( SkinListData* )( tvi.lParam); +							} +							if (!sd ) return 0; + +							if ( sd->File && !_tcschr( sd->File, _T('%'))) +							{ +								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Author"), 	TranslateT("( unknown )"), 	Author, 		SIZEOF( Author ), 		sd->File ); +								GetPrivateProfileString( _T("Skin_Description_Section"), _T("URL"), 		_T(""), 						URL, 		SIZEOF( URL ), 		sd->File ); +								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Contact"), 	_T(""), 						Contact, 	SIZEOF( Contact ), 	sd->File ); +								GetPrivateProfileString( _T("Skin_Description_Section"), _T("Description"), _T(""), 					Description, SIZEOF( Description ), sd->File ); +								mir_sntprintf(text, SIZEOF(text), TranslateT("Preview is not available\n\n%s\n----------------------\n\n%s\n\nAUTHOR(S):\n%s\n\nCONTACT:\n%s\n\nHOMEPAGE:\n%s"), +									sd->Name, Description, Author, Contact, URL); +							} +							else +							{ +								mir_sntprintf(text, SIZEOF(text), TranslateT("%s\n\n%s\n\nAUTHORS:\n%s\n\nCONTACT:\n%s\n\nWEB:\n%s\n\n\n"), +									TranslateT("reVista for Modern v0.5"), +									TranslateT("This is second default Modern Contact list skin in Vista Aero style"), +									TranslateT("graphics by Angeli-Ka\ntemplate by FYR"), +									_T("JID: fyr@jabber.ru"), +									_T("fyr.mirandaim.ru")); +							} +							ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), SW_HIDE ); +							ShowWindow( GetDlgItem( hwndDlg, IDC_STATIC_INFO ), SW_SHOW ); +							SetDlgItemText(hwndDlg, IDC_STATIC_INFO, text); +						} +					} +					else { +						//no selected +						SetDlgItemText(hwndDlg, IDC_EDIT_SKIN_FILENAME, TranslateT("Select skin from list")); +						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_APPLY_SKIN ), FALSE ); +						EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_INFO ), FALSE ); +						SetDlgItemText(hwndDlg, IDC_STATIC_INFO, TranslateT("Please select skin to apply")); +						ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), SW_HIDE ); +					} +					ShowWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), hPreviewBitmap?SW_SHOW:SW_HIDE ); +					return 0; +				} +				else if (nmtv->hdr.code == TVN_DELETEITEMA || nmtv->hdr.code == TVN_DELETEITEMW) { +					mir_free_and_nil( nmtv->itemOld.lParam); +					return 0; +				} +			} +			break; + +		case 0: +			switch (((LPNMHDR)lParam)->code) { +			case PSN_APPLY: +				pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0 ); +				NotifyEventHooks( g_CluiData.hEventBkgrChanged, 0, 0 ); +				pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0 ); +				RedrawWindow( GetParent( pcli->hwndContactTree ), NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_ALLCHILDREN ); +			} +			break; +		} +	} +	return 0; +} + +int SearchSkinFiles( HWND hwndDlg, TCHAR * Folder ) +{ +	struct _tfinddata_t fd = {0}; +	TCHAR mask[MAX_PATH]; +	long hFile; +	mir_sntprintf(mask, SIZEOF(mask), _T("%s\\*.msf"), Folder); +	//fd.attrib = _A_SUBDIR; +	hFile = _tfindfirst( mask, &fd ); +	if ( hFile != -1 ) +	{ +		do { +			AddSkinToList( hwndDlg, Folder, fd.name ); +		} +			while (!_tfindnext( hFile, &fd )); +		_findclose( hFile ); +	} +	mir_sntprintf(mask, SIZEOF(mask), _T("%s\\*"), Folder); +	hFile = _tfindfirst( mask, &fd ); +	{ +		do { +			if ( fd.attrib&_A_SUBDIR && !( _tcsicmp( fd.name, _T("."))  == 0  || _tcsicmp( fd.name, _T("..")) == 0 )) +			{//Next level of subfolders +				TCHAR path[MAX_PATH]; +				mir_sntprintf(path, SIZEOF(path), _T("%s\\%s"), Folder, fd.name); +				SearchSkinFiles( hwndDlg, path ); +			} +		}while (!_tfindnext( hFile, &fd )); +		_findclose( hFile ); +	} +	return 0; +} + +HTREEITEM FillAvailableSkinList(HWND hwndDlg) +{ +	struct _finddata_t fd = {0}; +	//long hFile; +	HTREEITEM res = (HTREEITEM)-1; +	int attrib; + +	TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_TREE1)); +	AddSkinToList(hwndDlg, TranslateT("Default Skin"), _T("%Default Skin%")); +	attrib = GetFileAttributes(SkinsFolder); +	if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY)) +		SearchSkinFiles(hwndDlg, SkinsFolder); +	{ +		TCHAR skinfull[MAX_PATH]; +		ptrT skinfile( db_get_tsa( NULL, SKIN, "SkinFile")); +		if (skinfile) { +			PathToAbsoluteT(skinfile, skinfull); +			res = AddSkinToListFullName(hwndDlg, skinfull); +		} +	} +	return res; +} +HTREEITEM AddSkinToListFullName( HWND hwndDlg, TCHAR * fullName ) +{ +	TCHAR path[MAX_PATH] = {0}; +	TCHAR file[MAX_PATH] = {0}; +	TCHAR *buf; +	_tcsncpy( path, fullName, SIZEOF( path )); +	buf = path + _tcslen( path ); +	while ( buf > path ) +	{ +		if ( *buf == _T( '\\' )) +		{ +			*buf = _T( '\0' ); +			break; +		} +		buf--; +	} +	buf++; +	_tcsncpy( file, buf, SIZEOF( file )); +	return AddSkinToList( hwndDlg, path, file ); +} + + +HTREEITEM AddSkinToList( HWND hwndDlg, TCHAR * path, TCHAR* file ) +{ +	TCHAR fullName[MAX_PATH], defskinname[MAX_PATH]; +	SkinListData *sd = ( SkinListData * )mir_alloc( sizeof( SkinListData )); +	if (!sd ) +		return 0; + +	if (!file || _tcschr( file, _T('%'))) { +		mir_sntprintf(sd->File, MAX_PATH, _T("%%Default Skin%%")); +		mir_sntprintf(sd->Name, 100, TranslateT("%Default Skin%")); +		_tcsncpy(fullName, TranslateT("Default Skin"), SIZEOF(fullName)); +	} +	else { +		mir_sntprintf(fullName, SIZEOF(fullName), _T("%s\\%s"), path, file); +		memcpy(defskinname, file, (_tcslen( file )-4) * sizeof(TCHAR)); +		defskinname[_tcslen( file )+1] = _T('\0'); +		GetPrivateProfileString( _T("Skin_Description_Section"), _T("Name"), defskinname, sd->Name, SIZEOF( sd->Name ), fullName ); +		_tcscpy(sd->File, fullName); +	} +	return AddItemToTree( GetDlgItem( hwndDlg, IDC_TREE1 ), fullName, sd->Name, sd ); +} + +HTREEITEM FindChild( HWND hTree, HTREEITEM Parent, TCHAR * Caption, void * data ) +{ +	HTREEITEM res = NULL, tmp = NULL; +	if ( Parent ) +		tmp = TreeView_GetChild( hTree, Parent ); +	else +		tmp = TreeView_GetRoot( hTree ); + +	while (tmp) { +		TVITEM tvi; +		TCHAR buf[255]; +		tvi.hItem = tmp; +		tvi.mask = TVIF_TEXT|TVIF_HANDLE; +		tvi.pszText = (LPTSTR)&buf; +		tvi.cchTextMax = 254; +		TreeView_GetItem( hTree, &tvi ); +		if ( _tcsicmp(Caption, tvi.pszText) == 0) { +			if (!data) +				return tmp; + +			TVITEM tvi = {0}; +			tvi.hItem = tmp; +			tvi.mask = TVIF_HANDLE|TVIF_PARAM; +			TreeView_GetItem(hTree, &tvi); +			SkinListData *sd = (SkinListData*)tvi.lParam; +			if (sd) +				if (!_tcsicmp(sd->File, (( SkinListData* )data )->File)) +					return tmp; +		} +		tmp = TreeView_GetNextSibling(hTree, tmp); +	} +	return tmp; +} + +HTREEITEM AddItemToTree(HWND hTree, TCHAR *folder, TCHAR *itemName, void *data) +{ +	HTREEITEM cItem = NULL; +	//Insert item node +	cItem = FindChild( hTree, 0, itemName, data ); +	if (!cItem) { +		TVINSERTSTRUCT tvis = {0}; +		tvis.hInsertAfter = TVI_SORT; +		tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_PARAM; +		tvis.item.pszText = itemName; +		tvis.item.lParam = (LPARAM)data; +		return TreeView_InsertItem(hTree, &tvis); +	} + +	mir_free(data); //need to free otherwise memory leak +	return cItem; +} + +INT_PTR SvcActiveSkin(WPARAM wParam, LPARAM lParam) +{ +	ptrT skinfile( db_get_tsa(NULL, SKIN, "SkinFile")); +	if (skinfile) { +		TCHAR skinfull[MAX_PATH]; +		PathToAbsoluteT(skinfile, skinfull); +		return (INT_PTR)mir_tstrdup(skinfull); +	} + +	return NULL; +} + +INT_PTR SvcApplySkin(WPARAM wParam, LPARAM lParam) +{ +	ske_LoadSkinFromIniFile((TCHAR *)lParam, FALSE); +	ske_LoadSkinFromDB( ); +	pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0 ); +	Sync( CLUIFrames_OnClistResize_mod, 0, 0 ); +	ske_RedrawCompleteWindow( ); +	Sync( CLUIFrames_OnClistResize_mod, 0, 0 ); + +	HWND hwnd = pcli->hwndContactList; +	RECT rc = {0}; +	GetWindowRect( hwnd, &rc ); +	Sync( CLUIFrames_OnMoving, hwnd, &rc ); + +	if (g_hCLUIOptionsWnd) { +		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT )); +		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT )); +		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT )); +		SendDlgItemMessage( g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b( NULL, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT )); +	} +	return 0; +} + +INT_PTR SvcPreviewSkin(WPARAM wParam, LPARAM lParam) +{ +	DRAWITEMSTRUCT *dis = ( DRAWITEMSTRUCT * )wParam; +	int mWidth = dis->rcItem.right-dis->rcItem.left; +	int mHeight = dis->rcItem.bottom-dis->rcItem.top; +	RECT workRect = dis->rcItem; +	OffsetRect( &workRect, -workRect.left, -workRect.top ); + +	if (lParam) { +		TCHAR prfn[MAX_PATH] = {0}; +		TCHAR imfn[MAX_PATH] = {0}; +		TCHAR skinfolder[MAX_PATH] = {0}; +		GetPrivateProfileString( _T("Skin_Description_Section"), _T("Preview"), _T(""), imfn, SIZEOF( imfn ), (LPCTSTR)lParam); +		IniParser::GetSkinFolder((LPCTSTR)lParam, skinfolder ); +		mir_sntprintf(prfn, SIZEOF(prfn), _T("%s\\%s"), skinfolder, imfn); +		PathToAbsoluteT(prfn, imfn); + +		hPreviewBitmap = ske_LoadGlyphImage(imfn); +		if (hPreviewBitmap) { +			//variables +			BITMAP bmp = {0}; +			POINT imgPos = {0}; +			int wWidth, wHeight; +			int dWidth, dHeight; +			float xScale = 1, yScale = 1; +			//GetSize +			GetObject( hPreviewBitmap, sizeof( BITMAP ), &bmp ); +			wWidth = workRect.right-workRect.left; +			wHeight = workRect.bottom-workRect.top; +			if ( wWidth < bmp.bmWidth ) xScale = ( float )wWidth/bmp.bmWidth; +			if ( wHeight < bmp.bmHeight ) yScale = ( float )wHeight/bmp.bmHeight; +			xScale = min( xScale, yScale ); +			yScale = xScale; +			dWidth = ( int )( xScale*bmp.bmWidth ); +			dHeight = ( int )( yScale*bmp.bmHeight ); +			//CalcPosition +			imgPos.x = workRect.left+(( wWidth-dWidth )>>1 ); +			imgPos.y = workRect.top+(( wHeight-dHeight )>>1 ); +			//DrawImage +			DrawAvatarImageWithGDIp( dis->hDC, imgPos.x, imgPos.y, dWidth, dHeight, hPreviewBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, 8, 255 ); +			ske_UnloadGlyphImage(hPreviewBitmap); +		} +	} + +	return 0; +}  | 
