From 117cf2ba6883c5b3ff8b275f4c56eb562a219b95 Mon Sep 17 00:00:00 2001 From: Rozhuk Ivan Date: Thu, 27 Nov 2014 00:44:57 +0000 Subject: Clist_modern: code cleanup, review required git-svn-id: http://svn.miranda-ng.org/main/trunk@11113 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Clist_modern/src/modern_cachefuncs.cpp | 1804 +++--- plugins/Clist_modern/src/modern_clc.cpp | 3776 +++++------ plugins/Clist_modern/src/modern_clcitems.cpp | 1493 +++-- plugins/Clist_modern/src/modern_row.cpp | 1523 ++--- plugins/Clist_modern/src/modern_skinbutton.cpp | 1532 ++--- plugins/Clist_modern/src/modern_skinengine.cpp | 8285 ++++++++++++------------ plugins/Clist_modern/src/modern_skinopt.cpp | 1136 ++-- 7 files changed, 9776 insertions(+), 9773 deletions(-) (limited to 'plugins') 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] - 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("")); RemoveTag(to,_T("")); - RemoveTag(to,_T("")); RemoveTag(to,_T("")); - RemoveTag(to,_T("")); RemoveTag(to,_T("")); - - 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("")); RemoveTag(to,_T("")); - RemoveTag(to,_T("")); RemoveTag(to,_T("")); - RemoveTag(to,_T("")); RemoveTag(to,_T("")); - 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] + 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("")); RemoveTag(to,_T("")); + RemoveTag(to,_T("")); RemoveTag(to,_T("")); + RemoveTag(to,_T("")); RemoveTag(to,_T("")); + + 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("")); RemoveTag(to,_T("")); + RemoveTag(to,_T("")); RemoveTag(to,_T("")); + RemoveTag(to,_T("")); RemoveTag(to,_T("")); + 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 savedGroup(4); - OBJLIST savedContact(4); - OBJLIST 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 savedGroup(4); + OBJLIST savedContact(4); + OBJLIST 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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, "", strlen(word))) cont = TC_ROW; - else if (!_strnicmp(word, "", strlen(word))) cont = TC_COL; - else if (!_strnicmp(word, "/>", strlen(word)) || - !_strnicmp(word, "", strlen(word)) || - !_strnicmp(word, "", 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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, "", strlen(word))) cont = TC_ROW; + else if (!_strnicmp(word, "", strlen(word))) cont = TC_COL; + else if (!_strnicmp(word, "/>", strlen(word)) || + !_strnicmp(word, "", strlen(word)) || + !_strnicmp(word, "", 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 -#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 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 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 +#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 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 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; +} -- cgit v1.2.3