summaryrefslogtreecommitdiff
path: root/plugins/Clist_modern/src
diff options
context:
space:
mode:
authorRozhuk Ivan <rozhuk.im@gmail.com>2014-11-27 00:44:57 +0000
committerRozhuk Ivan <rozhuk.im@gmail.com>2014-11-27 00:44:57 +0000
commit117cf2ba6883c5b3ff8b275f4c56eb562a219b95 (patch)
tree748e5d8b028b589151183452cbdb3306a7afa2c1 /plugins/Clist_modern/src
parentbd1e3d8fe219dcbc55584d95dfba6ddae0d01d2c (diff)
Clist_modern: code cleanup, review required
git-svn-id: http://svn.miranda-ng.org/main/trunk@11113 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Clist_modern/src')
-rw-r--r--plugins/Clist_modern/src/modern_cachefuncs.cpp1804
-rw-r--r--plugins/Clist_modern/src/modern_clc.cpp3776
-rw-r--r--plugins/Clist_modern/src/modern_clcitems.cpp1493
-rw-r--r--plugins/Clist_modern/src/modern_row.cpp1523
-rw-r--r--plugins/Clist_modern/src/modern_skinbutton.cpp1532
-rw-r--r--plugins/Clist_modern/src/modern_skinengine.cpp8285
-rw-r--r--plugins/Clist_modern/src/modern_skinopt.cpp1136
7 files changed, 9776 insertions, 9773 deletions
diff --git a/plugins/Clist_modern/src/modern_cachefuncs.cpp b/plugins/Clist_modern/src/modern_cachefuncs.cpp
index 2caf524487..87fae9df20 100644
--- a/plugins/Clist_modern/src/modern_cachefuncs.cpp
+++ b/plugins/Clist_modern/src/modern_cachefuncs.cpp
@@ -1,900 +1,904 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
-Copyright (c) 2000-08 Miranda ICQ/IM project,
-all portions of this codebase are copyrighted to the people
-listed in contributors.txt.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-Created by Pescuma
-Modified by FYR
-*/
-
-/************************************************************************/
-/* Module for working with lines text and avatars */
-/************************************************************************/
-
-#include "hdr/modern_commonheaders.h"
-#include "hdr/modern_cache_funcs.h"
-#include "newpluginapi.h"
-#include "./hdr/modern_gettextasync.h"
-#include "hdr/modern_sync.h"
-
-typedef BOOL (* ExecuteOnAllContactsFuncPtr) (ClcContact *contact, BOOL subcontact, void *param);
-
-
-/***********************************/
-/** Module static declarations **/
-/***********************************/
-
-/* Module Static Prototypes */
-
-static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size);
-
-static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param);
-static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param);
-int CLUI_SyncGetShortData(WPARAM wParam, LPARAM lParam);
-void CListSettings_FreeCacheItemData(ClcCacheEntry *pDst);
-void CListSettings_FreeCacheItemDataOption( ClcCacheEntry *pDst, DWORD flag );
-/*
- * Get time zone for contact
- */
-void Cache_GetTimezone(ClcData *dat, MCONTACT hContact)
-{
- ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
- if (dat == NULL && pcli->hwndContactTree)
- dat = (ClcData *)GetWindowLongPtr(pcli->hwndContactTree,0);
-
- if (dat && dat->hWnd == pcli->hwndContactTree) {
- DWORD flags = dat->contact_time_show_only_if_different ? TZF_DIFONLY : 0;
- pdnce->hTimeZone = tmi.createByContact(hContact, 0, flags);
- }
-}
-
-/*
- * Get all lines of text
- */
-
-void Cache_GetText(ClcData *dat, ClcContact *contact, BOOL forceRenew)
-{
- Cache_GetFirstLineText(dat, contact);
- if (!dat->force_in_dialog) {
- ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
- if ((dat->second_line_show && (forceRenew || pdnce->szSecondLineText == NULL)) || (dat->third_line_show && (forceRenew || pdnce->szThirdLineText == NULL)))
- gtaAddRequest(dat,contact, contact->hContact);
- }
-}
-
-void CSmileyString::AddListeningToIcon(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR *szText, BOOL replace_smileys)
-{
- iMaxSmileyHeight = 0;
- DestroySmileyList();
-
- if (szText == NULL) return;
-
- int text_size = (int)_tcslen( szText );
-
- plText = List_Create( 0, 1 );
-
- // Add Icon
- {
- ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
- piece->type = TEXT_PIECE_TYPE_SMILEY;
- piece->len = 0;
- piece->smiley = g_hListeningToIcon;
- piece->smiley_width = 16;
- piece->smiley_height = 16;
-
- ICONINFO icon;
- if ( GetIconInfo(piece->smiley, &icon)) {
- BITMAP bm;
- if (GetObject(icon.hbmColor, sizeof(BITMAP), &bm)) {
- piece->smiley_width = bm.bmWidth;
- piece->smiley_height = bm.bmHeight;
- }
-
- DeleteObject(icon.hbmMask);
- DeleteObject(icon.hbmColor);
- }
-
- dat->text_smiley_height = max(piece->smiley_height, dat->text_smiley_height);
- iMaxSmileyHeight = max(piece->smiley_height, iMaxSmileyHeight);
-
- List_Insert( plText, piece, plText->realCount);
- }
-
- // Add text
- {
- ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
-
- piece->type = TEXT_PIECE_TYPE_TEXT;
- piece->start_pos = 0;
- piece->len = text_size;
- List_Insert( plText, piece, plText->realCount);
- }
-}
-
-void CSmileyString::_CopySmileyList( SortedList *plInput )
-{
- // ASSERT( plText == NULL );
-
- if (!plInput || plInput->realCount == 0 ) return;
- plText = List_Create( 0, 1 );
- for ( int i=0; i < plInput->realCount; i++ )
- {
- ClcContactTextPiece *pieceFrom = (ClcContactTextPiece *) plInput->items[i];
- if ( pieceFrom != NULL )
- {
- ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc( sizeof(ClcContactTextPiece));
- *piece = *pieceFrom;
- if ( pieceFrom->type == TEXT_PIECE_TYPE_SMILEY)
- piece->smiley = CopyIcon( pieceFrom->smiley );
- List_Insert( plText, piece, plText->realCount );
- }
- }
-}
-
-void CSmileyString::DestroySmileyList()
-{
- //ASSERT( plText == NULL );
-
- if ( plText == NULL ) return;
-
- if ( IsBadReadPtr( plText, sizeof(SortedList))) {
- plText = NULL;
- return;
- }
-
- if ( plText->realCount != 0 ) {
- for ( int i=0 ; i < plText->realCount ; i++ ) {
- if ( plText->items[i] != NULL ) {
- ClcContactTextPiece *piece = (ClcContactTextPiece *) plText->items[i];
-
- if (!IsBadWritePtr(piece, sizeof(ClcContactTextPiece))) {
- if (piece->type == TEXT_PIECE_TYPE_SMILEY && piece->smiley != g_hListeningToIcon)
- DestroyIcon_protect(piece->smiley);
- mir_free(piece);
- }
- }
- }
- List_Destroy( plText );
- }
- mir_free(plText);
-
- plText = NULL;
-}
-
-/*
-* Parsing of text for smiley
-*/
-
-void CSmileyString::ReplaceSmileys(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR * szText, BOOL replace_smileys)
-{
- SMADD_BATCHPARSE2 sp = {0};
- SMADD_BATCHPARSERES *spr;
-
- int last_pos = 0;
- iMaxSmileyHeight = 0;
-
- DestroySmileyList();
-
- if (!dat->text_replace_smileys || !replace_smileys || szText == NULL)
- return;
-
- int text_size = (int)_tcslen( szText );
-
- // Call service for the first time to see if needs to be used...
- sp.cbSize = sizeof(sp);
-
- if (dat->text_use_protocol_smileys) {
- sp.Protocolname = pdnce->m_cache_cszProto;
-
- if (db_get_b(NULL,"CLC","Meta",SETTING_USEMETAICON_DEFAULT) != 1 && pdnce->m_cache_cszProto != NULL && strcmp(pdnce->m_cache_cszProto, META_PROTO) == 0) {
- MCONTACT hContact = db_mc_getMostOnline(pdnce->hContact);
- if (hContact != 0)
- sp.Protocolname = GetContactProto(hContact);
- }
- }
- else sp.Protocolname = "clist";
-
- sp.str = szText;
- sp.flag = SAFL_TCHAR;
-
- spr = (SMADD_BATCHPARSERES*)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp);
-
- // Did not find a simley
- if (spr == NULL || (INT_PTR)spr == CALLSERVICE_NOTFOUND)
- return;
-
- // Lets add smileys
- plText = List_Create( 0, 1 );
-
- for (unsigned i=0; i < sp.numSmileys; ++i) {
- if (spr[i].hIcon != NULL) { // For deffective smileypacks
- // Add text
- if (spr[i].startChar - last_pos > 0) {
- ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
-
- piece->type = TEXT_PIECE_TYPE_TEXT;
- piece->start_pos = last_pos ;//sp.str - text;
- piece->len = spr[i].startChar - last_pos;
- List_Insert(plText, piece, plText->realCount);
- }
-
- // Add smiley
- {
- BITMAP bm;
- ICONINFO icon;
- ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
-
- piece->type = TEXT_PIECE_TYPE_SMILEY;
- piece->len = spr[i].size;
- piece->smiley = spr[i].hIcon;
-
- piece->smiley_width = 16;
- piece->smiley_height = 16;
- if (GetIconInfo(piece->smiley, &icon)) {
- if (GetObject(icon.hbmColor,sizeof(BITMAP),&bm)) {
- piece->smiley_width = bm.bmWidth;
- piece->smiley_height = bm.bmHeight;
- }
-
- DeleteObject(icon.hbmMask);
- DeleteObject(icon.hbmColor);
- }
-
- dat->text_smiley_height = max( piece->smiley_height, dat->text_smiley_height );
- iMaxSmileyHeight = max( piece->smiley_height, iMaxSmileyHeight );
-
- List_Insert(plText, piece, plText->realCount);
- }
- }
- // Get next
- last_pos = spr[i].startChar + spr[i].size;
- }
- CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)spr);
-
- // Add rest of text
- if (last_pos < text_size) {
- ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
-
- piece->type = TEXT_PIECE_TYPE_TEXT;
- piece->start_pos = last_pos;
- piece->len = text_size-last_pos;
-
- List_Insert(plText, piece, plText->realCount);
- }
-}
-
-/*
-* Getting Status name
-* -1 for XStatus, 1 for Status
-*/
-int GetStatusName(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority)
-{
- BOOL noAwayMsg = FALSE;
- BOOL noXstatus = FALSE;
- // Hide status text if Offline /// no offline
- WORD nStatus = pdnce___GetStatus(pdnce);
- if ((nStatus == ID_STATUS_OFFLINE || nStatus == 0) && g_CluiData.bRemoveAwayMessageForOffline) noAwayMsg = TRUE;
- if (nStatus == ID_STATUS_OFFLINE || nStatus == 0) noXstatus = TRUE;
- text[0] = '\0';
- // Get XStatusName
- if (!noAwayMsg && !noXstatus && xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
- DBVARIANT dbv = { 0 };
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
- //lstrcpyn(text, dbv.pszVal, text_size);
- CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
- db_free(&dbv);
-
- if (text[0] != '\0')
- return -1;
- }
- }
-
- // Get Status name
- TCHAR *tmp = pcli->pfnGetStatusModeDescription(nStatus, 0);
- if (tmp && *tmp) {
- _tcsncpy_s(text, text_size, tmp, _TRUNCATE);
- return 1;
- }
-
- // Get XStatusName
- if (!noAwayMsg && !noXstatus && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
- DBVARIANT dbv = { 0 };
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
- CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
- db_free(&dbv);
-
- if (text[0] != '\0')
- return -1;
- }
- }
-
- return 1;
-}
-
-/*
-* Get Listening to information
-*/
-
-void GetListeningTo(TCHAR *text, int text_size, ClcCacheEntry *pdnce)
-{
- DBVARIANT dbv = { 0 };
- WORD wStatus = pdnce___GetStatus(pdnce);
- text[0] = _T('\0');
-
- if (wStatus == ID_STATUS_OFFLINE || wStatus == 0)
- return;
-
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "ListeningTo", &dbv)) {
- CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
- db_free(&dbv);
- }
-}
-
-/*
-* Getting Status message (Away message)
-* -1 for XStatus, 1 for Status
-*/
-
-int GetStatusMessage(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority)
-{
- DBVARIANT dbv = { 0 };
- BOOL noAwayMsg = FALSE;
- WORD wStatus = pdnce___GetStatus(pdnce);
- text[0] = '\0';
- // Hide status text if Offline /// no offline
-
- if (wStatus == ID_STATUS_OFFLINE || wStatus == 0) noAwayMsg = TRUE;
- // Get XStatusMsg
- if (!noAwayMsg && xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
- // Try to get XStatusMsg
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
- //lstrcpyn(text, dbv.pszVal, text_size);
- CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
- db_free(&dbv);
-
- if (text[0] != '\0')
- return -1;
- }
- }
-
- // Get StatusMsg
- if (pdnce->hContact && text[0] == '\0') {
- if (!db_get_ts(pdnce->hContact, "CList", "StatusMsg", &dbv)) {
- //lstrcpyn(text, dbv.pszVal, text_size);
- CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
- db_free(&dbv);
-
- if (text[0] != '\0')
- return 1;
- }
- }
-
- // Get XStatusMsg
- if (!noAwayMsg && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto && text[0] == '\0') {
- // Try to get XStatusMsg
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
- //lstrcpyn(text, dbv.pszVal, text_size);
- CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
- db_free(&dbv);
-
- if (text[0] != '\0')
- return -1;
- }
- }
-
- return 1;
-}
-
-
-/*
-* Get the text for specified lines
-*/
-int Cache_GetLineText(
- ClcCacheEntry *pdnce, int type, LPTSTR text, int text_size, TCHAR *variable_text, BOOL xstatus_has_priority,
- BOOL show_status_if_no_away, BOOL show_listening_if_no_away, BOOL use_name_and_message_for_xstatus,
- BOOL pdnce_time_show_only_if_different)
-{
- text[0] = '\0';
- switch(type) {
- case TEXT_STATUS:
- if (GetStatusName(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) {
- DBVARIANT dbv = {0};
-
- // Try to get XStatusMsg
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
- if (dbv.ptszVal != NULL && dbv.ptszVal[0] != 0) {
- TCHAR *tmp = NEWTSTR_ALLOCA(text);
- mir_sntprintf(text, text_size, _T("%s: %s"), tmp, dbv.ptszVal);
- CopySkipUnprintableChars(text, text, text_size-1);
- }
- db_free(&dbv);
- }
- }
-
- return TEXT_STATUS;
-
- case TEXT_NICKNAME:
- if (pdnce->hContact && pdnce->m_cache_cszProto) {
- DBVARIANT dbv = {0};
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) {
- lstrcpyn(text, dbv.ptszVal, text_size);
- db_free(&dbv);
- CopySkipUnprintableChars(text, text, text_size-1);
- }
- }
-
- return TEXT_NICKNAME;
-
- case TEXT_STATUS_MESSAGE:
- if (GetStatusMessage(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) {
- DBVARIANT dbv = {0};
-
- // Try to get XStatusName
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
- if (dbv.pszVal != NULL && dbv.pszVal[0] != 0) {
- TCHAR *tmp = NEWTSTR_ALLOCA(text);
- mir_sntprintf(text, text_size, _T("%s: %s"), dbv.pszVal, tmp);
- }
- CopySkipUnprintableChars(text, text, text_size-1);
- db_free(&dbv);
- }
- }
- else if (use_name_and_message_for_xstatus && xstatus_has_priority) {
- DBVARIANT dbv = {0};
- // Try to get XStatusName
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
- if (dbv.pszVal != NULL && dbv.pszVal[0] != 0)
- mir_sntprintf(text, text_size, _T("%s"), dbv.pszVal);
- CopySkipUnprintableChars(text, text, text_size-1);
- db_free(&dbv);
- }
- }
-
- if (text[0] == '\0') {
- if (show_listening_if_no_away) {
- Cache_GetLineText(pdnce, TEXT_LISTENING_TO, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different);
- if (text[0] != '\0')
- return TEXT_LISTENING_TO;
- }
-
- if (show_status_if_no_away) {
- //re-request status if no away
- return Cache_GetLineText(pdnce, TEXT_STATUS, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different);
- }
- }
- return TEXT_STATUS_MESSAGE;
-
- case TEXT_LISTENING_TO:
- GetListeningTo(text, text_size, pdnce);
- return TEXT_LISTENING_TO;
-
- case TEXT_TEXT:
- {
- TCHAR *tmp = variables_parsedup(variable_text, pdnce->tszName, pdnce->hContact);
- lstrcpyn(text, tmp, text_size);
- mir_free(tmp);
- CopySkipUnprintableChars(text, text, text_size-1);
- }
- return TEXT_TEXT;
-
- case TEXT_CONTACT_TIME:
- if (pdnce->hTimeZone) {
- // Get pdnce time
- text[0] = 0;
- tmi.printDateTime( pdnce->hTimeZone, _T("t"), text, text_size, 0);
- }
-
- return TEXT_CONTACT_TIME;
- }
-
- return TEXT_EMPTY;
-}
-
-/*
-* Get the text for First Line
-*/
-void Cache_GetFirstLineText(ClcData *dat, ClcContact *contact)
-{
- if (GetCurrentThreadId() != g_dwMainThreadID)
- return;
-
- ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
- TCHAR *name = pcli->pfnGetContactDisplayName(contact->hContact, 0);
- if (dat->first_line_append_nick && (!dat->force_in_dialog)) {
- DBVARIANT dbv = { 0 };
- if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) {
- TCHAR nick[SIZEOF(contact->szText)];
- lstrcpyn(nick, dbv.ptszVal, SIZEOF(contact->szText));
- db_free(&dbv);
-
- // They are the same -> use the name to keep the case
- if (_tcsicmp(name, nick) == 0)
- lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
- else
- // Append then
- mir_sntprintf(contact->szText, SIZEOF(contact->szText), _T("%s - %s"), name, nick);
- }
- else lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
- }
- else lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
-
- if (!dat->force_in_dialog) {
- struct SHORTDATA data = { 0 };
- Sync(CLUI_SyncGetShortData, (WPARAM)pcli->hwndContactTree, (LPARAM)&data);
- contact->ssText.ReplaceSmileys(&data, pdnce, contact->szText, dat->first_line_draw_smileys);
- }
-}
-
-/*
-* Get the text for Second Line
-*/
-
-void Cache_GetSecondLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce)
-{
- TCHAR Text[240-EXTRA_ICON_COUNT] = {0};
- int type = TEXT_EMPTY;
-
- if (dat->second_line_show)
- type = Cache_GetLineText(pdnce, dat->second_line_type, (TCHAR*)Text, SIZEOF(Text), dat->second_line_text,
- dat->second_line_xstatus_has_priority,dat->second_line_show_status_if_no_away,dat->second_line_show_listening_if_no_away,
- dat->second_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different);
- Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string
-
- mir_free(pdnce->szSecondLineText);
-
- if (dat->second_line_show)// Text[0] != '\0')
- pdnce->szSecondLineText = mir_tstrdup((TCHAR*)Text);
- else
- pdnce->szSecondLineText = NULL;
-
- if (pdnce->szSecondLineText) {
- if (type == TEXT_LISTENING_TO && pdnce->szSecondLineText[0] != _T('\0'))
- pdnce->ssSecondLine.AddListeningToIcon(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys);
- else
- pdnce->ssSecondLine.ReplaceSmileys(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys);
- }
-}
-
-/*
-* Get the text for Third Line
-*/
-void Cache_GetThirdLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce)
-{
- TCHAR Text[240-EXTRA_ICON_COUNT] = {0};
- int type = TEXT_EMPTY;
- if (dat->third_line_show)
- type = Cache_GetLineText(pdnce, dat->third_line_type,(TCHAR*)Text, SIZEOF(Text), dat->third_line_text,
- dat->third_line_xstatus_has_priority,dat->third_line_show_status_if_no_away,dat->third_line_show_listening_if_no_away,
- dat->third_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different);
-
- Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string
-
- mir_free(pdnce->szThirdLineText);
-
- if (dat->third_line_show)//Text[0] != '\0')
- pdnce->szThirdLineText = mir_tstrdup((TCHAR*)Text);
- else
- pdnce->szThirdLineText = NULL;
-
- if (pdnce->szThirdLineText) {
- if (type == TEXT_LISTENING_TO && pdnce->szThirdLineText[0] != _T('\0'))
- pdnce->ssThirdLine.AddListeningToIcon(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys);
- else
- pdnce->ssThirdLine.ReplaceSmileys(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys);
- }
-}
-
-void RemoveTag(TCHAR *to, TCHAR *tag)
-{
- TCHAR *st = to;
- int len = (int)_tcslen(tag);
- int lastsize = (int)_tcslen(to)+1;
- while (st = _tcsstr(st,tag)) {
- lastsize -= len;
- memmove((void*)st,(void*)(st+len),(lastsize)*sizeof(TCHAR));
- }
-}
-
-/*
-* Copy string with removing Escape chars from text
-* And BBcodes
-*/
-static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size)
-{
- DWORD i;
- BOOL keep = 0;
- TCHAR * cp = to;
- if (!to) return 0;
- if (!buf) {
- to[0] = '\0';
- return 0;
- }
-
- for (i=0; i < size; i++) {
- if (buf[i] == 0) break;
- if (buf[i] > 0 && buf[i] < ' ') {
- *cp = ' ';
- if (!keep) cp++;
- keep = 1;
- }
- else {
- keep = 0;
- *cp = buf[i];
- cp++;
- }
- }
- *cp = 0;
-
- //remove bbcodes: [b] [i] [u] <b> <i> <u>
- RemoveTag(to,_T("[b]")); RemoveTag(to,_T("[/b]"));
- RemoveTag(to,_T("[u]")); RemoveTag(to,_T("[/u]"));
- RemoveTag(to,_T("[i]")); RemoveTag(to,_T("[/i]"));
-
- RemoveTag(to,_T("<b>")); RemoveTag(to,_T("</b>"));
- RemoveTag(to,_T("<u>")); RemoveTag(to,_T("</u>"));
- RemoveTag(to,_T("<i>")); RemoveTag(to,_T("</i>"));
-
- RemoveTag(to,_T("[B]")); RemoveTag(to,_T("[/b]"));
- RemoveTag(to,_T("[U]")); RemoveTag(to,_T("[/u]"));
- RemoveTag(to,_T("[I]")); RemoveTag(to,_T("[/i]"));
-
- RemoveTag(to,_T("<B>")); RemoveTag(to,_T("</B>"));
- RemoveTag(to,_T("<U>")); RemoveTag(to,_T("</U>"));
- RemoveTag(to,_T("<I>")); RemoveTag(to,_T("</I>"));
- return i;
-}
-
-// If ExecuteOnAllContactsFuncPtr returns FALSE, stop loop
-// Return TRUE if finished, FALSE if was stoped
-static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param)
-{
- BOOL res;
- res = ExecuteOnAllContactsOfGroup(&dat->list, func, param);
- return res;
-}
-
-static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param)
-{
- if (!group)
- return TRUE;
-
- for (int scanIndex = 0 ; scanIndex < group->cl.count ; scanIndex++) {
- if (group->cl.items[scanIndex]->type == CLCIT_CONTACT) {
- if (!func(group->cl.items[scanIndex], FALSE, param))
- return FALSE;
-
- if (group->cl.items[scanIndex]->SubAllocated > 0) {
- for (int i=0 ; i < group->cl.items[scanIndex]->SubAllocated ; i++)
- if (!func(&group->cl.items[scanIndex]->subcontacts[i], TRUE, param))
- return FALSE;
- }
- }
- else if (group->cl.items[scanIndex]->type == CLCIT_GROUP)
- if (!ExecuteOnAllContactsOfGroup(group->cl.items[scanIndex]->group, func, param))
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
-* Avatar working routines
-*/
-BOOL UpdateAllAvatarsProxy(ClcContact *contact, BOOL subcontact, void *param)
-{
- Cache_GetAvatar((ClcData *)param, contact);
- return TRUE;
-}
-
-void UpdateAllAvatars(ClcData *dat)
-{
- ExecuteOnAllContacts(dat,UpdateAllAvatarsProxy,dat);
-}
-
-BOOL ReduceAvatarPosition(ClcContact *contact, BOOL subcontact, void *param)
-{
- if (contact->avatar_pos >= *((int *)param))
- contact->avatar_pos--;
-
- return TRUE;
-}
-
-void Cache_ProceedAvatarInList(ClcData *dat, ClcContact *contact)
-{
- struct avatarCacheEntry * ace = contact->avatar_data;
- int old_pos = contact->avatar_pos;
-
- if (ace == NULL || ace->dwFlags == AVS_BITMAP_EXPIRED || ace->hbmPic == NULL) {
- //Avatar was not ready or removed - need to remove it from cache
- if (old_pos >= 0) {
- ImageArray_RemoveImage(&dat->avatar_cache, old_pos);
- // Update all items
- ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos);
- contact->avatar_pos = AVATAR_POS_DONT_HAVE;
- return;
- }
- }
- else if (contact->avatar_data->hbmPic != NULL) //Lets Add it
- {
- // Make bounds -> keep aspect radio
- LONG width_clip;
- LONG height_clip;
- RECT rc = {0};
-
- // Clipping width and height
- width_clip = dat->avatars_maxwidth_size?dat->avatars_maxwidth_size:dat->avatars_maxheight_size;
- height_clip = dat->avatars_maxheight_size;
-
- if (height_clip * ace->bmWidth / ace->bmHeight <= width_clip)
- width_clip = height_clip * ace->bmWidth / ace->bmHeight;
- else
- height_clip = width_clip * ace->bmHeight / ace->bmWidth;
-
- if (wildcmpit(contact->avatar_data->szFilename,_T("*.gif"))) {
- if (old_pos == AVATAR_POS_ANIMATED)
- AniAva_RemoveAvatar(contact->hContact);
-
- int res = AniAva_AddAvatar(contact->hContact, contact->avatar_data->szFilename, width_clip, height_clip);
- if (res) {
- contact->avatar_pos = AVATAR_POS_ANIMATED;
- contact->avatar_size.cy = HIWORD(res);
- contact->avatar_size.cx = LOWORD(res);
- return;
- }
- }
-
- // Create objs
- void * pt;
- HDC hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
- HBITMAP hDrawBmp = ske_CreateDIB32Point(width_clip, height_clip,&pt);
- HBITMAP oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
- //need to draw avatar bitmap here
- {
- RECT real_rc = {0, 0, width_clip, height_clip};
-
- int w = width_clip;
- int h = height_clip;
- DrawAvatarImageWithGDIp(hdc, 0, 0, w, h,ace->hbmPic, 0, 0, ace->bmWidth,ace->bmHeight,ace->dwFlags,255);
- }
- SelectObject(hdc,oldBmp);
- DeleteDC(hdc);
- // Add to list
- if (old_pos >= 0) {
- ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos);
- contact->avatar_pos = old_pos;
- }
- else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1);
-
- if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED)
- AniAva_RemoveAvatar(contact->hContact);
-
- DeleteObject(hDrawBmp);
- }
-}
-
-void Cache_GetAvatar(ClcData *dat, ClcContact *contact)
-{
- int old_pos = contact->avatar_pos;
- // workaround for avatar service and other wich destroys service on OK_TOEXIT
- if (g_CluiData.bSTATE != STATE_NORMAL || (dat->use_avatar_service && !ServiceExists(MS_AV_GETAVATARBITMAP))) {
- contact->avatar_pos = AVATAR_POS_DONT_HAVE;
- contact->avatar_data = NULL;
- return;
- }
-
- if (dat->use_avatar_service && ServiceExists(MS_AV_GETAVATARBITMAP)) {
- if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) {
- contact->avatar_data = (struct avatarCacheEntry *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)contact->hContact, 0);
- if (contact->avatar_data == NULL || contact->avatar_data->cbSize != sizeof(struct avatarCacheEntry) || contact->avatar_data->dwFlags == AVS_BITMAP_EXPIRED)
- contact->avatar_data = NULL;
-
- if (contact->avatar_data != NULL)
- contact->avatar_data->t_lastAccess = (DWORD)time(NULL);
- }
- else contact->avatar_data = NULL;
-
- Cache_ProceedAvatarInList(dat, contact);
- }
- else {
- contact->avatar_pos = AVATAR_POS_DONT_HAVE;
- if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) {
- DBVARIANT dbv;
- if (!db_get_ts(contact->hContact, "ContactPhoto", "File", &dbv)) {
- HBITMAP hBmp = (HBITMAP) CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)dbv.ptszVal);
- if (hBmp != NULL) {
- // Make bounds
- BITMAP bm;
- if (GetObject(hBmp,sizeof(BITMAP),&bm)) {
- // Create data...
- HDC hdc;
- HBITMAP hDrawBmp,oldBmp;
-
- // Make bounds -> keep aspect radio
- LONG width_clip;
- LONG height_clip;
- RECT rc = {0};
-
- // Clipping width and height
- width_clip = dat->avatars_maxheight_size;
- height_clip = dat->avatars_maxheight_size;
-
- if (height_clip * bm.bmWidth / bm.bmHeight <= width_clip)
- width_clip = height_clip * bm.bmWidth / bm.bmHeight;
- else
- height_clip = width_clip * bm.bmHeight / bm.bmWidth;
-
- // Create objs
- hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
- hDrawBmp = ske_CreateDIB32(width_clip, height_clip);
- oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
- SetBkMode(hdc,TRANSPARENT);
-
- POINT org;
- GetBrushOrgEx(hdc, &org);
- SetStretchBltMode(hdc, HALFTONE);
- SetBrushOrgEx(hdc, org.x, org.y, NULL);
-
- rc.right = width_clip - 1;
- rc.bottom = height_clip - 1;
-
- // Draw bitmap 8//8
- HDC dcMem = CreateCompatibleDC(hdc);
- HBITMAP obmp = (HBITMAP)SelectObject(dcMem, hBmp);
- StretchBlt(hdc, 0, 0, width_clip, height_clip,dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
- SelectObject(dcMem,obmp);
- DeleteDC(dcMem);
-
- RECT rtr = {0};
- rtr.right = width_clip+1;
- rtr.bottom = height_clip+1;
- ske_SetRectOpaque(hdc,&rtr);
-
- hDrawBmp = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
- SelectObject(hdc,oldBmp);
- DeleteDC(hdc);
-
- // Add to list
- if (old_pos >= 0) {
- ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos);
- contact->avatar_pos = old_pos;
- }
- else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1);
-
- DeleteObject(hDrawBmp);
- } // if (GetObject(hBmp,sizeof(BITMAP),&bm))
- DeleteObject(hBmp);
- } //if (hBmp != NULL)
- db_free(&dbv);
- }
- }
-
- // Remove avatar if needed
- if (old_pos >= 0 && contact->avatar_pos == AVATAR_POS_DONT_HAVE) {
- ImageArray_RemoveImage(&dat->avatar_cache, old_pos);
- // Update all items
- ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos);
- }
-
- if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED)
- AniAva_RemoveAvatar( contact->hContact );
- }
-}
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
+Copyright (c) 2000-08 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Created by Pescuma
+Modified by FYR
+*/
+
+/************************************************************************/
+/* Module for working with lines text and avatars */
+/************************************************************************/
+
+#include "hdr/modern_commonheaders.h"
+#include "hdr/modern_cache_funcs.h"
+#include "newpluginapi.h"
+#include "./hdr/modern_gettextasync.h"
+#include "hdr/modern_sync.h"
+
+typedef BOOL (* ExecuteOnAllContactsFuncPtr) (ClcContact *contact, BOOL subcontact, void *param);
+
+
+/***********************************/
+/** Module static declarations **/
+/***********************************/
+
+/* Module Static Prototypes */
+
+static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size);
+
+static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param);
+static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param);
+int CLUI_SyncGetShortData(WPARAM wParam, LPARAM lParam);
+void CListSettings_FreeCacheItemData(ClcCacheEntry *pDst);
+void CListSettings_FreeCacheItemDataOption( ClcCacheEntry *pDst, DWORD flag );
+/*
+ * Get time zone for contact
+ */
+void Cache_GetTimezone(ClcData *dat, MCONTACT hContact)
+{
+ ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
+ if (dat == NULL && pcli->hwndContactTree)
+ dat = (ClcData *)GetWindowLongPtr(pcli->hwndContactTree,0);
+
+ if (dat && dat->hWnd == pcli->hwndContactTree) {
+ DWORD flags = dat->contact_time_show_only_if_different ? TZF_DIFONLY : 0;
+ pdnce->hTimeZone = tmi.createByContact(hContact, 0, flags);
+ }
+}
+
+/*
+ * Get all lines of text
+ */
+
+void Cache_GetText(ClcData *dat, ClcContact *contact, BOOL forceRenew)
+{
+ Cache_GetFirstLineText(dat, contact);
+ if (!dat->force_in_dialog) {
+ ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
+ if ((dat->second_line_show && (forceRenew || pdnce->szSecondLineText == NULL)) || (dat->third_line_show && (forceRenew || pdnce->szThirdLineText == NULL)))
+ gtaAddRequest(dat,contact, contact->hContact);
+ }
+}
+
+void CSmileyString::AddListeningToIcon(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR *szText, BOOL replace_smileys)
+{
+ iMaxSmileyHeight = 0;
+ DestroySmileyList();
+
+ if (szText == NULL) return;
+
+ int text_size = (int)_tcslen( szText );
+
+ plText = List_Create( 0, 1 );
+
+ // Add Icon
+ {
+ ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
+ piece->type = TEXT_PIECE_TYPE_SMILEY;
+ piece->len = 0;
+ piece->smiley = g_hListeningToIcon;
+ piece->smiley_width = 16;
+ piece->smiley_height = 16;
+
+ ICONINFO icon;
+ if ( GetIconInfo(piece->smiley, &icon)) {
+ BITMAP bm;
+ if (GetObject(icon.hbmColor, sizeof(BITMAP), &bm)) {
+ piece->smiley_width = bm.bmWidth;
+ piece->smiley_height = bm.bmHeight;
+ }
+
+ DeleteObject(icon.hbmMask);
+ DeleteObject(icon.hbmColor);
+ }
+
+ dat->text_smiley_height = max(piece->smiley_height, dat->text_smiley_height);
+ iMaxSmileyHeight = max(piece->smiley_height, iMaxSmileyHeight);
+
+ List_Insert( plText, piece, plText->realCount);
+ }
+
+ // Add text
+ {
+ ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
+
+ piece->type = TEXT_PIECE_TYPE_TEXT;
+ piece->start_pos = 0;
+ piece->len = text_size;
+ List_Insert( plText, piece, plText->realCount);
+ }
+}
+
+void CSmileyString::_CopySmileyList( SortedList *plInput )
+{
+ // ASSERT( plText == NULL );
+
+ if (!plInput || plInput->realCount == 0 ) return;
+ plText = List_Create( 0, 1 );
+ for ( int i=0; i < plInput->realCount; i++ )
+ {
+ ClcContactTextPiece *pieceFrom = (ClcContactTextPiece *) plInput->items[i];
+ if ( pieceFrom != NULL )
+ {
+ ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc( sizeof(ClcContactTextPiece));
+ *piece = *pieceFrom;
+ if ( pieceFrom->type == TEXT_PIECE_TYPE_SMILEY)
+ piece->smiley = CopyIcon( pieceFrom->smiley );
+ List_Insert( plText, piece, plText->realCount );
+ }
+ }
+}
+
+void CSmileyString::DestroySmileyList()
+{
+ //ASSERT( plText == NULL );
+
+ if ( plText == NULL ) return;
+
+ if ( IsBadReadPtr( plText, sizeof(SortedList))) {
+ plText = NULL;
+ return;
+ }
+
+ if ( plText->realCount != 0 ) {
+ for ( int i=0 ; i < plText->realCount ; i++ ) {
+ if ( plText->items[i] != NULL ) {
+ ClcContactTextPiece *piece = (ClcContactTextPiece *) plText->items[i];
+
+ if (!IsBadWritePtr(piece, sizeof(ClcContactTextPiece))) {
+ if (piece->type == TEXT_PIECE_TYPE_SMILEY && piece->smiley != g_hListeningToIcon)
+ DestroyIcon_protect(piece->smiley);
+ mir_free(piece);
+ }
+ }
+ }
+ List_Destroy( plText );
+ }
+ mir_free(plText);
+
+ plText = NULL;
+}
+
+/*
+* Parsing of text for smiley
+*/
+
+void CSmileyString::ReplaceSmileys(struct SHORTDATA *dat, ClcCacheEntry *pdnce, TCHAR * szText, BOOL replace_smileys)
+{
+ SMADD_BATCHPARSE2 sp = {0};
+ SMADD_BATCHPARSERES *spr;
+
+ int last_pos = 0;
+ iMaxSmileyHeight = 0;
+
+ DestroySmileyList();
+
+ if (!dat->text_replace_smileys || !replace_smileys || szText == NULL)
+ return;
+
+ int text_size = (int)_tcslen( szText );
+
+ // Call service for the first time to see if needs to be used...
+ sp.cbSize = sizeof(sp);
+
+ if (dat->text_use_protocol_smileys) {
+ sp.Protocolname = pdnce->m_cache_cszProto;
+
+ if (db_get_b(NULL,"CLC","Meta",SETTING_USEMETAICON_DEFAULT) != 1 && pdnce->m_cache_cszProto != NULL && strcmp(pdnce->m_cache_cszProto, META_PROTO) == 0) {
+ MCONTACT hContact = db_mc_getMostOnline(pdnce->hContact);
+ if (hContact != 0)
+ sp.Protocolname = GetContactProto(hContact);
+ }
+ }
+ else sp.Protocolname = "clist";
+
+ sp.str = szText;
+ sp.flag = SAFL_TCHAR;
+
+ spr = (SMADD_BATCHPARSERES*)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp);
+
+ // Did not find a simley
+ if (spr == NULL || (INT_PTR)spr == CALLSERVICE_NOTFOUND)
+ return;
+
+ // Lets add smileys
+ plText = List_Create( 0, 1 );
+
+ for (unsigned i=0; i < sp.numSmileys; ++i) {
+ if (spr[i].hIcon != NULL) { // For deffective smileypacks
+ // Add text
+ if (spr[i].startChar - last_pos > 0) {
+ ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
+
+ piece->type = TEXT_PIECE_TYPE_TEXT;
+ piece->start_pos = last_pos ;//sp.str - text;
+ piece->len = spr[i].startChar - last_pos;
+ List_Insert(plText, piece, plText->realCount);
+ }
+
+ // Add smiley
+ {
+ BITMAP bm;
+ ICONINFO icon;
+ ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
+
+ piece->type = TEXT_PIECE_TYPE_SMILEY;
+ piece->len = spr[i].size;
+ piece->smiley = spr[i].hIcon;
+
+ piece->smiley_width = 16;
+ piece->smiley_height = 16;
+ if (GetIconInfo(piece->smiley, &icon)) {
+ if (GetObject(icon.hbmColor,sizeof(BITMAP),&bm)) {
+ piece->smiley_width = bm.bmWidth;
+ piece->smiley_height = bm.bmHeight;
+ }
+
+ DeleteObject(icon.hbmMask);
+ DeleteObject(icon.hbmColor);
+ }
+
+ dat->text_smiley_height = max( piece->smiley_height, dat->text_smiley_height );
+ iMaxSmileyHeight = max( piece->smiley_height, iMaxSmileyHeight );
+
+ List_Insert(plText, piece, plText->realCount);
+ }
+ }
+ // Get next
+ last_pos = spr[i].startChar + spr[i].size;
+ }
+ CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)spr);
+
+ // Add rest of text
+ if (last_pos < text_size) {
+ ClcContactTextPiece *piece = (ClcContactTextPiece *) mir_alloc(sizeof(ClcContactTextPiece));
+
+ piece->type = TEXT_PIECE_TYPE_TEXT;
+ piece->start_pos = last_pos;
+ piece->len = text_size-last_pos;
+
+ List_Insert(plText, piece, plText->realCount);
+ }
+}
+
+/*
+* Getting Status name
+* -1 for XStatus, 1 for Status
+*/
+int GetStatusName(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority)
+{
+ BOOL noAwayMsg = FALSE;
+ BOOL noXstatus = FALSE;
+ // Hide status text if Offline /// no offline
+ WORD nStatus = pdnce___GetStatus(pdnce);
+ if ((nStatus == ID_STATUS_OFFLINE || nStatus == 0) && g_CluiData.bRemoveAwayMessageForOffline) noAwayMsg = TRUE;
+ if (nStatus == ID_STATUS_OFFLINE || nStatus == 0) noXstatus = TRUE;
+ text[0] = '\0';
+ // Get XStatusName
+ if (!noAwayMsg && !noXstatus && xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
+ DBVARIANT dbv = { 0 };
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
+ //lstrcpyn(text, dbv.pszVal, text_size);
+ CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
+ db_free(&dbv);
+
+ if (text[0] != '\0')
+ return -1;
+ }
+ }
+
+ // Get Status name
+ TCHAR *tmp = pcli->pfnGetStatusModeDescription(nStatus, 0);
+ if (tmp && *tmp) {
+ _tcsncpy_s(text, text_size, tmp, _TRUNCATE);
+ return 1;
+ }
+
+ // Get XStatusName
+ if (!noAwayMsg && !noXstatus && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
+ DBVARIANT dbv = { 0 };
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
+ CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
+ db_free(&dbv);
+
+ if (text[0] != '\0')
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+/*
+* Get Listening to information
+*/
+
+void GetListeningTo(TCHAR *text, int text_size, ClcCacheEntry *pdnce)
+{
+ DBVARIANT dbv = { 0 };
+ WORD wStatus = pdnce___GetStatus(pdnce);
+ text[0] = _T('\0');
+
+ if (wStatus == ID_STATUS_OFFLINE || wStatus == 0)
+ return;
+
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "ListeningTo", &dbv)) {
+ CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
+ db_free(&dbv);
+ }
+}
+
+/*
+* Getting Status message (Away message)
+* -1 for XStatus, 1 for Status
+*/
+
+int GetStatusMessage(TCHAR *text, int text_size, ClcCacheEntry *pdnce, BOOL xstatus_has_priority)
+{
+ DBVARIANT dbv = { 0 };
+ BOOL noAwayMsg = FALSE;
+ WORD wStatus = pdnce___GetStatus(pdnce);
+ text[0] = '\0';
+ // Hide status text if Offline /// no offline
+
+ if (wStatus == ID_STATUS_OFFLINE || wStatus == 0) noAwayMsg = TRUE;
+ // Get XStatusMsg
+ if (!noAwayMsg && xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto) {
+ // Try to get XStatusMsg
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
+ //lstrcpyn(text, dbv.pszVal, text_size);
+ CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
+ db_free(&dbv);
+
+ if (text[0] != '\0')
+ return -1;
+ }
+ }
+
+ // Get StatusMsg
+ if (pdnce->hContact && text[0] == '\0') {
+ if (!db_get_ts(pdnce->hContact, "CList", "StatusMsg", &dbv)) {
+ //lstrcpyn(text, dbv.pszVal, text_size);
+ CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
+ db_free(&dbv);
+
+ if (text[0] != '\0')
+ return 1;
+ }
+ }
+
+ // Get XStatusMsg
+ if (!noAwayMsg && !xstatus_has_priority && pdnce->hContact && pdnce->m_cache_cszProto && text[0] == '\0') {
+ // Try to get XStatusMsg
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
+ //lstrcpyn(text, dbv.pszVal, text_size);
+ CopySkipUnprintableChars(text, dbv.ptszVal, text_size - 1);
+ db_free(&dbv);
+
+ if (text[0] != '\0')
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+
+/*
+* Get the text for specified lines
+*/
+int Cache_GetLineText(
+ ClcCacheEntry *pdnce, int type, LPTSTR text, int text_size, TCHAR *variable_text, BOOL xstatus_has_priority,
+ BOOL show_status_if_no_away, BOOL show_listening_if_no_away, BOOL use_name_and_message_for_xstatus,
+ BOOL pdnce_time_show_only_if_different)
+{
+
+ if (text == NULL)
+ return TEXT_EMPTY;
+ text[0] = '\0';
+
+ switch(type) {
+ case TEXT_STATUS:
+ if (GetStatusName(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) {
+ DBVARIANT dbv = {0};
+
+ // Try to get XStatusMsg
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusMsg", &dbv)) {
+ if (dbv.ptszVal != NULL && dbv.ptszVal[0] != 0) {
+ TCHAR *tmp = NEWTSTR_ALLOCA(text);
+ mir_sntprintf(text, text_size, _T("%s: %s"), tmp, dbv.ptszVal);
+ CopySkipUnprintableChars(text, text, text_size-1);
+ }
+ db_free(&dbv);
+ }
+ }
+
+ return TEXT_STATUS;
+
+ case TEXT_NICKNAME:
+ if (pdnce->hContact && pdnce->m_cache_cszProto) {
+ DBVARIANT dbv = {0};
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) {
+ lstrcpyn(text, dbv.ptszVal, text_size);
+ db_free(&dbv);
+ CopySkipUnprintableChars(text, text, text_size-1);
+ }
+ }
+
+ return TEXT_NICKNAME;
+
+ case TEXT_STATUS_MESSAGE:
+ if (GetStatusMessage(text, text_size, pdnce, xstatus_has_priority) == -1 && use_name_and_message_for_xstatus) {
+ DBVARIANT dbv = {0};
+
+ // Try to get XStatusName
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
+ if (dbv.pszVal != NULL && dbv.pszVal[0] != 0) {
+ TCHAR *tmp = NEWTSTR_ALLOCA(text);
+ mir_sntprintf(text, text_size, _T("%s: %s"), dbv.pszVal, tmp);
+ }
+ CopySkipUnprintableChars(text, text, text_size-1);
+ db_free(&dbv);
+ }
+ }
+ else if (use_name_and_message_for_xstatus && xstatus_has_priority) {
+ DBVARIANT dbv = {0};
+ // Try to get XStatusName
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "XStatusName", &dbv)) {
+ if (dbv.pszVal != NULL && dbv.pszVal[0] != 0)
+ mir_sntprintf(text, text_size, _T("%s"), dbv.pszVal);
+ CopySkipUnprintableChars(text, text, text_size-1);
+ db_free(&dbv);
+ }
+ }
+
+ if (text[0] == '\0') {
+ if (show_listening_if_no_away) {
+ Cache_GetLineText(pdnce, TEXT_LISTENING_TO, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different);
+ if (text[0] != '\0')
+ return TEXT_LISTENING_TO;
+ }
+
+ if (show_status_if_no_away) {
+ //re-request status if no away
+ return Cache_GetLineText(pdnce, TEXT_STATUS, text, text_size, variable_text, xstatus_has_priority, 0, 0, use_name_and_message_for_xstatus, pdnce_time_show_only_if_different);
+ }
+ }
+ return TEXT_STATUS_MESSAGE;
+
+ case TEXT_LISTENING_TO:
+ GetListeningTo(text, text_size, pdnce);
+ return TEXT_LISTENING_TO;
+
+ case TEXT_TEXT:
+ {
+ TCHAR *tmp = variables_parsedup(variable_text, pdnce->tszName, pdnce->hContact);
+ lstrcpyn(text, tmp, text_size);
+ mir_free(tmp);
+ CopySkipUnprintableChars(text, text, text_size-1);
+ }
+ return TEXT_TEXT;
+
+ case TEXT_CONTACT_TIME:
+ if (pdnce->hTimeZone) {
+ // Get pdnce time
+ text[0] = 0;
+ tmi.printDateTime( pdnce->hTimeZone, _T("t"), text, text_size, 0);
+ }
+
+ return TEXT_CONTACT_TIME;
+ }
+
+ return TEXT_EMPTY;
+}
+
+/*
+* Get the text for First Line
+*/
+void Cache_GetFirstLineText(ClcData *dat, ClcContact *contact)
+{
+ if (GetCurrentThreadId() != g_dwMainThreadID)
+ return;
+
+ ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
+ TCHAR *name = pcli->pfnGetContactDisplayName(contact->hContact, 0);
+ if (dat->first_line_append_nick && (!dat->force_in_dialog)) {
+ DBVARIANT dbv = { 0 };
+ if (!db_get_ts(pdnce->hContact, pdnce->m_cache_cszProto, "Nick", &dbv)) {
+ TCHAR nick[SIZEOF(contact->szText)];
+ lstrcpyn(nick, dbv.ptszVal, SIZEOF(contact->szText));
+ db_free(&dbv);
+
+ // They are the same -> use the name to keep the case
+ if (_tcsicmp(name, nick) == 0)
+ lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
+ else
+ // Append then
+ mir_sntprintf(contact->szText, SIZEOF(contact->szText), _T("%s - %s"), name, nick);
+ }
+ else lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
+ }
+ else lstrcpyn(contact->szText, name, SIZEOF(contact->szText));
+
+ if (!dat->force_in_dialog) {
+ struct SHORTDATA data = { 0 };
+ Sync(CLUI_SyncGetShortData, (WPARAM)pcli->hwndContactTree, (LPARAM)&data);
+ contact->ssText.ReplaceSmileys(&data, pdnce, contact->szText, dat->first_line_draw_smileys);
+ }
+}
+
+/*
+* Get the text for Second Line
+*/
+
+void Cache_GetSecondLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce)
+{
+ TCHAR Text[240-EXTRA_ICON_COUNT] = {0};
+ int type = TEXT_EMPTY;
+
+ if (dat->second_line_show)
+ type = Cache_GetLineText(pdnce, dat->second_line_type, (TCHAR*)Text, SIZEOF(Text), dat->second_line_text,
+ dat->second_line_xstatus_has_priority,dat->second_line_show_status_if_no_away,dat->second_line_show_listening_if_no_away,
+ dat->second_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different);
+ Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string
+
+ mir_free(pdnce->szSecondLineText);
+
+ if (dat->second_line_show)// Text[0] != '\0')
+ pdnce->szSecondLineText = mir_tstrdup((TCHAR*)Text);
+ else
+ pdnce->szSecondLineText = NULL;
+
+ if (pdnce->szSecondLineText) {
+ if (type == TEXT_LISTENING_TO && pdnce->szSecondLineText[0] != _T('\0'))
+ pdnce->ssSecondLine.AddListeningToIcon(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys);
+ else
+ pdnce->ssSecondLine.ReplaceSmileys(dat, pdnce, pdnce->szSecondLineText, dat->second_line_draw_smileys);
+ }
+}
+
+/*
+* Get the text for Third Line
+*/
+void Cache_GetThirdLineText(struct SHORTDATA *dat, ClcCacheEntry *pdnce)
+{
+ TCHAR Text[240-EXTRA_ICON_COUNT] = {0};
+ int type = TEXT_EMPTY;
+ if (dat->third_line_show)
+ type = Cache_GetLineText(pdnce, dat->third_line_type,(TCHAR*)Text, SIZEOF(Text), dat->third_line_text,
+ dat->third_line_xstatus_has_priority,dat->third_line_show_status_if_no_away,dat->third_line_show_listening_if_no_away,
+ dat->third_line_use_name_and_message_for_xstatus, dat->contact_time_show_only_if_different);
+
+ Text[SIZEOF(Text)-1] = 0; //to be sure that it is null terminated string
+
+ mir_free(pdnce->szThirdLineText);
+
+ if (dat->third_line_show)//Text[0] != '\0')
+ pdnce->szThirdLineText = mir_tstrdup((TCHAR*)Text);
+ else
+ pdnce->szThirdLineText = NULL;
+
+ if (pdnce->szThirdLineText) {
+ if (type == TEXT_LISTENING_TO && pdnce->szThirdLineText[0] != _T('\0'))
+ pdnce->ssThirdLine.AddListeningToIcon(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys);
+ else
+ pdnce->ssThirdLine.ReplaceSmileys(dat, pdnce, pdnce->szThirdLineText, dat->third_line_draw_smileys);
+ }
+}
+
+void RemoveTag(TCHAR *to, TCHAR *tag)
+{
+ TCHAR *st = to;
+ int len = (int)_tcslen(tag);
+ int lastsize = (int)_tcslen(to)+1;
+ while (st = _tcsstr(st,tag)) {
+ lastsize -= len;
+ memmove((void*)st,(void*)(st+len),(lastsize)*sizeof(TCHAR));
+ }
+}
+
+/*
+* Copy string with removing Escape chars from text
+* And BBcodes
+*/
+static int CopySkipUnprintableChars(TCHAR *to, TCHAR * buf, DWORD size)
+{
+ DWORD i;
+ BOOL keep = 0;
+ TCHAR * cp = to;
+ if (!to) return 0;
+ if (!buf) {
+ to[0] = '\0';
+ return 0;
+ }
+
+ for (i=0; i < size; i++) {
+ if (buf[i] == 0) break;
+ if (buf[i] > 0 && buf[i] < ' ') {
+ *cp = ' ';
+ if (!keep) cp++;
+ keep = 1;
+ }
+ else {
+ keep = 0;
+ *cp = buf[i];
+ cp++;
+ }
+ }
+ *cp = 0;
+
+ //remove bbcodes: [b] [i] [u] <b> <i> <u>
+ RemoveTag(to,_T("[b]")); RemoveTag(to,_T("[/b]"));
+ RemoveTag(to,_T("[u]")); RemoveTag(to,_T("[/u]"));
+ RemoveTag(to,_T("[i]")); RemoveTag(to,_T("[/i]"));
+
+ RemoveTag(to,_T("<b>")); RemoveTag(to,_T("</b>"));
+ RemoveTag(to,_T("<u>")); RemoveTag(to,_T("</u>"));
+ RemoveTag(to,_T("<i>")); RemoveTag(to,_T("</i>"));
+
+ RemoveTag(to,_T("[B]")); RemoveTag(to,_T("[/b]"));
+ RemoveTag(to,_T("[U]")); RemoveTag(to,_T("[/u]"));
+ RemoveTag(to,_T("[I]")); RemoveTag(to,_T("[/i]"));
+
+ RemoveTag(to,_T("<B>")); RemoveTag(to,_T("</B>"));
+ RemoveTag(to,_T("<U>")); RemoveTag(to,_T("</U>"));
+ RemoveTag(to,_T("<I>")); RemoveTag(to,_T("</I>"));
+ return i;
+}
+
+// If ExecuteOnAllContactsFuncPtr returns FALSE, stop loop
+// Return TRUE if finished, FALSE if was stoped
+static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param)
+{
+ BOOL res;
+ res = ExecuteOnAllContactsOfGroup(&dat->list, func, param);
+ return res;
+}
+
+static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param)
+{
+ if (!group)
+ return TRUE;
+
+ for (int scanIndex = 0 ; scanIndex < group->cl.count ; scanIndex++) {
+ if (group->cl.items[scanIndex]->type == CLCIT_CONTACT) {
+ if (!func(group->cl.items[scanIndex], FALSE, param))
+ return FALSE;
+
+ if (group->cl.items[scanIndex]->SubAllocated > 0) {
+ for (int i=0 ; i < group->cl.items[scanIndex]->SubAllocated ; i++)
+ if (!func(&group->cl.items[scanIndex]->subcontacts[i], TRUE, param))
+ return FALSE;
+ }
+ }
+ else if (group->cl.items[scanIndex]->type == CLCIT_GROUP)
+ if (!ExecuteOnAllContactsOfGroup(group->cl.items[scanIndex]->group, func, param))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+* Avatar working routines
+*/
+BOOL UpdateAllAvatarsProxy(ClcContact *contact, BOOL subcontact, void *param)
+{
+ Cache_GetAvatar((ClcData *)param, contact);
+ return TRUE;
+}
+
+void UpdateAllAvatars(ClcData *dat)
+{
+ ExecuteOnAllContacts(dat,UpdateAllAvatarsProxy,dat);
+}
+
+BOOL ReduceAvatarPosition(ClcContact *contact, BOOL subcontact, void *param)
+{
+ if (contact->avatar_pos >= *((int *)param))
+ contact->avatar_pos--;
+
+ return TRUE;
+}
+
+void Cache_ProceedAvatarInList(ClcData *dat, ClcContact *contact)
+{
+ struct avatarCacheEntry * ace = contact->avatar_data;
+ int old_pos = contact->avatar_pos;
+
+ if (ace == NULL || ace->dwFlags == AVS_BITMAP_EXPIRED || ace->hbmPic == NULL) {
+ //Avatar was not ready or removed - need to remove it from cache
+ if (old_pos >= 0) {
+ ImageArray_RemoveImage(&dat->avatar_cache, old_pos);
+ // Update all items
+ ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos);
+ contact->avatar_pos = AVATAR_POS_DONT_HAVE;
+ return;
+ }
+ }
+ else if (contact->avatar_data->hbmPic != NULL) //Lets Add it
+ {
+ // Make bounds -> keep aspect radio
+ LONG width_clip;
+ LONG height_clip;
+ RECT rc = {0};
+
+ // Clipping width and height
+ width_clip = dat->avatars_maxwidth_size?dat->avatars_maxwidth_size:dat->avatars_maxheight_size;
+ height_clip = dat->avatars_maxheight_size;
+
+ if (height_clip * ace->bmWidth / ace->bmHeight <= width_clip)
+ width_clip = height_clip * ace->bmWidth / ace->bmHeight;
+ else
+ height_clip = width_clip * ace->bmHeight / ace->bmWidth;
+
+ if (wildcmpit(contact->avatar_data->szFilename,_T("*.gif"))) {
+ if (old_pos == AVATAR_POS_ANIMATED)
+ AniAva_RemoveAvatar(contact->hContact);
+
+ int res = AniAva_AddAvatar(contact->hContact, contact->avatar_data->szFilename, width_clip, height_clip);
+ if (res) {
+ contact->avatar_pos = AVATAR_POS_ANIMATED;
+ contact->avatar_size.cy = HIWORD(res);
+ contact->avatar_size.cx = LOWORD(res);
+ return;
+ }
+ }
+
+ // Create objs
+ void * pt;
+ HDC hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
+ HBITMAP hDrawBmp = ske_CreateDIB32Point(width_clip, height_clip,&pt);
+ HBITMAP oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
+ //need to draw avatar bitmap here
+ {
+ RECT real_rc = {0, 0, width_clip, height_clip};
+
+ int w = width_clip;
+ int h = height_clip;
+ DrawAvatarImageWithGDIp(hdc, 0, 0, w, h,ace->hbmPic, 0, 0, ace->bmWidth,ace->bmHeight,ace->dwFlags,255);
+ }
+ SelectObject(hdc,oldBmp);
+ DeleteDC(hdc);
+ // Add to list
+ if (old_pos >= 0) {
+ ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos);
+ contact->avatar_pos = old_pos;
+ }
+ else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1);
+
+ if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED)
+ AniAva_RemoveAvatar(contact->hContact);
+
+ DeleteObject(hDrawBmp);
+ }
+}
+
+void Cache_GetAvatar(ClcData *dat, ClcContact *contact)
+{
+ int old_pos = contact->avatar_pos;
+ // workaround for avatar service and other wich destroys service on OK_TOEXIT
+ if (g_CluiData.bSTATE != STATE_NORMAL || (dat->use_avatar_service && !ServiceExists(MS_AV_GETAVATARBITMAP))) {
+ contact->avatar_pos = AVATAR_POS_DONT_HAVE;
+ contact->avatar_data = NULL;
+ return;
+ }
+
+ if (dat->use_avatar_service && ServiceExists(MS_AV_GETAVATARBITMAP)) {
+ if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) {
+ contact->avatar_data = (struct avatarCacheEntry *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)contact->hContact, 0);
+ if (contact->avatar_data == NULL || contact->avatar_data->cbSize != sizeof(struct avatarCacheEntry) || contact->avatar_data->dwFlags == AVS_BITMAP_EXPIRED)
+ contact->avatar_data = NULL;
+
+ if (contact->avatar_data != NULL)
+ contact->avatar_data->t_lastAccess = (DWORD)time(NULL);
+ }
+ else contact->avatar_data = NULL;
+
+ Cache_ProceedAvatarInList(dat, contact);
+ }
+ else {
+ contact->avatar_pos = AVATAR_POS_DONT_HAVE;
+ if (dat->avatars_show && !db_get_b(contact->hContact, "CList", "HideContactAvatar", 0)) {
+ DBVARIANT dbv;
+ if (!db_get_ts(contact->hContact, "ContactPhoto", "File", &dbv)) {
+ HBITMAP hBmp = (HBITMAP) CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)dbv.ptszVal);
+ if (hBmp != NULL) {
+ // Make bounds
+ BITMAP bm;
+ if (GetObject(hBmp,sizeof(BITMAP),&bm)) {
+ // Create data...
+ HDC hdc;
+ HBITMAP hDrawBmp,oldBmp;
+
+ // Make bounds -> keep aspect radio
+ LONG width_clip;
+ LONG height_clip;
+ RECT rc = {0};
+
+ // Clipping width and height
+ width_clip = dat->avatars_maxheight_size;
+ height_clip = dat->avatars_maxheight_size;
+
+ if (height_clip * bm.bmWidth / bm.bmHeight <= width_clip)
+ width_clip = height_clip * bm.bmWidth / bm.bmHeight;
+ else
+ height_clip = width_clip * bm.bmHeight / bm.bmWidth;
+
+ // Create objs
+ hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
+ hDrawBmp = ske_CreateDIB32(width_clip, height_clip);
+ oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
+ SetBkMode(hdc,TRANSPARENT);
+
+ POINT org;
+ GetBrushOrgEx(hdc, &org);
+ SetStretchBltMode(hdc, HALFTONE);
+ SetBrushOrgEx(hdc, org.x, org.y, NULL);
+
+ rc.right = width_clip - 1;
+ rc.bottom = height_clip - 1;
+
+ // Draw bitmap 8//8
+ HDC dcMem = CreateCompatibleDC(hdc);
+ HBITMAP obmp = (HBITMAP)SelectObject(dcMem, hBmp);
+ StretchBlt(hdc, 0, 0, width_clip, height_clip,dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
+ SelectObject(dcMem,obmp);
+ DeleteDC(dcMem);
+
+ RECT rtr = {0};
+ rtr.right = width_clip+1;
+ rtr.bottom = height_clip+1;
+ ske_SetRectOpaque(hdc,&rtr);
+
+ hDrawBmp = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
+ SelectObject(hdc,oldBmp);
+ DeleteDC(hdc);
+
+ // Add to list
+ if (old_pos >= 0) {
+ ImageArray_ChangeImage(&dat->avatar_cache, hDrawBmp, old_pos);
+ contact->avatar_pos = old_pos;
+ }
+ else contact->avatar_pos = ImageArray_AddImage(&dat->avatar_cache, hDrawBmp, -1);
+
+ DeleteObject(hDrawBmp);
+ } // if (GetObject(hBmp,sizeof(BITMAP),&bm))
+ DeleteObject(hBmp);
+ } //if (hBmp != NULL)
+ db_free(&dbv);
+ }
+ }
+
+ // Remove avatar if needed
+ if (old_pos >= 0 && contact->avatar_pos == AVATAR_POS_DONT_HAVE) {
+ ImageArray_RemoveImage(&dat->avatar_cache, old_pos);
+ // Update all items
+ ExecuteOnAllContacts(dat, ReduceAvatarPosition, (void *)&old_pos);
+ }
+
+ if (old_pos == AVATAR_POS_ANIMATED && contact->avatar_pos != AVATAR_POS_ANIMATED)
+ AniAva_RemoveAvatar( contact->hContact );
+ }
+}
diff --git a/plugins/Clist_modern/src/modern_clc.cpp b/plugins/Clist_modern/src/modern_clc.cpp
index 1859e65e0d..3dfe676130 100644
--- a/plugins/Clist_modern/src/modern_clc.cpp
+++ b/plugins/Clist_modern/src/modern_clc.cpp
@@ -1,1888 +1,1888 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
-Copyright (c) 2000-08 Miranda ICQ/IM project,
-all portions of this codebase are copyrighted to the people
-listed in contributors.txt.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-/************************************************************************/
-/* Module responsible for working with contact list control */
-/************************************************************************/
-
-#include "hdr/modern_commonheaders.h"
-#include "m_skin.h"
-#include "hdr/modern_commonprototypes.h"
-
-#include "hdr/modern_clc.h"
-#include "hdr/modern_clist.h"
-#include "hdr/modern_clcpaint.h"
-
-#include "m_modernopt.h"
-
-int ModernOptInit(WPARAM wParam, LPARAM lParam);
-int ModernSkinOptInit(WPARAM wParam, LPARAM lParam);
-
-/*
-* Private module variables
-*/
-static HANDLE hShowInfoTipEvent;
-static POINT HitPoint;
-static BOOL fMouseUpped;
-static BYTE IsDragToScrollMode = 0;
-static int StartDragPos = 0;
-static int StartScrollPos = 0;
-HANDLE hAckHook = NULL;
-HANDLE hAvatarChanged = NULL;
-static BOOL g_bSortTimerIsSet = FALSE;
-static ClcContact *hitcontact = NULL;
-HANDLE hSkinFolder;
-TCHAR SkinsFolder[MAX_PATH];
-
-static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam);
-static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam);
-static int clcHookBkgndConfigChanged(WPARAM wParam, LPARAM lParam);
-static int clcProceedDragToScroll(HWND hwnd, int Y);
-static int clcExitDragToScroll();
-
-
-int ReloadSkinFolder(WPARAM wParam, LPARAM lParam)
-{
- FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER));
- return 0;
-}
-
-static int clcHookModulesLoaded(WPARAM wParam, LPARAM lParam)
-{
- if (MirandaExiting())
- return 0;
-
- HookEvent(ME_MODERNOPT_INITIALIZE, ModernOptInit);
- HookEvent(ME_MODERNOPT_INITIALIZE, ModernSkinOptInit);
-
- HookEvent(ME_FOLDERS_PATH_CHANGED, ReloadSkinFolder);
- hSkinFolder = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("Modern contact list"), MIRANDA_PATHT _T("\\") _T(DEFAULT_SKIN_FOLDER));
- FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER));
-
- // Get icons
- TCHAR szMyPath[MAX_PATH];
- GetModuleFileName(g_hInst, szMyPath, SIZEOF(szMyPath));
-
- SKINICONDESC sid = { sizeof(sid) };
- sid.cx = sid.cy = 16;
- sid.ptszDefaultFile = szMyPath;
- sid.flags = SIDF_PATH_TCHAR;
-
- sid.pszSection = LPGEN("Contact list");
- sid.pszDescription = LPGEN("Listening to");
- sid.pszName = "LISTENING_TO_ICON";
- sid.iDefaultIndex = -IDI_LISTENING_TO;
- Skin_AddIcon(&sid);
-
- sid.pszSection = LPGEN("Contact list") "/" LPGEN("Avatar overlay");
- for (int i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
- sid.pszDescription = g_pAvatarOverlayIcons[i].description;
- sid.pszName = g_pAvatarOverlayIcons[i].name;
- sid.iDefaultIndex = -g_pAvatarOverlayIcons[i].id;
- Skin_AddIcon(&sid);
- }
-
- sid.pszSection = LPGEN("Contact list") "/" LPGEN("Status overlay");
- for (int i = 0; i < SIZEOF(g_pStatusOverlayIcons); i++) {
- sid.pszDescription = g_pStatusOverlayIcons[i].description;
- sid.pszName = g_pStatusOverlayIcons[i].name;
- sid.iDefaultIndex = -g_pStatusOverlayIcons[i].id;
- Skin_AddIcon(&sid);
- }
-
- clcHookIconsChanged(0, 0);
-
- HookEvent(ME_SKIN2_ICONSCHANGED, clcHookIconsChanged);
-
- // Register smiley category
- if (ServiceExists(MS_SMILEYADD_REGISTERCATEGORY)) {
- SMADD_REGCAT rc;
- rc.cbSize = sizeof(rc);
- rc.name = "clist";
- rc.dispname = Translate("Contact list smileys");
-
- CallService(MS_SMILEYADD_REGISTERCATEGORY, 0, (LPARAM)&rc);
-
- HookEvent(ME_SMILEYADD_OPTIONSCHANGED, clcHookSmileyAddOptionsChanged);
- }
-
- CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("List background")"/CLC"), 0);
- CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Menu background")"/Menu"), 0);
- CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Status bar background")"/StatusBar"), 0);
- CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Frames title bar background")"/FrameTitleBar"), 0);
-
- HookEvent(ME_BACKGROUNDCONFIG_CHANGED, clcHookBkgndConfigChanged);
- HookEvent(ME_BACKGROUNDCONFIG_CHANGED, BgStatusBarChange);
- HookEvent(ME_BACKGROUNDCONFIG_CHANGED, OnFrameTitleBarBackgroundChange);
- HookEvent(ME_COLOUR_RELOAD, OnFrameTitleBarBackgroundChange);
-
- AniAva_UpdateOptions();
- return 0;
-}
-
-static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam)
-{
- if (MirandaExiting()) return 0;
- pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
- pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0);
- return 0;
-}
-
-static int clcHookProtoAck(WPARAM wParam, LPARAM lParam)
-{
- return ClcDoProtoAck(wParam, (ACKDATA*)lParam);
-}
-
-static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam)
-{
- int i;
- if (MirandaExiting()) return 0;
- for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
- g_pAvatarOverlayIcons[i].listID = -1;
- g_pStatusOverlayIcons[i].listID = -1;
- }
-
- if (hAvatarOverlays)
- ImageList_Destroy(hAvatarOverlays);
- hAvatarOverlays = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, SIZEOF(g_pAvatarOverlayIcons) * 2, 1);
-
- for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
- HICON hIcon = Skin_GetIcon(g_pAvatarOverlayIcons[i].name);
- g_pAvatarOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon);
- Skin_ReleaseIcon(g_pAvatarOverlayIcons[i].name);
-
- hIcon = Skin_GetIcon(g_pStatusOverlayIcons[i].name);
- g_pStatusOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon);
- Skin_ReleaseIcon(g_pStatusOverlayIcons[i].name);
- }
-
- g_hListeningToIcon = Skin_GetIcon("LISTENING_TO_ICON");
-
- pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0);
- AniAva_UpdateOptions();
- return 0;
-}
-
-static int clcMetaModeChanged(WPARAM, LPARAM)
-{
- pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0);
- return 0;
-}
-
-static int clcMetacontactChanged(WPARAM hMeta, LPARAM)
-{
- pcli->pfnClcBroadcast(INTM_NAMEORDERCHANGED, 0, 0);
- return 0;
-}
-
-static int clcHookSettingChanged(WPARAM hContact, LPARAM lParam)
-{
- if (MirandaExiting())
- return 0;
-
- DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam;
- if (hContact == NULL) {
- if (!mir_strcmp(cws->szModule, "CListGroups"))
- pcli->pfnClcBroadcast(INTM_GROUPSCHANGED, hContact, lParam);
- else if (!strcmp(cws->szSetting, "XStatusId") || !strcmp(cws->szSetting, "XStatusName"))
- cliCluiProtocolStatusChanged(0, cws->szModule);
- }
- else // hContact != NULL
- {
- if (!strcmp(cws->szSetting, "TickTS"))
- pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0);
- else if (!strcmp(cws->szModule, "UserInfo")) {
- if (!strcmp(cws->szSetting, "Timezone"))
- pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0);
- }
- else if (!strcmp(cws->szModule, "CList")) {
- if (!strcmp(cws->szSetting, "StatusMsg"))
- pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
-
- }
- else if (!strcmp(cws->szModule, "ContactPhoto")) {
- if (!strcmp(cws->szSetting, "File"))
- pcli->pfnClcBroadcast(INTM_AVATARCHANGED, hContact, 0);
- }
- else {
- if ((!strcmp(cws->szSetting, "XStatusName") || !strcmp(cws->szSetting, "XStatusMsg")))
- pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
- else if (!strcmp(cws->szSetting, "XStatusId"))
- pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0);
- else if (!strcmp(cws->szSetting, "Timezone"))
- pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0);
- else if (!strcmp(cws->szSetting, "ListeningTo"))
- pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
- else if (!strcmp(cws->szSetting, "Transport") || !strcmp(cws->szSetting, "IsTransported")) {
- pcli->pfnInvalidateDisplayNameCacheEntry(hContact);
- pcli->pfnClcBroadcast(CLM_AUTOREBUILD, hContact, 0);
- }
- }
- }
- return 0;
-}
-
-static int clcHookDbEventAdded(WPARAM hContact, LPARAM lParam)
-{
- g_CluiData.t_now = time(NULL);
- if (hContact && lParam) {
- DBEVENTINFO dbei = { sizeof(dbei) };
- db_event_get((HANDLE)lParam, &dbei);
- if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
- db_set_dw(hContact, "CList", "mf_lastmsg", dbei.timestamp);
- ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
- if (pdnce)
- pdnce->dwLastMsgTime = dbei.timestamp;
- }
- }
- return 0;
-}
-
-static int clcHookBkgndConfigChanged(WPARAM, LPARAM)
-{
- pcli->pfnClcOptionsChanged();
- return 0;
-}
-
-static int clcHookAvatarChanged(WPARAM wParam, LPARAM lParam)
-{
- if (MirandaExiting()) return 0;
- pcli->pfnClcBroadcast(INTM_AVATARCHANGED, wParam, lParam);
- return 0;
-}
-
-static int clcExitDragToScroll()
-{
- if (!IsDragToScrollMode) return 0;
- IsDragToScrollMode = 0;
- ReleaseCapture();
- return 1;
-}
-
-static int clcProceedDragToScroll(HWND hwnd, int Y)
-{
- int pos, dy;
- if (!IsDragToScrollMode) return 0;
- if (GetCapture() != hwnd) clcExitDragToScroll();
- dy = StartDragPos - Y;
- pos = StartScrollPos + dy;
- if (pos < 0)
- pos = 0;
- SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, pos), 0);
- return 1;
-}
-
-
-
-static int clcSearchNextContact(HWND hwnd, ClcData *dat, int index, const TCHAR *text, int prefixOk, BOOL fSearchUp)
-{
- ClcGroup *group = &dat->list;
- int testlen = lstrlen(text);
- BOOL fReturnAsFound = FALSE;
- int nLastFound = -1;
- if (index == -1) fReturnAsFound = TRUE;
- group->scanIndex = 0;
- for (;;) {
- if (group->scanIndex == group->cl.count) {
- group = group->parent;
- if (group == NULL)
- break;
- group->scanIndex++;
- continue;
- }
- if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) {
- bool found;
- if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
- found = true;
- }
- else if (dat->filterSearch) {
- TCHAR *lowered_szText = CharLowerW(NEWTSTR_ALLOCA(group->cl.items[group->scanIndex]->szText));
- TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch));
- found = _tcsstr(lowered_szText, lowered_search) != NULL;
- }
- else {
- found = ((prefixOk && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, text, -1, group->cl.items[group->scanIndex]->szText, testlen)) || (!prefixOk && !lstrcmpi(text, group->cl.items[group->scanIndex]->szText)));
- }
- if (found) {
- ClcGroup *contactGroup = group;
- int contactScanIndex = group->scanIndex;
- int foundindex;
- for (; group; group = group->parent)
- pcli->pfnSetGroupExpand(hwnd, dat, group, 1);
- foundindex = pcli->pfnGetRowsPriorTo(&dat->list, contactGroup, contactScanIndex);
- if (fReturnAsFound)
- return foundindex;
- else if (nLastFound != -1 && fSearchUp && foundindex == index)
- return nLastFound;
- else if (!fSearchUp && foundindex == index)
- fReturnAsFound = TRUE;
- else
- nLastFound = foundindex;
- group = contactGroup;
- group->scanIndex = contactScanIndex;
- }
- if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
- if (!(dat->exStyle & CLS_EX_QUICKSEARCHVISONLY) || group->cl.items[group->scanIndex]->group->expanded) {
- group = group->cl.items[group->scanIndex]->group;
- group->scanIndex = 0;
- continue;
- }
- }
- }
- group->scanIndex++;
- }
- return -1;
-}
-
-static BOOL clcItemNotHiddenOffline(ClcData *dat, ClcGroup* group, ClcContact *contact)
-{
- if (g_CluiData.bFilterEffective) return FALSE;
-
- if (!contact) return FALSE;
- ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
- if (!pdnce) return FALSE;
- if (pdnce->m_cache_nNoHiddenOffline) return TRUE;
-
- if (!group) return FALSE;
- if (group->hideOffline) return FALSE;
-
- if (CLCItems_IsShowOfflineGroup(group)) return TRUE;
-
- return FALSE;
-}
-
-static LRESULT clcOnCreate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- dat = (ClcData*)mir_calloc(sizeof(ClcData));
- SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat);
- dat->hCheckBoxTheme = xpt_AddThemeHandle(hwnd, L"BUTTON");
- dat->m_paintCouter = 0;
- dat->hWnd = hwnd;
- dat->use_avatar_service = ServiceExists(MS_AV_GETAVATARBITMAP);
- if (dat->use_avatar_service)
- if (!hAvatarChanged)
- hAvatarChanged = HookEvent(ME_AV_AVATARCHANGED, clcHookAvatarChanged);
-
- ImageArray_Initialize(&dat->avatar_cache, FALSE, 20); //this array will be used to keep small avatars too
-
- RowHeights_Initialize(dat);
-
- dat->needsResort = 1;
- dat->MetaIgnoreEmptyExtra = db_get_b(NULL, "CLC", "MetaIgnoreEmptyExtra", SETTING_METAIGNOREEMPTYEXTRA_DEFAULT);
-
- dat->IsMetaContactsEnabled = (!(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_MANUALUPDATE)) && db_mc_isEnabled();
-
- dat->expandMeta = db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT);
- dat->useMetaIcon = db_get_b(NULL, "CLC", "Meta", SETTING_USEMETAICON_DEFAULT);
- dat->drawOverlayedStatus = db_get_b(NULL, "CLC", "DrawOverlayedStatus", SETTING_DRAWOVERLAYEDSTATUS_DEFAULT);
- g_CluiData.bSortByOrder[0] = db_get_b(NULL, "CList", "SortBy1", SETTING_SORTBY1_DEFAULT);
- g_CluiData.bSortByOrder[1] = db_get_b(NULL, "CList", "SortBy2", SETTING_SORTBY2_DEFAULT);
- g_CluiData.bSortByOrder[2] = db_get_b(NULL, "CList", "SortBy3", SETTING_SORTBY3_DEFAULT);
- g_CluiData.fSortNoOfflineBottom = db_get_b(NULL, "CList", "NoOfflineBottom", SETTING_NOOFFLINEBOTTOM_DEFAULT);
- dat->menuOwnerID = -1;
- dat->menuOwnerType = CLCIT_INVALID;
-
- corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- LoadCLCOptions(hwnd, dat, TRUE);
- if (dat->contact_time_show || dat->second_line_type == TEXT_CONTACT_TIME || dat->third_line_type == TEXT_CONTACT_TIME)
- CLUI_SafeSetTimer(hwnd, TIMERID_INVALIDATE, 5000, NULL);
- else
- KillTimer(hwnd, TIMERID_INVALIDATE);
-
- TRACE("Create New ClistControl TO END\r\n");
- return 0;
-}
-
-static LRESULT clcOnHitTest(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- return DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
-}
-
-static LRESULT clcOnCommand(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- ClcContact *contact;
- int hit = pcli->pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
- if (hit == -1) return 0;
- if (contact->type == CLCIT_CONTACT && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), contact->hContact)) return 0;
-
- switch (LOWORD(wParam)) {
- case POPUP_NEWSUBGROUP:
- if (contact->type != CLCIT_GROUP)
- return 0;
- SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
- SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | CLS_USEGROUPS);
- CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0);
- return 0;
- case POPUP_RENAMEGROUP:
- pcli->pfnBeginRenameSelection(hwnd, dat);
- return 0;
- case POPUP_DELETEGROUP:
- if (contact->type == CLCIT_GROUP)
- CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0);
- return 0;
- case POPUP_GROUPSHOWOFFLINE:
- if (contact->type == CLCIT_GROUP) {
- CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(CLCItems_IsShowOfflineGroup(contact->group) ? 0 : GROUPF_SHOWOFFLINE, GROUPF_SHOWOFFLINE));
- pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
- }
- return 0;
- case POPUP_GROUPHIDEOFFLINE:
- if (contact->type == CLCIT_GROUP)
- CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE));
- return 0;
- }
-
- if (contact->type == CLCIT_GROUP)
- if (CallService(MO_PROCESSCOMMANDBYMENUIDENT, LOWORD(wParam), (LPARAM)hwnd))
- return 0;
-
- return 0;
-}
-
-static LRESULT clcOnSize(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- pcli->pfnEndRename(hwnd, dat, 1);
- KillTimer(hwnd, TIMERID_INFOTIP);
- KillTimer(hwnd, TIMERID_RENAME);
- cliRecalcScrollBar(hwnd, dat);
- if (g_CluiData.fDisableSkinEngine || dat->force_in_dialog) {
- RECT rc = { 0 };
- GetClientRect(hwnd, &rc);
- if (rc.right == 0)
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- rc.bottom = max(dat->row_min_heigh, 1);
-
- HDC hdc = GetDC(hwnd);
- int depth = GetDeviceCaps(hdc, BITSPIXEL);
- if (depth < 16)
- depth = 16;
- HBITMAP hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL);
- HBITMAP hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL);
- HDC hdcMem = CreateCompatibleDC(hdc);
- HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp);
- HBRUSH hBrush = CreateSolidBrush((dat->useWindowsColours || dat->force_in_dialog) ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour);
- FillRect(hdcMem, &rc, hBrush);
- DeleteObject(hBrush);
-
- HBITMAP hoMaskBmp = (HBITMAP)SelectObject(hdcMem, hBmpMask);
- FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
- SelectObject(hdcMem, hoMaskBmp);
- SelectObject(hdcMem, hoBmp);
- DeleteDC(hdcMem);
- ReleaseDC(hwnd, hdc);
- if (dat->himlHighlight)
- ImageList_Destroy(dat->himlHighlight);
- dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, ILC_COLOR32 | ILC_MASK, 1, 1);
- ImageList_Add(dat->himlHighlight, hBmp, hBmpMask);
- DeleteObject(hBmpMask);
- DeleteObject(hBmp);
- }
- else if (dat->himlHighlight) {
- ImageList_Destroy(dat->himlHighlight);
- dat->himlHighlight = NULL;
- }
- return 0;
-}
-
-static LRESULT clcOnChar(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (wParam == 27 && dat->szQuickSearch[0] == '\0') { //escape and not quick search
- // minimize clist
- CListMod_HideWindow(pcli->hwndContactList, SW_HIDE);
- }
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-}
-static LRESULT clcOnPaint(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (IsWindowVisible(hwnd)) {
- if (!g_CluiData.fLayered || GetParent(hwnd) != pcli->hwndContactList) {
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hwnd, &ps);
- g_clcPainter.cliPaintClc(hwnd, dat, hdc, &ps.rcPaint);
- EndPaint(hwnd, &ps);
- }
- else CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, (WPARAM)hwnd, 0);
- }
- return DefWindowProc(hwnd, msg, wParam, lParam);
-}
-
-static LRESULT clcOnEraseBkGround(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- return 1;
-}
-
-static LRESULT clcOnKeyDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (wParam == VK_CONTROL)
- return 0;
-
- pcli->pfnHideInfoTip(hwnd, dat);
- KillTimer(hwnd, TIMERID_INFOTIP);
- KillTimer(hwnd, TIMERID_RENAME);
-
- if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU))
- return 0;
-
- RECT clRect;
- GetClientRect(hwnd, &clRect);
- int pageSize = (dat->rowHeight) ? clRect.bottom / dat->rowHeight : 0;
- int selMoved = 0;
- int changeGroupExpand = 0;
-
- switch (wParam) {
- case VK_DOWN:
- case VK_UP:
- if (dat->szQuickSearch[0] != '\0' && dat->selection != -1) { //get next contact
- //get next contact
- int index = clcSearchNextContact(hwnd, dat, dat->selection, dat->szQuickSearch, 1, (wParam == VK_UP));
- if (index == -1) {
- MessageBeep(MB_OK);
- return 0;
- }
-
- dat->selection = index;
- pcli->pfnInvalidateRect(hwnd, NULL, FALSE);
- pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
- return 0;
- }
-
- if (wParam == VK_DOWN) dat->selection++;
- if (wParam == VK_UP) dat->selection--;
- selMoved = 1;
- break;
-
- case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break;
- case VK_NEXT: dat->selection += pageSize; selMoved = 1; break;
- case VK_HOME: dat->selection = 0; selMoved = 1; break;
- case VK_END: dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break;
- case VK_LEFT: changeGroupExpand = 1; break;
- case VK_RIGHT: changeGroupExpand = 2; break;
- case VK_RETURN:
- pcli->pfnDoSelectionDefaultAction(hwnd, dat);
- SetCapture(hwnd);
- dat->szQuickSearch[0] = 0;
- if (dat->filterSearch)
- pcli->pfnSaveStateAndRebuildList(hwnd, dat);
- return 0;
-
- case VK_F2: cliBeginRenameSelection(hwnd, dat); /*SetCapture(hwnd);*/ return 0;
- case VK_DELETE: pcli->pfnDeleteFromContactList(hwnd, dat); SetCapture(hwnd); return 0;
- case VK_ESCAPE:
- if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
- dat->iDragItem = -1;
- dat->iInsertionMark = -1;
- dat->dragStage = 0;
- ReleaseCapture();
- }
- return 0;
-
- default:
- NMKEY nmkey;
- nmkey.hdr.hwndFrom = hwnd;
- nmkey.hdr.idFrom = GetDlgCtrlID(hwnd);
- nmkey.hdr.code = NM_KEYDOWN;
- nmkey.nVKey = wParam;
- nmkey.uFlags = HIWORD(lParam);
-
- if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nmkey)) {
- SetCapture(hwnd);
- return 0;
- }
- }
-
- if (changeGroupExpand) {
- ClcContact *contact;
- ClcGroup *group;
- int hit = cliGetRowByIndex(dat, dat->selection, &contact, &group);
- if (hit == -1) {
- SetCapture(hwnd);
- return 0;
- }
-
- if (contact->type == CLCIT_CONTACT && (contact->isSubcontact || contact->SubAllocated > 0)) {
- if (contact->isSubcontact && changeGroupExpand == 1) {
- dat->selection -= contact->isSubcontact;
- selMoved = 1;
- }
- else if (!contact->isSubcontact && contact->SubAllocated > 0) {
- if (changeGroupExpand == 1 && !contact->SubExpanded) {
- dat->selection = cliGetRowsPriorTo(&dat->list, group, -1);
- selMoved = 1;
- }
- else if (changeGroupExpand == 1 && contact->SubExpanded) {
- //Contract
- ClcContact *ht = NULL;
- KillTimer(hwnd, TIMERID_SUBEXPAND);
- contact->SubExpanded = 0;
- db_set_b(contact->hContact, "CList", "Expanded", 0);
- ht = contact;
- dat->needsResort = 1;
- pcli->pfnSortCLC(hwnd, dat, 1);
- cliRecalcScrollBar(hwnd, dat);
- hitcontact = NULL;
- }
- else if (changeGroupExpand == 2 && contact->SubExpanded) {
- dat->selection++;
- selMoved = 1;
- }
- else if (changeGroupExpand == 2 && !contact->SubExpanded && dat->expandMeta) {
- ClcContact *ht = NULL;
- KillTimer(hwnd, TIMERID_SUBEXPAND);
- contact->SubExpanded = 1;
- db_set_b(contact->hContact, "CList", "Expanded", 1);
- ht = contact;
- dat->needsResort = 1;
- pcli->pfnSortCLC(hwnd, dat, 1);
- cliRecalcScrollBar(hwnd, dat);
- if (ht) {
- ClcContact *contact2;
- ClcGroup *group2;
- if (FindItem(hwnd, dat, contact->hContact, &contact2, &group2, NULL, FALSE)) {
- int i = cliGetRowsPriorTo(&dat->list, group2, GetContactIndex(group2, contact2));
- pcli->pfnEnsureVisible(hwnd, dat, i + contact->SubAllocated, 0);
- }
- }
- hitcontact = NULL;
- }
- }
- }
- else {
- if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) {
- if (group == &dat->list) { SetCapture(hwnd); return 0; }
- dat->selection = cliGetRowsPriorTo(&dat->list, group, -1);
- selMoved = 1;
- }
- else {
- if (contact->type == CLCIT_GROUP) {
- if (changeGroupExpand == 1) {
- if (!contact->group->expanded) {
- dat->selection--;
- selMoved = 1;
- }
- else pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 0);
- }
- else if (changeGroupExpand == 2) {
- pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 1);
- dat->selection++;
- selMoved = 1;
- }
- else { SetCapture(hwnd); return 0; }
- }
- }
- }
- }
- if (selMoved) {
- if (dat->selection >= pcli->pfnGetGroupContentsCount(&dat->list, 1))
- dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1;
- if (dat->selection < 0) dat->selection = 0;
- if (dat->bCompactMode)
- SendMessage(hwnd, WM_SIZE, 0, 0);
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
- UpdateWindow(hwnd);
- SetCapture(hwnd);
- return 0;
- }
- SetCapture(hwnd);
- return 0;
-}
-
-void clcSetDelayTimer(UINT_PTR uIDEvent, HWND hwnd, int nDelay)
-{
- KillTimer(hwnd, uIDEvent);
- int delay = nDelay;
- if (delay == -1) {
- switch (uIDEvent) {
- case TIMERID_DELAYEDRESORTCLC: delay = 10; break;
- case TIMERID_RECALCSCROLLBAR: delay = 10; break;
- case TIMERID_REBUILDAFTER: delay = 50; break;
- default: delay = 100; break;
- }
- }
- CLUI_SafeSetTimer(hwnd, uIDEvent, delay, NULL);
-}
-
-static LRESULT clcOnTimer(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- switch (wParam) {
- case TIMERID_INVALIDATE_FULL:
- KillTimer(hwnd, TIMERID_INVALIDATE_FULL);
- pcli->pfnRecalcScrollBar(hwnd, dat);
- pcli->pfnInvalidateRect(hwnd, NULL, 0);
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- case TIMERID_INVALIDATE:
- {
- time_t cur_time = (time(NULL) / 60);
- if (cur_time != dat->last_tick_time) {
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- dat->last_tick_time = cur_time;
- }
- }
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- case TIMERID_SUBEXPAND:
- KillTimer(hwnd, TIMERID_SUBEXPAND);
- {
- ClcContact *ht = NULL;
- if (hitcontact && dat->expandMeta) {
- if (hitcontact->SubExpanded) hitcontact->SubExpanded = 0; else hitcontact->SubExpanded = 1;
- db_set_b(hitcontact->hContact, "CList", "Expanded", hitcontact->SubExpanded);
- if (hitcontact->SubExpanded)
- ht = &(hitcontact->subcontacts[hitcontact->SubAllocated - 1]);
- }
-
- dat->needsResort = 1;
- pcli->pfnSortCLC(hwnd, dat, 1);
- cliRecalcScrollBar(hwnd, dat);
- if (ht) {
- int i = 0;
- ClcContact *contact;
- ClcGroup *group;
- if (FindItem(hwnd, dat, hitcontact->hContact, &contact, &group, NULL, FALSE)) {
- i = cliGetRowsPriorTo(&dat->list, group, GetContactIndex(group, contact));
- pcli->pfnEnsureVisible(hwnd, dat, i + hitcontact->SubAllocated, 0);
- }
- }
- hitcontact = NULL;
- }
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- case TIMERID_DELAYEDRESORTCLC:
- TRACE("Do sort on Timer\n");
- KillTimer(hwnd, TIMERID_DELAYEDRESORTCLC);
- pcli->pfnSortCLC(hwnd, dat, 1);
- pcli->pfnInvalidateRect(hwnd, NULL, FALSE);
- return 0;
-
- case TIMERID_RECALCSCROLLBAR:
- KillTimer(hwnd, TIMERID_RECALCSCROLLBAR);
- pcli->pfnRecalcScrollBar(hwnd, dat);
- return 0;
-
- default:
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- }
- return 0;
-}
-
-
-static LRESULT clcOnActivate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- TRACE("clcOnActivate\n");
- if (dat->bCompactMode) {
- cliRecalcScrollBar(hwnd, dat);
- if (dat->hwndRenameEdit == NULL)
- PostMessage(hwnd, WM_SIZE, 0, 0);
- }
- dat->dragStage |= DRAGSTAGEF_SKIPRENAME;
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-}
-
-static LRESULT clcOnSetCursor(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (!CLUI_IsInMainWindow(hwnd))
- return DefWindowProc(hwnd, msg, wParam, lParam);
-
- if (g_CluiData.nBehindEdgeState > 0)
- CLUI_ShowFromBehindEdge();
-
- if (g_CluiData.bBehindEdgeSettings)
- CLUI_UpdateTimer(0);
-
- int lResult = CLUI_TestCursorOnBorders();
- return lResult ? lResult : DefWindowProc(hwnd, msg, wParam, lParam);
-}
-
-static LRESULT clcOnLButtonDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- POINT pt = { LOWORD(lParam), HIWORD(lParam) };
- ClientToScreen(hwnd, &pt);
- int k = CLUI_SizingOnBorder(pt, 0);
- if (k) {
- int io = dat->iHotTrack;
- dat->iHotTrack = 0;
- if (dat->exStyle & CLS_EX_TRACKSELECT)
- pcli->pfnInvalidateItem(hwnd, dat, io);
-
- if (k && GetCapture() == hwnd)
- SendMessage(GetParent(hwnd), WM_PARENTNOTIFY, WM_LBUTTONDOWN, lParam);
- return FALSE;
- }
-
- fMouseUpped = FALSE;
- pcli->pfnHideInfoTip(hwnd, dat);
- KillTimer(hwnd, TIMERID_INFOTIP);
- KillTimer(hwnd, TIMERID_RENAME);
- KillTimer(hwnd, TIMERID_SUBEXPAND);
-
- pcli->pfnEndRename(hwnd, dat, 1);
- dat->ptDragStart.x = (short)LOWORD(lParam);
- dat->ptDragStart.y = (short)HIWORD(lParam);
-
- ClcContact *contact;
- ClcGroup *group;
- DWORD hitFlags;
- int hit = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), &contact, &group, &hitFlags);
- if (GetFocus() != hwnd)
- SetFocus(hwnd);
- if (hit != -1 && !(hitFlags & CLCHT_NOWHERE)) {
- if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) {
- if (!(dat->dragStage & DRAGSTAGEF_SKIPRENAME)) {
- SetCapture(hwnd);
- dat->iDragItem = dat->selection;
- dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME;
- dat->dragAutoScrolling = 0;
- return TRUE;
- }
- else {
- dat->dragStage &= ~DRAGSTAGEF_SKIPRENAME;
- return TRUE;
- }
- }
- }
-
- if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_CONTACT && contact->SubAllocated && !contact->isSubcontact)
- if (hitFlags & CLCHT_ONITEMICON && dat->expandMeta) {
- BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT);
-
- hitcontact = contact;
- HitPoint.x = (short)LOWORD(lParam);
- HitPoint.y = (short)HIWORD(lParam);
- fMouseUpped = FALSE;
- if ((GetKeyState(VK_SHIFT) & 0x8000) || (GetKeyState(VK_CONTROL) & 0x8000) || (GetKeyState(VK_MENU) & 0x8000)) {
- fMouseUpped = TRUE;
- hitcontact = contact;
- KillTimer(hwnd, TIMERID_SUBEXPAND);
- CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL);
- }
- }
- else hitcontact = NULL;
-
- if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_GROUP && (hitFlags & CLCHT_ONITEMICON)) {
- ClcGroup *selgroup;
- ClcContact *selcontact;
- dat->selection = cliGetRowByIndex(dat, dat->selection, &selcontact, &selgroup);
- pcli->pfnSetGroupExpand(hwnd, dat, contact->group, -1);
- if (dat->selection != -1) {
- dat->selection = cliGetRowsPriorTo(&dat->list, selgroup, GetContactIndex(selgroup, selcontact));
- if (dat->selection == -1)
- dat->selection = cliGetRowsPriorTo(&dat->list, contact->group, -1);
- }
-
- if (dat->bCompactMode)
- SendMessage(hwnd, WM_SIZE, 0, 0);
- else {
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- UpdateWindow(hwnd);
- }
- return TRUE;
- }
-
- if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && (hitFlags & CLCHT_ONITEMCHECK)) {
- int bNewState = (contact->flags & CONTACTF_CHECKED) == 0; // inversion
-
- if (contact->type == CLCIT_GROUP)
- pcli->pfnSetGroupChildCheckboxes(contact->group, bNewState);
- else
- pcli->pfnSetContactCheckboxes(contact, bNewState);
- pcli->pfnRecalculateGroupCheckboxes(hwnd, dat);
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
-
- NMCLISTCONTROL nm;
- nm.hdr.code = CLN_CHECKCHANGED;
- nm.hdr.hwndFrom = hwnd;
- nm.hdr.idFrom = GetDlgCtrlID(hwnd);
- nm.flags = 0;
- nm.hItem = ContactToItemHandle(contact, &nm.flags);
- SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
- }
-
- if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) {
- NMCLISTCONTROL nm;
- nm.hdr.code = NM_CLICK;
- nm.hdr.hwndFrom = hwnd;
- nm.hdr.idFrom = GetDlgCtrlID(hwnd);
- nm.flags = 0;
- nm.hItem = (hit == -1 || hitFlags & CLCHT_NOWHERE) ? NULL : ContactToItemHandle(contact, &nm.flags);
- nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1;
- nm.pt = dat->ptDragStart;
- SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
- }
-
- if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA))
- return FALSE;
-
- dat->selection = (hitFlags & CLCHT_NOWHERE) ? -1 : hit;
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
-
- UpdateWindow(hwnd);
- if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP) && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK | CLCHT_NOWHERE))) {
- SetCapture(hwnd);
- dat->iDragItem = dat->selection;
- dat->dragStage = DRAGSTAGE_NOTMOVED;
- dat->dragAutoScrolling = 0;
- }
-
- if (dat->bCompactMode)
- SendMessage(hwnd, WM_SIZE, 0, 0);
-
- if (dat->selection != -1)
- pcli->pfnEnsureVisible(hwnd, dat, hit, 0);
- return TRUE;
-}
-
-static LRESULT clcOnCaptureChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if ((HWND)lParam != hwnd) {
- if (dat->iHotTrack != -1) {
- int i;
- i = dat->iHotTrack;
- dat->iHotTrack = -1;
- pcli->pfnInvalidateItem(hwnd, dat, i);
- pcli->pfnHideInfoTip(hwnd, dat);
- }
- }
- return 0;
-}
-
-static LRESULT clcOnMouseMove(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- BOOL isOutside = FALSE;
- if (CLUI_IsInMainWindow(hwnd)) {
- if (g_CluiData.bBehindEdgeSettings)
- CLUI_UpdateTimer(0);
- CLUI_TestCursorOnBorders();
- }
-
- if (clcProceedDragToScroll(hwnd, (short)HIWORD(lParam)))
- return 0;
-
- if (dat->dragStage & DRAGSTAGEF_MAYBERENAME) {
- POINT pt = UNPACK_POINT(lParam);
- if (abs(pt.x - dat->ptDragStart.x) > GetSystemMetrics(SM_CXDOUBLECLK) || abs(pt.y - dat->ptDragStart.y) > GetSystemMetrics(SM_CYDOUBLECLK)) {
- KillTimer(hwnd, TIMERID_RENAME);
- dat->dragStage &= (~DRAGSTAGEF_MAYBERENAME);
- }
- }
-
- if (dat->iDragItem == -1) {
- POINT pt = UNPACK_POINT(lParam);
- ClientToScreen(hwnd, &pt);
- HWND window = WindowFromPoint(pt);
- if (window != hwnd)
- isOutside = TRUE;
- }
-
- if (hitcontact != NULL) {
- int x = (short)LOWORD(lParam);
- int y = (short)HIWORD(lParam);
- int xm = GetSystemMetrics(SM_CXDOUBLECLK);
- int ym = GetSystemMetrics(SM_CYDOUBLECLK);
- if (abs(HitPoint.x - x) > xm || abs(HitPoint.y - y) > ym) {
- if (fMouseUpped) {
- KillTimer(hwnd, TIMERID_SUBEXPAND);
- CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL);
- fMouseUpped = FALSE;
- }
- else {
- KillTimer(hwnd, TIMERID_SUBEXPAND);
- hitcontact = NULL;
- fMouseUpped = FALSE;
- }
- }
- }
-
- if (dat->iDragItem == -1) {
- DWORD flag = 0;
- int iOldHotTrack = dat->iHotTrack;
-
- if (dat->hwndRenameEdit != NULL || GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000)
- return 0;
-
- dat->iHotTrack = isOutside ? -1 : cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flag);
-
- if (flag & CLCHT_NOWHERE)
- dat->iHotTrack = -1;
-
- if (iOldHotTrack != dat->iHotTrack || isOutside) {
- if (iOldHotTrack == -1 && !isOutside)
- SetCapture(hwnd);
-
- if (dat->iHotTrack == -1 || isOutside)
- ReleaseCapture();
-
- if (dat->exStyle & CLS_EX_TRACKSELECT) {
- pcli->pfnInvalidateItem(hwnd, dat, iOldHotTrack);
- pcli->pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
- }
-
- pcli->pfnHideInfoTip(hwnd, dat);
- }
-
- KillTimer(hwnd, TIMERID_INFOTIP);
-
- if (wParam == 0 && dat->hInfoTipItem == NULL) {
- dat->ptInfoTip.x = (short)LOWORD(lParam);
- dat->ptInfoTip.y = (short)HIWORD(lParam);
- CLUI_SafeSetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL);
- }
- return 0;
- }
-
- if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP))
- if (abs((short)LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG) || abs((short)HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG))
- dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE;
-
- if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
- RECT clRect;
- GetClientRect(hwnd, &clRect);
-
- POINT pt = UNPACK_POINT(lParam);
- HCURSOR hNewCursor = LoadCursor(NULL, IDC_NO);
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- if (dat->dragAutoScrolling) {
- KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
- dat->dragAutoScrolling = 0;
- }
- int target = GetDropTargetInformation(hwnd, dat, pt);
- if ((dat->dragStage & DRAGSTAGEF_OUTSIDE) && target != DROPTARGET_OUTSIDE) {
- ClcContact *contact;
- cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
-
- NMCLISTCONTROL nm;
- nm.hdr.code = CLN_DRAGSTOP;
- nm.hdr.hwndFrom = hwnd;
- nm.hdr.idFrom = GetDlgCtrlID(hwnd);
- nm.flags = 0;
- nm.hItem = ContactToItemHandle(contact, &nm.flags);
- SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
- dat->dragStage &= ~DRAGSTAGEF_OUTSIDE;
- }
-
- ClcContact *contSour, *contDest;
-
- switch (target) {
- case DROPTARGET_ONSELF:
- break;
-
- case DROPTARGET_ONCONTACT:
- cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
- if (contSour->isChat())
- break;
- if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
- if (!contSour->isSubcontact)
- hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); /// Add to meta
- else
- hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DROPMETA));
- }
- break;
-
- case DROPTARGET_ONMETACONTACT:
- cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
- cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
- if (contSour->isChat() || contDest->isChat())
- break;
- if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
- if (!contSour->isSubcontact)
- hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); /// Add to meta
- else if (contSour->subcontacts == contDest)
- hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DEFAULTSUB)); ///MakeDefault
- else
- hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP));
- }
- break;
-
- case DROPTARGET_ONSUBCONTACT:
- cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
- cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
- if (contSour->isChat() || contDest->isChat())
- break;
- if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
- if (!contSour->isSubcontact)
- hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); /// Add to meta
- else if (contDest->subcontacts == contSour->subcontacts)
- break;
- else
- hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP));
- }
- break;
-
- case DROPTARGET_ONGROUP:
- hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));
- break;
-
- case DROPTARGET_INSERTION:
- hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROP));
- break;
-
- case DROPTARGET_OUTSIDE:
- if (pt.x >= 0 && pt.x < clRect.right && ((pt.y < 0 && pt.y>-dat->dragAutoScrollHeight) || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) {
- if (!dat->dragAutoScrolling) {
- dat->dragAutoScrolling = (pt.y < 0) ? -1 : 1;
- CLUI_SafeSetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL);
- }
- SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0);
- }
-
- dat->dragStage |= DRAGSTAGEF_OUTSIDE;
- {
- ClcContact *contact;
- cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
-
- NMCLISTCONTROL nm;
- nm.hdr.code = CLN_DRAGGING;
- nm.hdr.hwndFrom = hwnd;
- nm.hdr.idFrom = GetDlgCtrlID(hwnd);
- nm.flags = 0;
- nm.hItem = ContactToItemHandle(contact, &nm.flags);
- nm.pt = pt;
- if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm))
- return 0;
- }
- break;
-
- default:
- ClcGroup *group = NULL;
- cliGetRowByIndex(dat, dat->iDragItem, NULL, &group);
- if (group && group->parent) {
- ClcContact *contSour;
- cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
- if (!contSour->isSubcontact)
- hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));
- }
- break;
- }
- SetCursor(hNewCursor);
- }
- return 0;
-}
-
-static LRESULT clcOnLButtonUp(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (clcExitDragToScroll())
- return 0;
-
- fMouseUpped = TRUE;
-
- if (hitcontact != NULL && dat->expandMeta) {
- BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT);
- CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, GetDoubleClickTime()*doubleClickExpand, NULL);
- }
- else if (dat->iHotTrack == -1 && dat->iDragItem == -1)
- ReleaseCapture();
-
- if (dat->iDragItem == -1)
- return 0;
-
- SetCursor((HCURSOR)GetClassLongPtr(hwnd, GCLP_HCURSOR));
- if (dat->exStyle & CLS_EX_TRACKSELECT) {
- DWORD flags;
- dat->iHotTrack = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flags);
- if (dat->iHotTrack == -1)
- ReleaseCapture();
- }
- else if (hitcontact == NULL)
- ReleaseCapture();
- KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
- if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME))
- CLUI_SafeSetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL);
- else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
- TCHAR Wording[500];
- ClcContact *contDest, *contSour;
- POINT pt = UNPACK_POINT(lParam);
- int target = GetDropTargetInformation(hwnd, dat, pt);
- switch (target) {
- case DROPTARGET_ONSELF:
- break;
-
- case DROPTARGET_ONCONTACT:
- cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
- cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
- if (contSour->isChat() || contDest->isChat())
- break;
- if (contSour->type == CLCIT_CONTACT) {
- MCONTACT hcontact = contSour->hContact;
- if (mir_strcmp(contSour->proto, META_PROTO)) {
- if (!contSour->isSubcontact) {
- MCONTACT hDest = contDest->hContact;
- mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it?"), contDest->szText, contSour->szText);
- int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact"), MB_OKCANCEL | MB_ICONQUESTION);
- if (res == 1) {
- MCONTACT handle = CallService(MS_MC_CONVERTTOMETA, hDest, 0);
- if (!handle)
- return 0;
-
- CallService(MS_MC_ADDTOMETA, hcontact, handle);
- }
- }
- else {
- hcontact = contSour->hContact;
- MCONTACT hfrom = contSour->subcontacts->hContact;
- MCONTACT hdest = contDest->hContact;
- mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it (remove it from '%s')?"), contDest->szText, contSour->szText, contSour->subcontacts->szText);
- int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
- if (res == 1) {
- MCONTACT handle = (MCONTACT)CallService(MS_MC_CONVERTTOMETA, (WPARAM)hdest, 0);
- if (!handle)
- return 0;
-
- CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
- CallService(MS_MC_ADDTOMETA, hcontact, handle);
- }
- }
- }
- }
- break;
-
- case DROPTARGET_ONMETACONTACT:
- cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
- cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
- if (contSour->isChat() || contDest->isChat())
- break;
- if (contSour->type == CLCIT_CONTACT) {
- if (!strcmp(contSour->proto, META_PROTO))
- break;
- if (!contSour->isSubcontact) {
- MCONTACT hcontact = contSour->hContact;
- MCONTACT handle = contDest->hContact;
- mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->szText);
- int res = MessageBox(hwnd, Wording, TranslateT("Adding contact to metacontact"), MB_OKCANCEL | MB_ICONQUESTION);
- if (res == 1) {
- if (!handle)
- return 0;
- CallService(MS_MC_ADDTOMETA, hcontact, handle);
- }
- }
- else if (contSour->subcontacts == contDest) {
- MCONTACT hsour = contSour->hContact;
- mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be default?"), contSour->szText);
- int res = MessageBox(hwnd, Wording, TranslateT("Set default contact"), MB_OKCANCEL | MB_ICONQUESTION);
- if (res == 1)
- db_mc_setDefault(contDest->hContact, hsour, true);
- }
- else {
- MCONTACT hcontact = contSour->hContact;
- MCONTACT hfrom = contSour->subcontacts->hContact;
- MCONTACT handle = contDest->hContact;
- mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->szText);
- int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
- if (res == 1) {
- if (!handle)
- return 0;
-
- CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
- CallService(MS_MC_ADDTOMETA, hcontact, handle);
- }
- }
- }
- break;
-
- case DROPTARGET_ONSUBCONTACT:
- cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
- cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
- if (contSour->isChat() || contDest->isChat())
- break;
- if (contSour->type == CLCIT_CONTACT) {
- if (!strcmp(contSour->proto, META_PROTO))
- break;
- if (!contSour->isSubcontact) {
- MCONTACT hcontact = contSour->hContact;
- MCONTACT handle = contDest->subcontacts->hContact;
- mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->subcontacts->szText);
- int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
- if (res == 1) {
- if (!handle)
- return 0;
-
- CallService(MS_MC_ADDTOMETA, hcontact, handle);
- }
- }
- else if (contSour->subcontacts != contDest->subcontacts) {
- MCONTACT hcontact = contSour->hContact;
- MCONTACT hfrom = contSour->subcontacts->hContact;
- MCONTACT handle = contDest->subcontacts->hContact;
- mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->subcontacts->szText);
- int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
- if (res == 1) {
- if (!handle)
- return 0;
-
- CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
- CallService(MS_MC_ADDTOMETA, hcontact, handle);
- }
- }
- }
- break;
-
- case DROPTARGET_ONGROUP:
- corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- break;
-
- case DROPTARGET_INSERTION:
- {
- ClcContact *contact, *destcontact;
- ClcGroup *group, *destgroup;
- BOOL NeedRename = FALSE;
- TCHAR newName[128] = { 0 };
- pcli->pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group);
- int i = pcli->pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup);
- if (i != -1 && group->groupId != destgroup->groupId) {
- TCHAR *groupName = mir_tstrdup(pcli->pfnGetGroupName(contact->groupId, 0));
- TCHAR *shortGroup = NULL;
- TCHAR *sourceGrName = mir_tstrdup(pcli->pfnGetGroupName(destgroup->groupId, 0));
- if (groupName) {
- int len = (int)_tcslen(groupName);
- do { len--; }
- while (len >= 0 && groupName[len] != '\\');
- if (len >= 0) shortGroup = groupName + len + 1;
- else shortGroup = groupName;
- }
- if (shortGroup) {
- NeedRename = TRUE;
- if (sourceGrName)
- mir_sntprintf(newName, SIZEOF(newName), _T("%s\\%s"), sourceGrName, shortGroup);
- else
- mir_sntprintf(newName, SIZEOF(newName), _T("%s"), shortGroup);
- }
- mir_free(groupName);
- mir_free(sourceGrName);
- }
- int newIndex = CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, (destcontact && i != -1) ? destcontact->groupId : 0);
- newIndex = newIndex ? newIndex : contact->groupId;
- if (NeedRename) pcli->pfnRenameGroup(newIndex, newName);
- }
- break;
-
- case DROPTARGET_OUTSIDE:
- corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- break;
-
- default:
- corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- break;
- }
- }
-
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- dat->iDragItem = -1;
- dat->iInsertionMark = -1;
- return 0;
-}
-
-static LRESULT clcOnLButtonDblClick(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- KillTimer(hwnd, TIMERID_SUBEXPAND);
- hitcontact = NULL;
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-}
-
-static LRESULT clcOnDestroy(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- for (int i = 0; i <= FONTID_MODERN_MAX; i++) {
- if (dat->fontModernInfo[i].hFont)
- DeleteObject(dat->fontModernInfo[i].hFont);
- dat->fontModernInfo[i].hFont = NULL;
- }
- if (dat->hMenuBackground) {
- DeleteObject(dat->hMenuBackground);
- dat->hMenuBackground = NULL;
- }
- if (dat->hBmpBackground) {
- DeleteObject(dat->hBmpBackground);
- dat->hBmpBackground = NULL;
- }
-
- ImageArray_Clear(&dat->avatar_cache);
- DeleteDC(dat->avatar_cache.hdc);
- ImageArray_Free(&dat->avatar_cache, FALSE);
- if (dat->himlHighlight)
- ImageList_Destroy(dat->himlHighlight);
-
- RowHeights_Free(dat);
- corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- xpt_FreeThemeForWindow(hwnd);
- return 0;
-}
-
-static LRESULT clcOnIntmGroupChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- WORD iExtraImage[EXTRA_ICON_COUNT];
- BYTE flags = 0;
-
- ClcContact *contact;
- if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL))
- memset(iExtraImage, 0xFF, sizeof(iExtraImage));
- else {
- memcpy(iExtraImage, contact->iExtraImage, sizeof(iExtraImage));
- flags = contact->flags;
- }
- pcli->pfnDeleteItemFromTree(hwnd, wParam);
- if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !db_get_b(wParam, "CList", "Hidden", 0)) {
- NMCLISTCONTROL nm;
- pcli->pfnAddContactToTree(hwnd, dat, wParam, 1, 1);
- if (pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) {
- memcpy(contact->iExtraImage, iExtraImage, sizeof(iExtraImage));
- if (flags & CONTACTF_CHECKED)
- contact->flags |= CONTACTF_CHECKED;
- }
- nm.hdr.code = CLN_CONTACTMOVED;
- nm.hdr.hwndFrom = hwnd;
- nm.hdr.idFrom = GetDlgCtrlID(hwnd);
- nm.flags = 0;
- nm.hItem = (HANDLE)wParam;
- SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
- dat->needsResort = 1;
- }
- SetTimer(hwnd, TIMERID_REBUILDAFTER, 1, NULL);
- return 0;
-}
-
-static LRESULT clcOnIntmIconChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- ClcContact *contact = NULL;
- ClcGroup *group = NULL;
- int recalcScrollBar = 0, shouldShow;
- BOOL needRepaint = FALSE;
- RECT iconRect = { 0 };
- int contacticon = corecli.pfnGetContactIcon(wParam);
- MCONTACT hSelItem = NULL;
- ClcContact *selcontact = NULL;
-
- char *szProto = GetContactProto(wParam);
- WORD status = (szProto == NULL) ? ID_STATUS_OFFLINE : GetContactCachedStatus(wParam);
- BOOL image_is_special = (LOWORD(contacticon) != (LOWORD(lParam))); //check only base icons
-
- int nHiddenStatus = CLVM_GetContactHiddenStatus(wParam, szProto, dat);
-
- DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
- bool isVisiblebyFilter = (((style & CLS_SHOWHIDDEN) && nHiddenStatus != -1) || !nHiddenStatus);
- bool ifVisibleByClui = !pcli->pfnIsHiddenMode(dat, status);
- bool isVisible = g_CluiData.bFilterEffective&CLVM_FILTER_STATUS ? TRUE : ifVisibleByClui;
- bool isIconChanged = cli_GetContactIcon(wParam) != LOWORD(lParam);
-
- shouldShow = isVisiblebyFilter && (isVisible || isIconChanged);
-
- // XXX CLVM changed - this means an offline msg is flashing, so the contact should be shown
-
- if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, &group, NULL)) {
- if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) {
- if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
- hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
- pcli->pfnAddContactToTree(hwnd, dat, wParam, (style & CLS_CONTACTLIST) == 0, 0);
- recalcScrollBar = 1;
- needRepaint = TRUE;
- pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL);
- if (contact) {
- contact->iImage = lParam;
- contact->image_is_special = image_is_special;
- pcli->pfnNotifyNewContact(hwnd, wParam);
- dat->needsResort = 1;
- }
- }
- }
- else {
- //item in list already
- if (contact->iImage == lParam)
- return 0;
-
- if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline) && clcItemNotHiddenOffline(dat, group, contact))
- shouldShow = TRUE;
-
- if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && ((style & CLS_HIDEOFFLINE) || group->hideOffline || g_CluiData.bFilterEffective)) { // CLVM changed
- if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
- hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
- pcli->pfnRemoveItemFromGroup(hwnd, group, contact, (style & CLS_CONTACTLIST) == 0);
- needRepaint = TRUE;
- recalcScrollBar = 1;
- dat->needsResort = 1;
- }
- else if (contact) {
- contact->iImage = lParam;
- if (!pcli->pfnIsHiddenMode(dat, status))
- contact->flags |= CONTACTF_ONLINE;
- else
- contact->flags &= ~CONTACTF_ONLINE;
- contact->image_is_special = image_is_special;
- if (!image_is_special) { //Only if it is status changing
- dat->needsResort = 1;
- needRepaint = TRUE;
- }
- else if (dat->m_paintCouter == contact->lastPaintCounter) //if contacts is visible
- needRepaint = TRUE;
- }
- }
-
- if (hSelItem) {
- ClcGroup *selgroup;
- if (pcli->pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
- dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact));
- else
- dat->selection = -1;
- }
-
- if (dat->needsResort) {
- TRACE("Sort required\n");
- clcSetDelayTimer(TIMERID_DELAYEDRESORTCLC, hwnd);
- }
- else if (needRepaint) {
- if (contact && contact->pos_icon.bottom != 0 && contact->pos_icon.right != 0)
- CLUI__cliInvalidateRect(hwnd, &(contact->pos_icon), FALSE);
- else
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- //try only needed rectangle
- }
-
- return 0;
-}
-
-static LRESULT clcOnIntmAvatarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- ClcContact *contact;
- if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
- Cache_GetAvatar(dat, contact);
- else if (dat->use_avatar_service && !wParam)
- UpdateAllAvatars(dat);
-
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- return 0;
-}
-
-static LRESULT clcOnIntmTimeZoneChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- ClcContact *contact;
- if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- if (contact) {
- Cache_GetTimezone(dat, contact->hContact);
- Cache_GetText(dat, contact, 1);
- cliRecalcScrollBar(hwnd, dat);
- }
- return 0;
-}
-
-static LRESULT clcOnIntmNameChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- pcli->pfnInvalidateDisplayNameCacheEntry(wParam);
-
- ClcContact *contact;
- if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
- return ret;
-
- lstrcpyn(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), SIZEOF(contact->szText));
- if (contact) {
- Cache_GetText(dat, contact, 1);
- cliRecalcScrollBar(hwnd, dat);
- }
- dat->needsResort = 1;
- pcli->pfnSortContacts();
-
- return ret;
-}
-
-static LRESULT clcOnIntmApparentModeChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-}
-
-static LRESULT clcOnIntmStatusMsgChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM hContact, LPARAM lParam)
-{
- if (hContact == NULL || IsHContactInfo(hContact) || IsHContactGroup(hContact))
- return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
-
- ClcContact *contact;
- if (!FindItem(hwnd, dat, hContact, &contact, NULL, NULL, FALSE))
- return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
-
- if (contact) {
- Cache_GetText(dat, contact, 1);
- cliRecalcScrollBar(hwnd, dat);
- PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
- }
- return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
-}
-
-static LRESULT clcOnIntmNotOnListChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING*)lParam;
-
- ClcContact *contact;
- if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE))
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- if (contact->type != CLCIT_CONTACT)
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-
- if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0)
- contact->flags &= ~CONTACTF_NOTONLIST;
- else
- contact->flags |= CONTACTF_NOTONLIST;
-
- CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
-}
-
-static LRESULT clcOnIntmScrollBarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
- if (dat->noVScrollbar)
- ShowScrollBar(hwnd, SB_VERT, FALSE);
- else
- pcli->pfnRecalcScrollBar(hwnd, dat);
- }
- return 0;
-}
-
-static LRESULT clcOnIntmStatusChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- if (wParam != 0) {
- ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(wParam);
- if (pdnce && pdnce->m_cache_cszProto) {
- pdnce->m_cache_nStatus = GetStatusForContact(pdnce->hContact, pdnce->m_cache_cszProto);
- if (!dat->force_in_dialog && (dat->second_line_show || dat->third_line_show))
- gtaRenewText(pdnce->hContact);
- SendMessage(hwnd, INTM_ICONCHANGED, wParam, corecli.pfnGetContactIcon(wParam));
-
- ClcContact *contact;
- if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE)) {
- if (contact && contact->type == CLCIT_CONTACT) {
- if (!contact->image_is_special && pdnce___GetStatus(pdnce) > ID_STATUS_OFFLINE)
- contact->iImage = corecli.pfnGetContactIcon(wParam);
- if (contact->isSubcontact && contact->subcontacts && contact->subcontacts->type == CLCIT_CONTACT)
- pcli->pfnClcBroadcast(INTM_STATUSCHANGED, contact->subcontacts->hContact, 0); //forward status changing to host meta contact
- }
- }
- }
- }
-
- if (db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOOFLINETOROOT_DEFAULT))
- pcli->pfnInitAutoRebuild(hwnd);
- else {
- pcli->pfnSortContacts();
- PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
- }
- return ret;
-}
-
-static LRESULT clcOnIntmReloadOptions(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- pcli->pfnLoadClcOptions(hwnd, dat, FALSE);
- LoadCLCOptions(hwnd, dat, FALSE);
- pcli->pfnSaveStateAndRebuildList(hwnd, dat);
- pcli->pfnSortCLC(hwnd, dat, 1);
- if (IsWindowVisible(hwnd))
- pcli->pfnInvalidateRect(GetParent(hwnd), NULL, FALSE);
- return TRUE;
-}
-
-HRESULT ClcLoadModule()
-{
- g_himlCListClc = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0);
-
- HookEvent(ME_MC_SUBCONTACTSCHANGED, clcMetacontactChanged);
- HookEvent(ME_MC_ENABLED, clcMetaModeChanged);
- HookEvent(ME_DB_CONTACT_SETTINGCHANGED, clcHookSettingChanged);
- HookEvent(ME_OPT_INITIALISE, ClcOptInit);
- hAckHook = (HANDLE)HookEvent(ME_PROTO_ACK, clcHookProtoAck);
- HookEvent(ME_SYSTEM_MODULESLOADED, clcHookModulesLoaded);
- HookEvent(ME_DB_EVENT_ADDED, clcHookDbEventAdded);
- return S_OK;
-}
-
-int ClcUnloadModule()
-{
- if (g_CluiData.bOldUseGroups != (BYTE)-1)
- db_set_b(NULL, "CList", "UseGroups", (BYTE)g_CluiData.bOldUseGroups);
- if (g_CluiData.boldHideOffline != (BYTE)-1)
- db_set_b(NULL, "CList", "HideOffline", (BYTE)g_CluiData.boldHideOffline);
-
- return 0;
-}
-
-int ClcDoProtoAck(MCONTACT wParam, ACKDATA * ack)
-{
- if (MirandaExiting()) return 0;
- if (ack->type == ACKTYPE_STATUS) {
- if (ack->result == ACKRESULT_SUCCESS) {
- for (int i = 0; i < pcli->hClcProtoCount; i++) {
- if (!lstrcmpA(pcli->clcProto[i].szProto, ack->szModule)) {
- pcli->clcProto[i].dwStatus = (WORD)ack->lParam;
- if (pcli->clcProto[i].dwStatus >= ID_STATUS_OFFLINE)
- pcli->pfnTrayIconUpdateBase(pcli->clcProto[i].szProto);
- return 0;
- }
- }
- }
- }
- else if (ack->type == ACKTYPE_AWAYMSG) {
- if (ack->result == ACKRESULT_SUCCESS && ack->lParam) {
- //Do not change DB if it is IRC protocol
- if (ack->szModule != NULL)
- if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0)
- return 0;
-
- db_set_ws(ack->hContact, "CList", "StatusMsg", (const TCHAR *)ack->lParam);
- gtaRenewText(ack->hContact);
- }
- else {
- //db_unset(ack->hContact,"CList","StatusMsg");
- //char a = '\0';
- //Do not change DB if it is IRC protocol
- if (ack->szModule != NULL)
- if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0)
- return 0;
-
- if (ack->hContact) {
- char *val = db_get_sa(ack->hContact, "CList", "StatusMsg");
- if (val) {
- if (!mir_bool_strcmpi(val, ""))
- db_set_s(ack->hContact, "CList", "StatusMsg", "");
- else
- gtaRenewText(ack->hContact);
- mir_free(val);
- }
- }
- //pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED,(WPARAM)ack->hContact,&a);
- }
- }
- else if (ack->type == ACKTYPE_AVATAR) {
- if (ack->result == ACKRESULT_SUCCESS) {
- PROTO_AVATAR_INFORMATIONT *pai = (PROTO_AVATAR_INFORMATIONT*)ack->hProcess;
- if (pai != NULL && pai->hContact != NULL)
- pcli->pfnClcBroadcast(INTM_AVATARCHANGED, (WPARAM)pai->hContact, 0);
- }
- }
- else if (ack->type == ACKTYPE_EMAIL) {
- CLUIUnreadEmailCountChanged(0, 0);
- }
- return 0;
-}
-
-int ClcGetShortData(ClcData* pData, struct SHORTDATA *pShortData)
-{
- if (!pData || !pShortData)
- return -1;
-
- pShortData->hWnd = pData->hWnd;
- pShortData->text_replace_smileys = pData->text_replace_smileys;
- pShortData->text_smiley_height = pData->text_smiley_height;
- pShortData->text_use_protocol_smileys = pData->text_use_protocol_smileys;
- pShortData->contact_time_show_only_if_different = pData->contact_time_show_only_if_different;
- // Second line
- pShortData->second_line_show = pData->second_line_show;
- pShortData->second_line_draw_smileys = pData->second_line_draw_smileys;
- pShortData->second_line_type = pData->second_line_type;
-
- _tcsncpy(pShortData->second_line_text, pData->second_line_text, TEXT_TEXT_MAX_LENGTH);
-
- pShortData->second_line_xstatus_has_priority = pData->second_line_xstatus_has_priority;
- pShortData->second_line_show_status_if_no_away = pData->second_line_show_status_if_no_away;
- pShortData->second_line_show_listening_if_no_away = pData->second_line_show_listening_if_no_away;
- pShortData->second_line_use_name_and_message_for_xstatus = pData->second_line_use_name_and_message_for_xstatus;
-
- pShortData->third_line_show = pData->third_line_show;
- pShortData->third_line_draw_smileys = pData->third_line_draw_smileys;
- pShortData->third_line_type = pData->third_line_type;
-
- _tcsncpy(pShortData->third_line_text, pData->third_line_text, TEXT_TEXT_MAX_LENGTH);
-
- pShortData->third_line_xstatus_has_priority = pData->third_line_xstatus_has_priority;
- pShortData->third_line_show_status_if_no_away = pData->third_line_show_status_if_no_away;
- pShortData->third_line_show_listening_if_no_away = pData->third_line_show_listening_if_no_away;
- pShortData->third_line_use_name_and_message_for_xstatus = pData->third_line_use_name_and_message_for_xstatus;
- return 0;
-}
-
-int ClcEnterDragToScroll(HWND hwnd, int Y)
-{
- if (IsDragToScrollMode)
- return 0;
-
- ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0);
- if (!dat)
- return 0;
-
- StartDragPos = Y;
- StartScrollPos = dat->yScroll;
- IsDragToScrollMode = 1;
- SetCapture(hwnd);
- return 1;
-}
-
-
-/*
-* Contact list control window procedure
-*/
-LRESULT CALLBACK cli_ContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-
-#define CASE_MSG_RET(msg, handler) case msg: return handler(dat, hwnd, msg, wParam, lParam);
-
- ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0);
-
- if (msg >= CLM_FIRST && msg < CLM_LAST)
- return cli_ProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
-
- switch (msg) {
- CASE_MSG_RET(INTM_GROUPCHANGED, clcOnIntmGroupChanged);
- CASE_MSG_RET(INTM_ICONCHANGED, clcOnIntmIconChanged);
- CASE_MSG_RET(INTM_AVATARCHANGED, clcOnIntmAvatarChanged);
- CASE_MSG_RET(INTM_TIMEZONECHANGED, clcOnIntmTimeZoneChanged);
- CASE_MSG_RET(INTM_NAMECHANGED, clcOnIntmNameChanged);
- CASE_MSG_RET(INTM_APPARENTMODECHANGED, clcOnIntmApparentModeChanged);
- CASE_MSG_RET(INTM_STATUSMSGCHANGED, clcOnIntmStatusMsgChanged);
- CASE_MSG_RET(INTM_NOTONLISTCHANGED, clcOnIntmNotOnListChanged);
- CASE_MSG_RET(INTM_SCROLLBARCHANGED, clcOnIntmScrollBarChanged);
- CASE_MSG_RET(INTM_STATUSCHANGED, clcOnIntmStatusChanged);
- CASE_MSG_RET(INTM_RELOADOPTIONS, clcOnIntmReloadOptions);
-
- CASE_MSG_RET(WM_CREATE, clcOnCreate);
- CASE_MSG_RET(WM_NCHITTEST, clcOnHitTest);
- CASE_MSG_RET(WM_COMMAND, clcOnCommand);
- CASE_MSG_RET(WM_SIZE, clcOnSize);
- CASE_MSG_RET(WM_CHAR, clcOnChar);
- CASE_MSG_RET(WM_PAINT, clcOnPaint);
- CASE_MSG_RET(WM_ERASEBKGND, clcOnEraseBkGround);
- CASE_MSG_RET(WM_KEYDOWN, clcOnKeyDown);
- CASE_MSG_RET(WM_TIMER, clcOnTimer);
- CASE_MSG_RET(WM_ACTIVATE, clcOnActivate);
- CASE_MSG_RET(WM_SETCURSOR, clcOnSetCursor);
- CASE_MSG_RET(WM_LBUTTONDOWN, clcOnLButtonDown);
- CASE_MSG_RET(WM_CAPTURECHANGED, clcOnCaptureChanged);
- CASE_MSG_RET(WM_MOUSEMOVE, clcOnMouseMove);
- CASE_MSG_RET(WM_LBUTTONUP, clcOnLButtonUp);
- CASE_MSG_RET(WM_LBUTTONDBLCLK, clcOnLButtonDblClick);
- CASE_MSG_RET(WM_DESTROY, clcOnDestroy);
-
- default:
- return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
- }
- return TRUE;
-}
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
+Copyright (c) 2000-08 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/************************************************************************/
+/* Module responsible for working with contact list control */
+/************************************************************************/
+
+#include "hdr/modern_commonheaders.h"
+#include "m_skin.h"
+#include "hdr/modern_commonprototypes.h"
+
+#include "hdr/modern_clc.h"
+#include "hdr/modern_clist.h"
+#include "hdr/modern_clcpaint.h"
+
+#include "m_modernopt.h"
+
+int ModernOptInit(WPARAM wParam, LPARAM lParam);
+int ModernSkinOptInit(WPARAM wParam, LPARAM lParam);
+
+/*
+* Private module variables
+*/
+static HANDLE hShowInfoTipEvent;
+static POINT HitPoint;
+static BOOL fMouseUpped;
+static BYTE IsDragToScrollMode = 0;
+static int StartDragPos = 0;
+static int StartScrollPos = 0;
+HANDLE hAckHook = NULL;
+HANDLE hAvatarChanged = NULL;
+static BOOL g_bSortTimerIsSet = FALSE;
+static ClcContact *hitcontact = NULL;
+HANDLE hSkinFolder;
+TCHAR SkinsFolder[MAX_PATH];
+
+static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam);
+static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam);
+static int clcHookBkgndConfigChanged(WPARAM wParam, LPARAM lParam);
+static int clcProceedDragToScroll(HWND hwnd, int Y);
+static int clcExitDragToScroll();
+
+
+int ReloadSkinFolder(WPARAM wParam, LPARAM lParam)
+{
+ FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER));
+ return 0;
+}
+
+static int clcHookModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ if (MirandaExiting())
+ return 0;
+
+ HookEvent(ME_MODERNOPT_INITIALIZE, ModernOptInit);
+ HookEvent(ME_MODERNOPT_INITIALIZE, ModernSkinOptInit);
+
+ HookEvent(ME_FOLDERS_PATH_CHANGED, ReloadSkinFolder);
+ hSkinFolder = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("Modern contact list"), MIRANDA_PATHT _T("\\") _T(DEFAULT_SKIN_FOLDER));
+ FoldersGetCustomPathT(hSkinFolder, SkinsFolder, SIZEOF(SkinsFolder), _T(DEFAULT_SKIN_FOLDER));
+
+ // Get icons
+ TCHAR szMyPath[MAX_PATH];
+ GetModuleFileName(g_hInst, szMyPath, SIZEOF(szMyPath));
+
+ SKINICONDESC sid = { sizeof(sid) };
+ sid.cx = sid.cy = 16;
+ sid.ptszDefaultFile = szMyPath;
+ sid.flags = SIDF_PATH_TCHAR;
+
+ sid.pszSection = LPGEN("Contact list");
+ sid.pszDescription = LPGEN("Listening to");
+ sid.pszName = "LISTENING_TO_ICON";
+ sid.iDefaultIndex = -IDI_LISTENING_TO;
+ Skin_AddIcon(&sid);
+
+ sid.pszSection = LPGEN("Contact list") "/" LPGEN("Avatar overlay");
+ for (int i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
+ sid.pszDescription = g_pAvatarOverlayIcons[i].description;
+ sid.pszName = g_pAvatarOverlayIcons[i].name;
+ sid.iDefaultIndex = -g_pAvatarOverlayIcons[i].id;
+ Skin_AddIcon(&sid);
+ }
+
+ sid.pszSection = LPGEN("Contact list") "/" LPGEN("Status overlay");
+ for (int i = 0; i < SIZEOF(g_pStatusOverlayIcons); i++) {
+ sid.pszDescription = g_pStatusOverlayIcons[i].description;
+ sid.pszName = g_pStatusOverlayIcons[i].name;
+ sid.iDefaultIndex = -g_pStatusOverlayIcons[i].id;
+ Skin_AddIcon(&sid);
+ }
+
+ clcHookIconsChanged(0, 0);
+
+ HookEvent(ME_SKIN2_ICONSCHANGED, clcHookIconsChanged);
+
+ // Register smiley category
+ if (ServiceExists(MS_SMILEYADD_REGISTERCATEGORY)) {
+ SMADD_REGCAT rc;
+ rc.cbSize = sizeof(rc);
+ rc.name = "clist";
+ rc.dispname = Translate("Contact list smileys");
+
+ CallService(MS_SMILEYADD_REGISTERCATEGORY, 0, (LPARAM)&rc);
+
+ HookEvent(ME_SMILEYADD_OPTIONSCHANGED, clcHookSmileyAddOptionsChanged);
+ }
+
+ CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("List background")"/CLC"), 0);
+ CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Menu background")"/Menu"), 0);
+ CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Status bar background")"/StatusBar"), 0);
+ CallService(MS_BACKGROUNDCONFIG_REGISTER, (WPARAM)(LPGEN("Frames title bar background")"/FrameTitleBar"), 0);
+
+ HookEvent(ME_BACKGROUNDCONFIG_CHANGED, clcHookBkgndConfigChanged);
+ HookEvent(ME_BACKGROUNDCONFIG_CHANGED, BgStatusBarChange);
+ HookEvent(ME_BACKGROUNDCONFIG_CHANGED, OnFrameTitleBarBackgroundChange);
+ HookEvent(ME_COLOUR_RELOAD, OnFrameTitleBarBackgroundChange);
+
+ AniAva_UpdateOptions();
+ return 0;
+}
+
+static int clcHookSmileyAddOptionsChanged(WPARAM wParam, LPARAM lParam)
+{
+ if (MirandaExiting()) return 0;
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0);
+ return 0;
+}
+
+static int clcHookProtoAck(WPARAM wParam, LPARAM lParam)
+{
+ return ClcDoProtoAck(wParam, (ACKDATA*)lParam);
+}
+
+static int clcHookIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ if (MirandaExiting()) return 0;
+ for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
+ g_pAvatarOverlayIcons[i].listID = -1;
+ g_pStatusOverlayIcons[i].listID = -1;
+ }
+
+ if (hAvatarOverlays)
+ ImageList_Destroy(hAvatarOverlays);
+ hAvatarOverlays = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, SIZEOF(g_pAvatarOverlayIcons) * 2, 1);
+
+ for (i = 0; i < SIZEOF(g_pAvatarOverlayIcons); i++) {
+ HICON hIcon = Skin_GetIcon(g_pAvatarOverlayIcons[i].name);
+ g_pAvatarOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon);
+ Skin_ReleaseIcon(g_pAvatarOverlayIcons[i].name);
+
+ hIcon = Skin_GetIcon(g_pStatusOverlayIcons[i].name);
+ g_pStatusOverlayIcons[i].listID = ImageList_AddIcon(hAvatarOverlays, hIcon);
+ Skin_ReleaseIcon(g_pStatusOverlayIcons[i].name);
+ }
+
+ g_hListeningToIcon = Skin_GetIcon("LISTENING_TO_ICON");
+
+ pcli->pfnClcBroadcast(INTM_INVALIDATE, 0, 0);
+ AniAva_UpdateOptions();
+ return 0;
+}
+
+static int clcMetaModeChanged(WPARAM, LPARAM)
+{
+ pcli->pfnClcBroadcast(INTM_RELOADOPTIONS, 0, 0);
+ return 0;
+}
+
+static int clcMetacontactChanged(WPARAM hMeta, LPARAM)
+{
+ pcli->pfnClcBroadcast(INTM_NAMEORDERCHANGED, 0, 0);
+ return 0;
+}
+
+static int clcHookSettingChanged(WPARAM hContact, LPARAM lParam)
+{
+ if (MirandaExiting())
+ return 0;
+
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam;
+ if (hContact == NULL) {
+ if (!mir_strcmp(cws->szModule, "CListGroups"))
+ pcli->pfnClcBroadcast(INTM_GROUPSCHANGED, hContact, lParam);
+ else if (!strcmp(cws->szSetting, "XStatusId") || !strcmp(cws->szSetting, "XStatusName"))
+ cliCluiProtocolStatusChanged(0, cws->szModule);
+ }
+ else // hContact != NULL
+ {
+ if (!strcmp(cws->szSetting, "TickTS"))
+ pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0);
+ else if (!strcmp(cws->szModule, "UserInfo")) {
+ if (!strcmp(cws->szSetting, "Timezone"))
+ pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0);
+ }
+ else if (!strcmp(cws->szModule, "CList")) {
+ if (!strcmp(cws->szSetting, "StatusMsg"))
+ pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
+
+ }
+ else if (!strcmp(cws->szModule, "ContactPhoto")) {
+ if (!strcmp(cws->szSetting, "File"))
+ pcli->pfnClcBroadcast(INTM_AVATARCHANGED, hContact, 0);
+ }
+ else {
+ if ((!strcmp(cws->szSetting, "XStatusName") || !strcmp(cws->szSetting, "XStatusMsg")))
+ pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
+ else if (!strcmp(cws->szSetting, "XStatusId"))
+ pcli->pfnClcBroadcast(INTM_STATUSCHANGED, hContact, 0);
+ else if (!strcmp(cws->szSetting, "Timezone"))
+ pcli->pfnClcBroadcast(INTM_TIMEZONECHANGED, hContact, 0);
+ else if (!strcmp(cws->szSetting, "ListeningTo"))
+ pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED, hContact, 0);
+ else if (!strcmp(cws->szSetting, "Transport") || !strcmp(cws->szSetting, "IsTransported")) {
+ pcli->pfnInvalidateDisplayNameCacheEntry(hContact);
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, hContact, 0);
+ }
+ }
+ }
+ return 0;
+}
+
+static int clcHookDbEventAdded(WPARAM hContact, LPARAM lParam)
+{
+ g_CluiData.t_now = time(NULL);
+ if (hContact && lParam) {
+ DBEVENTINFO dbei = { sizeof(dbei) };
+ db_event_get((HANDLE)lParam, &dbei);
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
+ db_set_dw(hContact, "CList", "mf_lastmsg", dbei.timestamp);
+ ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
+ if (pdnce)
+ pdnce->dwLastMsgTime = dbei.timestamp;
+ }
+ }
+ return 0;
+}
+
+static int clcHookBkgndConfigChanged(WPARAM, LPARAM)
+{
+ pcli->pfnClcOptionsChanged();
+ return 0;
+}
+
+static int clcHookAvatarChanged(WPARAM wParam, LPARAM lParam)
+{
+ if (MirandaExiting()) return 0;
+ pcli->pfnClcBroadcast(INTM_AVATARCHANGED, wParam, lParam);
+ return 0;
+}
+
+static int clcExitDragToScroll()
+{
+ if (!IsDragToScrollMode) return 0;
+ IsDragToScrollMode = 0;
+ ReleaseCapture();
+ return 1;
+}
+
+static int clcProceedDragToScroll(HWND hwnd, int Y)
+{
+ int pos, dy;
+ if (!IsDragToScrollMode) return 0;
+ if (GetCapture() != hwnd) clcExitDragToScroll();
+ dy = StartDragPos - Y;
+ pos = StartScrollPos + dy;
+ if (pos < 0)
+ pos = 0;
+ SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, pos), 0);
+ return 1;
+}
+
+
+
+static int clcSearchNextContact(HWND hwnd, ClcData *dat, int index, const TCHAR *text, int prefixOk, BOOL fSearchUp)
+{
+ ClcGroup *group = &dat->list;
+ int testlen = lstrlen(text);
+ BOOL fReturnAsFound = FALSE;
+ int nLastFound = -1;
+ if (index == -1) fReturnAsFound = TRUE;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) {
+ bool found;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ found = true;
+ }
+ else if (dat->filterSearch) {
+ TCHAR *lowered_szText = CharLowerW(NEWTSTR_ALLOCA(group->cl.items[group->scanIndex]->szText));
+ TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch));
+ found = _tcsstr(lowered_szText, lowered_search) != NULL;
+ }
+ else {
+ found = ((prefixOk && CSTR_EQUAL == CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, text, -1, group->cl.items[group->scanIndex]->szText, testlen)) || (!prefixOk && !lstrcmpi(text, group->cl.items[group->scanIndex]->szText)));
+ }
+ if (found) {
+ ClcGroup *contactGroup = group;
+ int contactScanIndex = group->scanIndex;
+ int foundindex;
+ for (; group; group = group->parent)
+ pcli->pfnSetGroupExpand(hwnd, dat, group, 1);
+ foundindex = pcli->pfnGetRowsPriorTo(&dat->list, contactGroup, contactScanIndex);
+ if (fReturnAsFound)
+ return foundindex;
+ else if (nLastFound != -1 && fSearchUp && foundindex == index)
+ return nLastFound;
+ else if (!fSearchUp && foundindex == index)
+ fReturnAsFound = TRUE;
+ else
+ nLastFound = foundindex;
+ group = contactGroup;
+ group->scanIndex = contactScanIndex;
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (!(dat->exStyle & CLS_EX_QUICKSEARCHVISONLY) || group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ }
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+static BOOL clcItemNotHiddenOffline(ClcData *dat, ClcGroup* group, ClcContact *contact)
+{
+ if (g_CluiData.bFilterEffective) return FALSE;
+
+ if (!contact) return FALSE;
+ ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(contact->hContact);
+ if (!pdnce) return FALSE;
+ if (pdnce->m_cache_nNoHiddenOffline) return TRUE;
+
+ if (!group) return FALSE;
+ if (group->hideOffline) return FALSE;
+
+ if (CLCItems_IsShowOfflineGroup(group)) return TRUE;
+
+ return FALSE;
+}
+
+static LRESULT clcOnCreate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ dat = (ClcData*)mir_calloc(sizeof(ClcData));
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat);
+ dat->hCheckBoxTheme = xpt_AddThemeHandle(hwnd, L"BUTTON");
+ dat->m_paintCouter = 0;
+ dat->hWnd = hwnd;
+ dat->use_avatar_service = ServiceExists(MS_AV_GETAVATARBITMAP);
+ if (dat->use_avatar_service)
+ if (!hAvatarChanged)
+ hAvatarChanged = HookEvent(ME_AV_AVATARCHANGED, clcHookAvatarChanged);
+
+ ImageArray_Initialize(&dat->avatar_cache, FALSE, 20); //this array will be used to keep small avatars too
+
+ RowHeights_Initialize(dat);
+
+ dat->needsResort = 1;
+ dat->MetaIgnoreEmptyExtra = db_get_b(NULL, "CLC", "MetaIgnoreEmptyExtra", SETTING_METAIGNOREEMPTYEXTRA_DEFAULT);
+
+ dat->IsMetaContactsEnabled = (!(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_MANUALUPDATE)) && db_mc_isEnabled();
+
+ dat->expandMeta = db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT);
+ dat->useMetaIcon = db_get_b(NULL, "CLC", "Meta", SETTING_USEMETAICON_DEFAULT);
+ dat->drawOverlayedStatus = db_get_b(NULL, "CLC", "DrawOverlayedStatus", SETTING_DRAWOVERLAYEDSTATUS_DEFAULT);
+ g_CluiData.bSortByOrder[0] = db_get_b(NULL, "CList", "SortBy1", SETTING_SORTBY1_DEFAULT);
+ g_CluiData.bSortByOrder[1] = db_get_b(NULL, "CList", "SortBy2", SETTING_SORTBY2_DEFAULT);
+ g_CluiData.bSortByOrder[2] = db_get_b(NULL, "CList", "SortBy3", SETTING_SORTBY3_DEFAULT);
+ g_CluiData.fSortNoOfflineBottom = db_get_b(NULL, "CList", "NoOfflineBottom", SETTING_NOOFFLINEBOTTOM_DEFAULT);
+ dat->menuOwnerID = -1;
+ dat->menuOwnerType = CLCIT_INVALID;
+
+ corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ LoadCLCOptions(hwnd, dat, TRUE);
+ if (dat->contact_time_show || dat->second_line_type == TEXT_CONTACT_TIME || dat->third_line_type == TEXT_CONTACT_TIME)
+ CLUI_SafeSetTimer(hwnd, TIMERID_INVALIDATE, 5000, NULL);
+ else
+ KillTimer(hwnd, TIMERID_INVALIDATE);
+
+ TRACE("Create New ClistControl TO END\r\n");
+ return 0;
+}
+
+static LRESULT clcOnHitTest(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ return DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
+}
+
+static LRESULT clcOnCommand(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ClcContact *contact;
+ int hit = pcli->pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (hit == -1) return 0;
+ if (contact->type == CLCIT_CONTACT && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), contact->hContact)) return 0;
+
+ switch (LOWORD(wParam)) {
+ case POPUP_NEWSUBGROUP:
+ if (contact->type != CLCIT_GROUP)
+ return 0;
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | CLS_USEGROUPS);
+ CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0);
+ return 0;
+ case POPUP_RENAMEGROUP:
+ pcli->pfnBeginRenameSelection(hwnd, dat);
+ return 0;
+ case POPUP_DELETEGROUP:
+ if (contact->type == CLCIT_GROUP)
+ CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0);
+ return 0;
+ case POPUP_GROUPSHOWOFFLINE:
+ if (contact->type == CLCIT_GROUP) {
+ CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(CLCItems_IsShowOfflineGroup(contact->group) ? 0 : GROUPF_SHOWOFFLINE, GROUPF_SHOWOFFLINE));
+ pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0);
+ }
+ return 0;
+ case POPUP_GROUPHIDEOFFLINE:
+ if (contact->type == CLCIT_GROUP)
+ CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE));
+ return 0;
+ }
+
+ if (contact->type == CLCIT_GROUP)
+ if (CallService(MO_PROCESSCOMMANDBYMENUIDENT, LOWORD(wParam), (LPARAM)hwnd))
+ return 0;
+
+ return 0;
+}
+
+static LRESULT clcOnSize(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ pcli->pfnEndRename(hwnd, dat, 1);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cliRecalcScrollBar(hwnd, dat);
+ if (g_CluiData.fDisableSkinEngine || dat->force_in_dialog) {
+ RECT rc = { 0 };
+ GetClientRect(hwnd, &rc);
+ if (rc.right == 0)
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ rc.bottom = max(dat->row_min_heigh, 1);
+
+ HDC hdc = GetDC(hwnd);
+ int depth = GetDeviceCaps(hdc, BITSPIXEL);
+ if (depth < 16)
+ depth = 16;
+ HBITMAP hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL);
+ HBITMAP hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL);
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp);
+ HBRUSH hBrush = CreateSolidBrush((dat->useWindowsColours || dat->force_in_dialog) ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour);
+ FillRect(hdcMem, &rc, hBrush);
+ DeleteObject(hBrush);
+
+ HBITMAP hoMaskBmp = (HBITMAP)SelectObject(hdcMem, hBmpMask);
+ FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ SelectObject(hdcMem, hoMaskBmp);
+ SelectObject(hdcMem, hoBmp);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd, hdc);
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+ dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, ILC_COLOR32 | ILC_MASK, 1, 1);
+ ImageList_Add(dat->himlHighlight, hBmp, hBmpMask);
+ DeleteObject(hBmpMask);
+ DeleteObject(hBmp);
+ }
+ else if (dat->himlHighlight) {
+ ImageList_Destroy(dat->himlHighlight);
+ dat->himlHighlight = NULL;
+ }
+ return 0;
+}
+
+static LRESULT clcOnChar(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == 27 && dat->szQuickSearch[0] == '\0') { //escape and not quick search
+ // minimize clist
+ CListMod_HideWindow(pcli->hwndContactList, SW_HIDE);
+ }
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+}
+static LRESULT clcOnPaint(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (IsWindowVisible(hwnd)) {
+ if (!g_CluiData.fLayered || GetParent(hwnd) != pcli->hwndContactList) {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ g_clcPainter.cliPaintClc(hwnd, dat, hdc, &ps.rcPaint);
+ EndPaint(hwnd, &ps);
+ }
+ else CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, (WPARAM)hwnd, 0);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT clcOnEraseBkGround(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ return 1;
+}
+
+static LRESULT clcOnKeyDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == VK_CONTROL)
+ return 0;
+
+ pcli->pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+
+ if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU))
+ return 0;
+
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ int pageSize = (dat->rowHeight) ? clRect.bottom / dat->rowHeight : 0;
+ int selMoved = 0;
+ int changeGroupExpand = 0;
+
+ switch (wParam) {
+ case VK_DOWN:
+ case VK_UP:
+ if (dat->szQuickSearch[0] != '\0' && dat->selection != -1) { //get next contact
+ //get next contact
+ int index = clcSearchNextContact(hwnd, dat, dat->selection, dat->szQuickSearch, 1, (wParam == VK_UP));
+ if (index == -1) {
+ MessageBeep(MB_OK);
+ return 0;
+ }
+
+ dat->selection = index;
+ pcli->pfnInvalidateRect(hwnd, NULL, FALSE);
+ pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ return 0;
+ }
+
+ if (wParam == VK_DOWN) dat->selection++;
+ if (wParam == VK_UP) dat->selection--;
+ selMoved = 1;
+ break;
+
+ case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break;
+ case VK_NEXT: dat->selection += pageSize; selMoved = 1; break;
+ case VK_HOME: dat->selection = 0; selMoved = 1; break;
+ case VK_END: dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break;
+ case VK_LEFT: changeGroupExpand = 1; break;
+ case VK_RIGHT: changeGroupExpand = 2; break;
+ case VK_RETURN:
+ pcli->pfnDoSelectionDefaultAction(hwnd, dat);
+ SetCapture(hwnd);
+ dat->szQuickSearch[0] = 0;
+ if (dat->filterSearch)
+ pcli->pfnSaveStateAndRebuildList(hwnd, dat);
+ return 0;
+
+ case VK_F2: cliBeginRenameSelection(hwnd, dat); /*SetCapture(hwnd);*/ return 0;
+ case VK_DELETE: pcli->pfnDeleteFromContactList(hwnd, dat); SetCapture(hwnd); return 0;
+ case VK_ESCAPE:
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ dat->dragStage = 0;
+ ReleaseCapture();
+ }
+ return 0;
+
+ default:
+ NMKEY nmkey;
+ nmkey.hdr.hwndFrom = hwnd;
+ nmkey.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nmkey.hdr.code = NM_KEYDOWN;
+ nmkey.nVKey = wParam;
+ nmkey.uFlags = HIWORD(lParam);
+
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nmkey)) {
+ SetCapture(hwnd);
+ return 0;
+ }
+ }
+
+ if (changeGroupExpand) {
+ ClcContact *contact;
+ ClcGroup *group;
+ int hit = cliGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (hit == -1) {
+ SetCapture(hwnd);
+ return 0;
+ }
+
+ if (contact->type == CLCIT_CONTACT && (contact->isSubcontact || contact->SubAllocated > 0)) {
+ if (contact->isSubcontact && changeGroupExpand == 1) {
+ dat->selection -= contact->isSubcontact;
+ selMoved = 1;
+ }
+ else if (!contact->isSubcontact && contact->SubAllocated > 0) {
+ if (changeGroupExpand == 1 && !contact->SubExpanded) {
+ dat->selection = cliGetRowsPriorTo(&dat->list, group, -1);
+ selMoved = 1;
+ }
+ else if (changeGroupExpand == 1 && contact->SubExpanded) {
+ //Contract
+ ClcContact *ht = NULL;
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+ contact->SubExpanded = 0;
+ db_set_b(contact->hContact, "CList", "Expanded", 0);
+ ht = contact;
+ dat->needsResort = 1;
+ pcli->pfnSortCLC(hwnd, dat, 1);
+ cliRecalcScrollBar(hwnd, dat);
+ hitcontact = NULL;
+ }
+ else if (changeGroupExpand == 2 && contact->SubExpanded) {
+ dat->selection++;
+ selMoved = 1;
+ }
+ else if (changeGroupExpand == 2 && !contact->SubExpanded && dat->expandMeta) {
+ ClcContact *ht = NULL;
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+ contact->SubExpanded = 1;
+ db_set_b(contact->hContact, "CList", "Expanded", 1);
+ ht = contact;
+ dat->needsResort = 1;
+ pcli->pfnSortCLC(hwnd, dat, 1);
+ cliRecalcScrollBar(hwnd, dat);
+ if (ht) {
+ ClcContact *contact2;
+ ClcGroup *group2;
+ if (FindItem(hwnd, dat, contact->hContact, &contact2, &group2, NULL, FALSE)) {
+ int i = cliGetRowsPriorTo(&dat->list, group2, GetContactIndex(group2, contact2));
+ pcli->pfnEnsureVisible(hwnd, dat, i + contact->SubAllocated, 0);
+ }
+ }
+ hitcontact = NULL;
+ }
+ }
+ }
+ else {
+ if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) {
+ if (group == &dat->list) { SetCapture(hwnd); return 0; }
+ dat->selection = cliGetRowsPriorTo(&dat->list, group, -1);
+ selMoved = 1;
+ }
+ else {
+ if (contact->type == CLCIT_GROUP) {
+ if (changeGroupExpand == 1) {
+ if (!contact->group->expanded) {
+ dat->selection--;
+ selMoved = 1;
+ }
+ else pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 0);
+ }
+ else if (changeGroupExpand == 2) {
+ pcli->pfnSetGroupExpand(hwnd, dat, contact->group, 1);
+ dat->selection++;
+ selMoved = 1;
+ }
+ else { SetCapture(hwnd); return 0; }
+ }
+ }
+ }
+ }
+ if (selMoved) {
+ if (dat->selection >= pcli->pfnGetGroupContentsCount(&dat->list, 1))
+ dat->selection = pcli->pfnGetGroupContentsCount(&dat->list, 1) - 1;
+ if (dat->selection < 0) dat->selection = 0;
+ if (dat->bCompactMode)
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+ SetCapture(hwnd);
+ return 0;
+ }
+ SetCapture(hwnd);
+ return 0;
+}
+
+void clcSetDelayTimer(UINT_PTR uIDEvent, HWND hwnd, int nDelay)
+{
+ KillTimer(hwnd, uIDEvent);
+ int delay = nDelay;
+ if (delay == -1) {
+ switch (uIDEvent) {
+ case TIMERID_DELAYEDRESORTCLC: delay = 10; break;
+ case TIMERID_RECALCSCROLLBAR: delay = 10; break;
+ case TIMERID_REBUILDAFTER: delay = 50; break;
+ default: delay = 100; break;
+ }
+ }
+ CLUI_SafeSetTimer(hwnd, uIDEvent, delay, NULL);
+}
+
+static LRESULT clcOnTimer(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (wParam) {
+ case TIMERID_INVALIDATE_FULL:
+ KillTimer(hwnd, TIMERID_INVALIDATE_FULL);
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+ pcli->pfnInvalidateRect(hwnd, NULL, 0);
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ case TIMERID_INVALIDATE:
+ {
+ time_t cur_time = (time(NULL) / 60);
+ if (cur_time != dat->last_tick_time) {
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ dat->last_tick_time = cur_time;
+ }
+ }
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ case TIMERID_SUBEXPAND:
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+ {
+ ClcContact *ht = NULL;
+ if (hitcontact && dat->expandMeta) {
+ if (hitcontact->SubExpanded) hitcontact->SubExpanded = 0; else hitcontact->SubExpanded = 1;
+ db_set_b(hitcontact->hContact, "CList", "Expanded", hitcontact->SubExpanded);
+ if (hitcontact->SubExpanded)
+ ht = &(hitcontact->subcontacts[hitcontact->SubAllocated - 1]);
+ }
+
+ dat->needsResort = 1;
+ pcli->pfnSortCLC(hwnd, dat, 1);
+ cliRecalcScrollBar(hwnd, dat);
+ if (ht) {
+ int i = 0;
+ ClcContact *contact;
+ ClcGroup *group;
+ if (FindItem(hwnd, dat, hitcontact->hContact, &contact, &group, NULL, FALSE)) {
+ i = cliGetRowsPriorTo(&dat->list, group, GetContactIndex(group, contact));
+ pcli->pfnEnsureVisible(hwnd, dat, i + hitcontact->SubAllocated, 0);
+ }
+ }
+ hitcontact = NULL;
+ }
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ case TIMERID_DELAYEDRESORTCLC:
+ TRACE("Do sort on Timer\n");
+ KillTimer(hwnd, TIMERID_DELAYEDRESORTCLC);
+ pcli->pfnSortCLC(hwnd, dat, 1);
+ pcli->pfnInvalidateRect(hwnd, NULL, FALSE);
+ return 0;
+
+ case TIMERID_RECALCSCROLLBAR:
+ KillTimer(hwnd, TIMERID_RECALCSCROLLBAR);
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+ return 0;
+
+ default:
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ }
+ return 0;
+}
+
+
+static LRESULT clcOnActivate(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ TRACE("clcOnActivate\n");
+ if (dat->bCompactMode) {
+ cliRecalcScrollBar(hwnd, dat);
+ if (dat->hwndRenameEdit == NULL)
+ PostMessage(hwnd, WM_SIZE, 0, 0);
+ }
+ dat->dragStage |= DRAGSTAGEF_SKIPRENAME;
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT clcOnSetCursor(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (!CLUI_IsInMainWindow(hwnd))
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ if (g_CluiData.nBehindEdgeState > 0)
+ CLUI_ShowFromBehindEdge();
+
+ if (g_CluiData.bBehindEdgeSettings)
+ CLUI_UpdateTimer(0);
+
+ int lResult = CLUI_TestCursorOnBorders();
+ return lResult ? lResult : DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT clcOnLButtonDown(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+ ClientToScreen(hwnd, &pt);
+ int k = CLUI_SizingOnBorder(pt, 0);
+ if (k) {
+ int io = dat->iHotTrack;
+ dat->iHotTrack = 0;
+ if (dat->exStyle & CLS_EX_TRACKSELECT)
+ pcli->pfnInvalidateItem(hwnd, dat, io);
+
+ if (k && GetCapture() == hwnd)
+ SendMessage(GetParent(hwnd), WM_PARENTNOTIFY, WM_LBUTTONDOWN, lParam);
+ return FALSE;
+ }
+
+ fMouseUpped = FALSE;
+ pcli->pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+
+ pcli->pfnEndRename(hwnd, dat, 1);
+ dat->ptDragStart.x = (short)LOWORD(lParam);
+ dat->ptDragStart.y = (short)HIWORD(lParam);
+
+ ClcContact *contact;
+ ClcGroup *group;
+ DWORD hitFlags;
+ int hit = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), &contact, &group, &hitFlags);
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ if (hit != -1 && !(hitFlags & CLCHT_NOWHERE)) {
+ if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) {
+ if (!(dat->dragStage & DRAGSTAGEF_SKIPRENAME)) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME;
+ dat->dragAutoScrolling = 0;
+ return TRUE;
+ }
+ else {
+ dat->dragStage &= ~DRAGSTAGEF_SKIPRENAME;
+ return TRUE;
+ }
+ }
+ }
+
+ if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_CONTACT && contact->SubAllocated && !contact->isSubcontact)
+ if (hitFlags & CLCHT_ONITEMICON && dat->expandMeta) {
+ BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT);
+
+ hitcontact = contact;
+ HitPoint.x = (short)LOWORD(lParam);
+ HitPoint.y = (short)HIWORD(lParam);
+ fMouseUpped = FALSE;
+ if ((GetKeyState(VK_SHIFT) & 0x8000) || (GetKeyState(VK_CONTROL) & 0x8000) || (GetKeyState(VK_MENU) & 0x8000)) {
+ fMouseUpped = TRUE;
+ hitcontact = contact;
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+ CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL);
+ }
+ }
+ else hitcontact = NULL;
+
+ if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && contact->type == CLCIT_GROUP && (hitFlags & CLCHT_ONITEMICON)) {
+ ClcGroup *selgroup;
+ ClcContact *selcontact;
+ dat->selection = cliGetRowByIndex(dat, dat->selection, &selcontact, &selgroup);
+ pcli->pfnSetGroupExpand(hwnd, dat, contact->group, -1);
+ if (dat->selection != -1) {
+ dat->selection = cliGetRowsPriorTo(&dat->list, selgroup, GetContactIndex(selgroup, selcontact));
+ if (dat->selection == -1)
+ dat->selection = cliGetRowsPriorTo(&dat->list, contact->group, -1);
+ }
+
+ if (dat->bCompactMode)
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ else {
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ UpdateWindow(hwnd);
+ }
+ return TRUE;
+ }
+
+ if (hit != -1 && !(hitFlags & CLCHT_NOWHERE) && (hitFlags & CLCHT_ONITEMCHECK)) {
+ int bNewState = (contact->flags & CONTACTF_CHECKED) == 0; // inversion
+
+ if (contact->type == CLCIT_GROUP)
+ pcli->pfnSetGroupChildCheckboxes(contact->group, bNewState);
+ else
+ pcli->pfnSetContactCheckboxes(contact, bNewState);
+ pcli->pfnRecalculateGroupCheckboxes(hwnd, dat);
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_CHECKCHANGED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = ContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+
+ if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) {
+ NMCLISTCONTROL nm;
+ nm.hdr.code = NM_CLICK;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = (hit == -1 || hitFlags & CLCHT_NOWHERE) ? NULL : ContactToItemHandle(contact, &nm.flags);
+ nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1;
+ nm.pt = dat->ptDragStart;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+
+ if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA))
+ return FALSE;
+
+ dat->selection = (hitFlags & CLCHT_NOWHERE) ? -1 : hit;
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+
+ UpdateWindow(hwnd);
+ if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP) && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK | CLCHT_NOWHERE))) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED;
+ dat->dragAutoScrolling = 0;
+ }
+
+ if (dat->bCompactMode)
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+
+ if (dat->selection != -1)
+ pcli->pfnEnsureVisible(hwnd, dat, hit, 0);
+ return TRUE;
+}
+
+static LRESULT clcOnCaptureChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if ((HWND)lParam != hwnd) {
+ if (dat->iHotTrack != -1) {
+ int i;
+ i = dat->iHotTrack;
+ dat->iHotTrack = -1;
+ pcli->pfnInvalidateItem(hwnd, dat, i);
+ pcli->pfnHideInfoTip(hwnd, dat);
+ }
+ }
+ return 0;
+}
+
+static LRESULT clcOnMouseMove(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL isOutside = FALSE;
+ if (CLUI_IsInMainWindow(hwnd)) {
+ if (g_CluiData.bBehindEdgeSettings)
+ CLUI_UpdateTimer(0);
+ CLUI_TestCursorOnBorders();
+ }
+
+ if (clcProceedDragToScroll(hwnd, (short)HIWORD(lParam)))
+ return 0;
+
+ if (dat->dragStage & DRAGSTAGEF_MAYBERENAME) {
+ POINT pt = UNPACK_POINT(lParam);
+ if (abs(pt.x - dat->ptDragStart.x) > GetSystemMetrics(SM_CXDOUBLECLK) || abs(pt.y - dat->ptDragStart.y) > GetSystemMetrics(SM_CYDOUBLECLK)) {
+ KillTimer(hwnd, TIMERID_RENAME);
+ dat->dragStage &= (~DRAGSTAGEF_MAYBERENAME);
+ }
+ }
+
+ if (dat->iDragItem == -1) {
+ POINT pt = UNPACK_POINT(lParam);
+ ClientToScreen(hwnd, &pt);
+ HWND window = WindowFromPoint(pt);
+ if (window != hwnd)
+ isOutside = TRUE;
+ }
+
+ if (hitcontact != NULL) {
+ int x = (short)LOWORD(lParam);
+ int y = (short)HIWORD(lParam);
+ int xm = GetSystemMetrics(SM_CXDOUBLECLK);
+ int ym = GetSystemMetrics(SM_CYDOUBLECLK);
+ if (abs(HitPoint.x - x) > xm || abs(HitPoint.y - y) > ym) {
+ if (fMouseUpped) {
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+ CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, 0, NULL);
+ fMouseUpped = FALSE;
+ }
+ else {
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+ hitcontact = NULL;
+ fMouseUpped = FALSE;
+ }
+ }
+ }
+
+ if (dat->iDragItem == -1) {
+ DWORD flag = 0;
+ int iOldHotTrack = dat->iHotTrack;
+
+ if (dat->hwndRenameEdit != NULL || GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000)
+ return 0;
+
+ dat->iHotTrack = isOutside ? -1 : cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flag);
+
+ if (flag & CLCHT_NOWHERE)
+ dat->iHotTrack = -1;
+
+ if (iOldHotTrack != dat->iHotTrack || isOutside) {
+ if (iOldHotTrack == -1 && !isOutside)
+ SetCapture(hwnd);
+
+ if (dat->iHotTrack == -1 || isOutside)
+ ReleaseCapture();
+
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ pcli->pfnInvalidateItem(hwnd, dat, iOldHotTrack);
+ pcli->pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ }
+
+ pcli->pfnHideInfoTip(hwnd, dat);
+ }
+
+ KillTimer(hwnd, TIMERID_INFOTIP);
+
+ if (wParam == 0 && dat->hInfoTipItem == NULL) {
+ dat->ptInfoTip.x = (short)LOWORD(lParam);
+ dat->ptInfoTip.y = (short)HIWORD(lParam);
+ CLUI_SafeSetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL);
+ }
+ return 0;
+ }
+
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP))
+ if (abs((short)LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG) || abs((short)HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG))
+ dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE;
+
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+
+ POINT pt = UNPACK_POINT(lParam);
+ HCURSOR hNewCursor = LoadCursor(NULL, IDC_NO);
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->dragAutoScrolling) {
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ dat->dragAutoScrolling = 0;
+ }
+ int target = GetDropTargetInformation(hwnd, dat, pt);
+ if ((dat->dragStage & DRAGSTAGEF_OUTSIDE) && target != DROPTARGET_OUTSIDE) {
+ ClcContact *contact;
+ cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_DRAGSTOP;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = ContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
+ dat->dragStage &= ~DRAGSTAGEF_OUTSIDE;
+ }
+
+ ClcContact *contSour, *contDest;
+
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ break;
+
+ case DROPTARGET_ONCONTACT:
+ cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
+ if (contSour->isChat())
+ break;
+ if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
+ if (!contSour->isSubcontact)
+ hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); /// Add to meta
+ else
+ hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DROPMETA));
+ }
+ break;
+
+ case DROPTARGET_ONMETACONTACT:
+ cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
+ cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
+ if (contSour->isChat() || contDest->isChat())
+ break;
+ if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
+ if (!contSour->isSubcontact)
+ hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); /// Add to meta
+ else if (contSour->subcontacts == contDest)
+ hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_DEFAULTSUB)); ///MakeDefault
+ else
+ hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP));
+ }
+ break;
+
+ case DROPTARGET_ONSUBCONTACT:
+ cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
+ cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
+ if (contSour->isChat() || contDest->isChat())
+ break;
+ if (contSour->type == CLCIT_CONTACT && mir_strcmp(contSour->proto, META_PROTO)) {
+ if (!contSour->isSubcontact)
+ hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER)); /// Add to meta
+ else if (contDest->subcontacts == contSour->subcontacts)
+ break;
+ else
+ hNewCursor = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_REGROUP));
+ }
+ break;
+
+ case DROPTARGET_ONGROUP:
+ hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+
+ case DROPTARGET_INSERTION:
+ hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROP));
+ break;
+
+ case DROPTARGET_OUTSIDE:
+ if (pt.x >= 0 && pt.x < clRect.right && ((pt.y < 0 && pt.y>-dat->dragAutoScrollHeight) || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) {
+ if (!dat->dragAutoScrolling) {
+ dat->dragAutoScrolling = (pt.y < 0) ? -1 : 1;
+ CLUI_SafeSetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL);
+ }
+ SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0);
+ }
+
+ dat->dragStage |= DRAGSTAGEF_OUTSIDE;
+ {
+ ClcContact *contact;
+ cliGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_DRAGGING;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = ContactToItemHandle(contact, &nm.flags);
+ nm.pt = pt;
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm))
+ return 0;
+ }
+ break;
+
+ default:
+ ClcGroup *group = NULL;
+ cliGetRowByIndex(dat, dat->iDragItem, NULL, &group);
+ if (group && group->parent) {
+ ClcContact *contSour;
+ cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
+ if (!contSour->isSubcontact)
+ hNewCursor = LoadCursor(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_DROPUSER));
+ }
+ break;
+ }
+ SetCursor(hNewCursor);
+ }
+ return 0;
+}
+
+static LRESULT clcOnLButtonUp(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (clcExitDragToScroll())
+ return 0;
+
+ fMouseUpped = TRUE;
+
+ if (hitcontact != NULL && dat->expandMeta) {
+ BYTE doubleClickExpand = db_get_b(NULL, "CLC", "MetaDoubleClick", SETTING_METAAVOIDDBLCLICK_DEFAULT);
+ CLUI_SafeSetTimer(hwnd, TIMERID_SUBEXPAND, GetDoubleClickTime()*doubleClickExpand, NULL);
+ }
+ else if (dat->iHotTrack == -1 && dat->iDragItem == -1)
+ ReleaseCapture();
+
+ if (dat->iDragItem == -1)
+ return 0;
+
+ SetCursor((HCURSOR)GetClassLongPtr(hwnd, GCLP_HCURSOR));
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ DWORD flags;
+ dat->iHotTrack = cliHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, &flags);
+ if (dat->iHotTrack == -1)
+ ReleaseCapture();
+ }
+ else if (hitcontact == NULL)
+ ReleaseCapture();
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME))
+ CLUI_SafeSetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL);
+ else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ TCHAR Wording[500];
+ ClcContact *contDest, *contSour;
+ POINT pt = UNPACK_POINT(lParam);
+ int target = GetDropTargetInformation(hwnd, dat, pt);
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ break;
+
+ case DROPTARGET_ONCONTACT:
+ cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
+ cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
+ if (contSour->isChat() || contDest->isChat())
+ break;
+ if (contSour->type == CLCIT_CONTACT) {
+ MCONTACT hcontact = contSour->hContact;
+ if (mir_strcmp(contSour->proto, META_PROTO)) {
+ if (!contSour->isSubcontact) {
+ MCONTACT hDest = contDest->hContact;
+ mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it?"), contDest->szText, contSour->szText);
+ int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact"), MB_OKCANCEL | MB_ICONQUESTION);
+ if (res == 1) {
+ MCONTACT handle = CallService(MS_MC_CONVERTTOMETA, hDest, 0);
+ if (!handle)
+ return 0;
+
+ CallService(MS_MC_ADDTOMETA, hcontact, handle);
+ }
+ }
+ else {
+ hcontact = contSour->hContact;
+ MCONTACT hfrom = contSour->subcontacts->hContact;
+ MCONTACT hdest = contDest->hContact;
+ mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be converted to metacontact and '%s' be added to it (remove it from '%s')?"), contDest->szText, contSour->szText, contSour->subcontacts->szText);
+ int res = MessageBox(hwnd, Wording, TranslateT("Converting to metacontact (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
+ if (res == 1) {
+ MCONTACT handle = (MCONTACT)CallService(MS_MC_CONVERTTOMETA, (WPARAM)hdest, 0);
+ if (!handle)
+ return 0;
+
+ CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
+ CallService(MS_MC_ADDTOMETA, hcontact, handle);
+ }
+ }
+ }
+ }
+ break;
+
+ case DROPTARGET_ONMETACONTACT:
+ cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
+ cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
+ if (contSour->isChat() || contDest->isChat())
+ break;
+ if (contSour->type == CLCIT_CONTACT) {
+ if (!strcmp(contSour->proto, META_PROTO))
+ break;
+ if (!contSour->isSubcontact) {
+ MCONTACT hcontact = contSour->hContact;
+ MCONTACT handle = contDest->hContact;
+ mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->szText);
+ int res = MessageBox(hwnd, Wording, TranslateT("Adding contact to metacontact"), MB_OKCANCEL | MB_ICONQUESTION);
+ if (res == 1) {
+ if (!handle)
+ return 0;
+ CallService(MS_MC_ADDTOMETA, hcontact, handle);
+ }
+ }
+ else if (contSour->subcontacts == contDest) {
+ MCONTACT hsour = contSour->hContact;
+ mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be default?"), contSour->szText);
+ int res = MessageBox(hwnd, Wording, TranslateT("Set default contact"), MB_OKCANCEL | MB_ICONQUESTION);
+ if (res == 1)
+ db_mc_setDefault(contDest->hContact, hsour, true);
+ }
+ else {
+ MCONTACT hcontact = contSour->hContact;
+ MCONTACT hfrom = contSour->subcontacts->hContact;
+ MCONTACT handle = contDest->hContact;
+ mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->szText);
+ int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
+ if (res == 1) {
+ if (!handle)
+ return 0;
+
+ CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
+ CallService(MS_MC_ADDTOMETA, hcontact, handle);
+ }
+ }
+ }
+ break;
+
+ case DROPTARGET_ONSUBCONTACT:
+ cliGetRowByIndex(dat, dat->iDragItem, &contSour, NULL);
+ cliGetRowByIndex(dat, dat->selection, &contDest, NULL);
+ if (contSour->isChat() || contDest->isChat())
+ break;
+ if (contSour->type == CLCIT_CONTACT) {
+ if (!strcmp(contSour->proto, META_PROTO))
+ break;
+ if (!contSour->isSubcontact) {
+ MCONTACT hcontact = contSour->hContact;
+ MCONTACT handle = contDest->subcontacts->hContact;
+ mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be added to metacontact '%s'?"), contSour->szText, contDest->subcontacts->szText);
+ int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
+ if (res == 1) {
+ if (!handle)
+ return 0;
+
+ CallService(MS_MC_ADDTOMETA, hcontact, handle);
+ }
+ }
+ else if (contSour->subcontacts != contDest->subcontacts) {
+ MCONTACT hcontact = contSour->hContact;
+ MCONTACT hfrom = contSour->subcontacts->hContact;
+ MCONTACT handle = contDest->subcontacts->hContact;
+ mir_sntprintf(Wording, SIZEOF(Wording), TranslateT("Do you want contact '%s' to be removed from metacontact '%s' and added to '%s'?"), contSour->szText, contSour->subcontacts->szText, contDest->subcontacts->szText);
+ int res = MessageBox(hwnd, Wording, TranslateT("Changing metacontacts (moving)"), MB_OKCANCEL | MB_ICONQUESTION);
+ if (res == 1) {
+ if (!handle)
+ return 0;
+
+ CallService(MS_MC_REMOVEFROMMETA, 0, hcontact);
+ CallService(MS_MC_ADDTOMETA, hcontact, handle);
+ }
+ }
+ }
+ break;
+
+ case DROPTARGET_ONGROUP:
+ corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ break;
+
+ case DROPTARGET_INSERTION:
+ {
+ ClcContact *contact, *destcontact;
+ ClcGroup *group, *destgroup;
+ BOOL NeedRename = FALSE;
+ TCHAR newName[128] = { 0 };
+ pcli->pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group);
+ int i = pcli->pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup);
+ if (i != -1 && group->groupId != destgroup->groupId) {
+ TCHAR *groupName = mir_tstrdup(pcli->pfnGetGroupName(contact->groupId, 0));
+ TCHAR *shortGroup = NULL;
+ TCHAR *sourceGrName = mir_tstrdup(pcli->pfnGetGroupName(destgroup->groupId, 0));
+ if (groupName) {
+ int len = (int)_tcslen(groupName);
+ do { len--; }
+ while (len >= 0 && groupName[len] != '\\');
+ if (len >= 0) shortGroup = groupName + len + 1;
+ else shortGroup = groupName;
+ }
+ if (shortGroup) {
+ NeedRename = TRUE;
+ if (sourceGrName)
+ mir_sntprintf(newName, SIZEOF(newName), _T("%s\\%s"), sourceGrName, shortGroup);
+ else
+ mir_sntprintf(newName, SIZEOF(newName), _T("%s"), shortGroup);
+ }
+ mir_free(groupName);
+ mir_free(sourceGrName);
+ }
+ int newIndex = CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, (destcontact && i != -1) ? destcontact->groupId : 0);
+ newIndex = newIndex ? newIndex : contact->groupId;
+ if (NeedRename) pcli->pfnRenameGroup(newIndex, newName);
+ }
+ break;
+
+ case DROPTARGET_OUTSIDE:
+ corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ break;
+
+ default:
+ corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ break;
+ }
+ }
+
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ return 0;
+}
+
+static LRESULT clcOnLButtonDblClick(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ KillTimer(hwnd, TIMERID_SUBEXPAND);
+ hitcontact = NULL;
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT clcOnDestroy(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ for (int i = 0; i <= FONTID_MODERN_MAX; i++) {
+ if (dat->fontModernInfo[i].hFont)
+ DeleteObject(dat->fontModernInfo[i].hFont);
+ dat->fontModernInfo[i].hFont = NULL;
+ }
+ if (dat->hMenuBackground) {
+ DeleteObject(dat->hMenuBackground);
+ dat->hMenuBackground = NULL;
+ }
+ if (dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+
+ ImageArray_Clear(&dat->avatar_cache);
+ DeleteDC(dat->avatar_cache.hdc);
+ ImageArray_Free(&dat->avatar_cache, FALSE);
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+
+ RowHeights_Free(dat);
+ corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ xpt_FreeThemeForWindow(hwnd);
+ return 0;
+}
+
+static LRESULT clcOnIntmGroupChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD iExtraImage[EXTRA_ICON_COUNT];
+ BYTE flags = 0;
+
+ ClcContact *contact;
+ if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL))
+ memset(iExtraImage, 0xFF, sizeof(iExtraImage));
+ else {
+ memcpy(iExtraImage, contact->iExtraImage, sizeof(iExtraImage));
+ flags = contact->flags;
+ }
+ pcli->pfnDeleteItemFromTree(hwnd, wParam);
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !db_get_b(wParam, "CList", "Hidden", 0)) {
+ NMCLISTCONTROL nm;
+ pcli->pfnAddContactToTree(hwnd, dat, wParam, 1, 1);
+ if (pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) {
+ memcpy(contact->iExtraImage, iExtraImage, sizeof(iExtraImage));
+ if (flags & CONTACTF_CHECKED)
+ contact->flags |= CONTACTF_CHECKED;
+ }
+ nm.hdr.code = CLN_CONTACTMOVED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = (HANDLE)wParam;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
+ dat->needsResort = 1;
+ }
+ SetTimer(hwnd, TIMERID_REBUILDAFTER, 1, NULL);
+ return 0;
+}
+
+static LRESULT clcOnIntmIconChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ClcContact *contact = NULL;
+ ClcGroup *group = NULL;
+ int recalcScrollBar = 0, shouldShow;
+ BOOL needRepaint = FALSE;
+ RECT iconRect = { 0 };
+ int contacticon = corecli.pfnGetContactIcon(wParam);
+ MCONTACT hSelItem = NULL;
+ ClcContact *selcontact = NULL;
+
+ char *szProto = GetContactProto(wParam);
+ WORD status = (szProto == NULL) ? ID_STATUS_OFFLINE : GetContactCachedStatus(wParam);
+ BOOL image_is_special = (LOWORD(contacticon) != (LOWORD(lParam))); //check only base icons
+
+ int nHiddenStatus = CLVM_GetContactHiddenStatus(wParam, szProto, dat);
+
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ bool isVisiblebyFilter = (((style & CLS_SHOWHIDDEN) && nHiddenStatus != -1) || !nHiddenStatus);
+ bool ifVisibleByClui = !pcli->pfnIsHiddenMode(dat, status);
+ bool isVisible = g_CluiData.bFilterEffective&CLVM_FILTER_STATUS ? TRUE : ifVisibleByClui;
+ bool isIconChanged = cli_GetContactIcon(wParam) != LOWORD(lParam);
+
+ shouldShow = isVisiblebyFilter && (isVisible || isIconChanged);
+
+ // XXX CLVM changed - this means an offline msg is flashing, so the contact should be shown
+
+ if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, &group, NULL)) {
+ if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) {
+ if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
+ hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
+ pcli->pfnAddContactToTree(hwnd, dat, wParam, (style & CLS_CONTACTLIST) == 0, 0);
+ recalcScrollBar = 1;
+ needRepaint = TRUE;
+ pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL);
+ if (contact) {
+ contact->iImage = lParam;
+ contact->image_is_special = image_is_special;
+ pcli->pfnNotifyNewContact(hwnd, wParam);
+ dat->needsResort = 1;
+ }
+ }
+ }
+ else {
+ //item in list already
+ if (contact && contact->iImage == lParam)
+ return 0;
+
+ if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline) && clcItemNotHiddenOffline(dat, group, contact))
+ shouldShow = TRUE;
+
+ if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && ((style & CLS_HIDEOFFLINE) || group->hideOffline || g_CluiData.bFilterEffective)) { // CLVM changed
+ if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
+ hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
+ pcli->pfnRemoveItemFromGroup(hwnd, group, contact, (style & CLS_CONTACTLIST) == 0);
+ needRepaint = TRUE;
+ recalcScrollBar = 1;
+ dat->needsResort = 1;
+ }
+ else if (contact) {
+ contact->iImage = lParam;
+ if (!pcli->pfnIsHiddenMode(dat, status))
+ contact->flags |= CONTACTF_ONLINE;
+ else
+ contact->flags &= ~CONTACTF_ONLINE;
+ contact->image_is_special = image_is_special;
+ if (!image_is_special) { //Only if it is status changing
+ dat->needsResort = 1;
+ needRepaint = TRUE;
+ }
+ else if (dat->m_paintCouter == contact->lastPaintCounter) //if contacts is visible
+ needRepaint = TRUE;
+ }
+ }
+
+ if (hSelItem) {
+ ClcGroup *selgroup;
+ if (pcli->pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact));
+ else
+ dat->selection = -1;
+ }
+
+ if (dat->needsResort) {
+ TRACE("Sort required\n");
+ clcSetDelayTimer(TIMERID_DELAYEDRESORTCLC, hwnd);
+ }
+ else if (needRepaint) {
+ if (contact && contact->pos_icon.bottom != 0 && contact->pos_icon.right != 0)
+ CLUI__cliInvalidateRect(hwnd, &(contact->pos_icon), FALSE);
+ else
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ //try only needed rectangle
+ }
+
+ return 0;
+}
+
+static LRESULT clcOnIntmAvatarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ClcContact *contact;
+ if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
+ Cache_GetAvatar(dat, contact);
+ else if (dat->use_avatar_service && !wParam)
+ UpdateAllAvatars(dat);
+
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ return 0;
+}
+
+static LRESULT clcOnIntmTimeZoneChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ClcContact *contact;
+ if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ if (contact) {
+ Cache_GetTimezone(dat, contact->hContact);
+ Cache_GetText(dat, contact, 1);
+ cliRecalcScrollBar(hwnd, dat);
+ }
+ return 0;
+}
+
+static LRESULT clcOnIntmNameChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ pcli->pfnInvalidateDisplayNameCacheEntry(wParam);
+
+ ClcContact *contact;
+ if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, FALSE))
+ return ret;
+
+ if (contact) {
+ lstrcpyn(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), SIZEOF(contact->szText));
+ Cache_GetText(dat, contact, 1);
+ cliRecalcScrollBar(hwnd, dat);
+ }
+ dat->needsResort = 1;
+ pcli->pfnSortContacts();
+
+ return ret;
+}
+
+static LRESULT clcOnIntmApparentModeChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT clcOnIntmStatusMsgChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM hContact, LPARAM lParam)
+{
+ if (hContact == NULL || IsHContactInfo(hContact) || IsHContactGroup(hContact))
+ return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
+
+ ClcContact *contact;
+ if (!FindItem(hwnd, dat, hContact, &contact, NULL, NULL, FALSE))
+ return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
+
+ if (contact) {
+ Cache_GetText(dat, contact, 1);
+ cliRecalcScrollBar(hwnd, dat);
+ PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
+ }
+ return corecli.pfnContactListControlWndProc(hwnd, msg, hContact, lParam);
+}
+
+static LRESULT clcOnIntmNotOnListChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING*)lParam;
+
+ ClcContact *contact;
+ if (!FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE))
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ if (contact->type != CLCIT_CONTACT)
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+
+ if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0)
+ contact->flags &= ~CONTACTF_NOTONLIST;
+ else
+ contact->flags |= CONTACTF_NOTONLIST;
+
+ CLUI__cliInvalidateRect(hwnd, NULL, FALSE);
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT clcOnIntmScrollBarChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar)
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ else
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+ }
+ return 0;
+}
+
+static LRESULT clcOnIntmStatusChanged(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int ret = corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ if (wParam != 0) {
+ ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(wParam);
+ if (pdnce && pdnce->m_cache_cszProto) {
+ pdnce->m_cache_nStatus = GetStatusForContact(pdnce->hContact, pdnce->m_cache_cszProto);
+ if (!dat->force_in_dialog && (dat->second_line_show || dat->third_line_show))
+ gtaRenewText(pdnce->hContact);
+ SendMessage(hwnd, INTM_ICONCHANGED, wParam, corecli.pfnGetContactIcon(wParam));
+
+ ClcContact *contact;
+ if (FindItem(hwnd, dat, wParam, &contact, NULL, NULL, TRUE)) {
+ if (contact && contact->type == CLCIT_CONTACT) {
+ if (!contact->image_is_special && pdnce___GetStatus(pdnce) > ID_STATUS_OFFLINE)
+ contact->iImage = corecli.pfnGetContactIcon(wParam);
+ if (contact->isSubcontact && contact->subcontacts && contact->subcontacts->type == CLCIT_CONTACT)
+ pcli->pfnClcBroadcast(INTM_STATUSCHANGED, contact->subcontacts->hContact, 0); //forward status changing to host meta contact
+ }
+ }
+ }
+ }
+
+ if (db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOOFLINETOROOT_DEFAULT))
+ pcli->pfnInitAutoRebuild(hwnd);
+ else {
+ pcli->pfnSortContacts();
+ PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
+ }
+ return ret;
+}
+
+static LRESULT clcOnIntmReloadOptions(ClcData *dat, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ pcli->pfnLoadClcOptions(hwnd, dat, FALSE);
+ LoadCLCOptions(hwnd, dat, FALSE);
+ pcli->pfnSaveStateAndRebuildList(hwnd, dat);
+ pcli->pfnSortCLC(hwnd, dat, 1);
+ if (IsWindowVisible(hwnd))
+ pcli->pfnInvalidateRect(GetParent(hwnd), NULL, FALSE);
+ return TRUE;
+}
+
+HRESULT ClcLoadModule()
+{
+ g_himlCListClc = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0);
+
+ HookEvent(ME_MC_SUBCONTACTSCHANGED, clcMetacontactChanged);
+ HookEvent(ME_MC_ENABLED, clcMetaModeChanged);
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED, clcHookSettingChanged);
+ HookEvent(ME_OPT_INITIALISE, ClcOptInit);
+ hAckHook = (HANDLE)HookEvent(ME_PROTO_ACK, clcHookProtoAck);
+ HookEvent(ME_SYSTEM_MODULESLOADED, clcHookModulesLoaded);
+ HookEvent(ME_DB_EVENT_ADDED, clcHookDbEventAdded);
+ return S_OK;
+}
+
+int ClcUnloadModule()
+{
+ if (g_CluiData.bOldUseGroups != (BYTE)-1)
+ db_set_b(NULL, "CList", "UseGroups", (BYTE)g_CluiData.bOldUseGroups);
+ if (g_CluiData.boldHideOffline != (BYTE)-1)
+ db_set_b(NULL, "CList", "HideOffline", (BYTE)g_CluiData.boldHideOffline);
+
+ return 0;
+}
+
+int ClcDoProtoAck(MCONTACT wParam, ACKDATA * ack)
+{
+ if (MirandaExiting()) return 0;
+ if (ack->type == ACKTYPE_STATUS) {
+ if (ack->result == ACKRESULT_SUCCESS) {
+ for (int i = 0; i < pcli->hClcProtoCount; i++) {
+ if (!lstrcmpA(pcli->clcProto[i].szProto, ack->szModule)) {
+ pcli->clcProto[i].dwStatus = (WORD)ack->lParam;
+ if (pcli->clcProto[i].dwStatus >= ID_STATUS_OFFLINE)
+ pcli->pfnTrayIconUpdateBase(pcli->clcProto[i].szProto);
+ return 0;
+ }
+ }
+ }
+ }
+ else if (ack->type == ACKTYPE_AWAYMSG) {
+ if (ack->result == ACKRESULT_SUCCESS && ack->lParam) {
+ //Do not change DB if it is IRC protocol
+ if (ack->szModule != NULL)
+ if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0)
+ return 0;
+
+ db_set_ws(ack->hContact, "CList", "StatusMsg", (const TCHAR *)ack->lParam);
+ gtaRenewText(ack->hContact);
+ }
+ else {
+ //db_unset(ack->hContact,"CList","StatusMsg");
+ //char a = '\0';
+ //Do not change DB if it is IRC protocol
+ if (ack->szModule != NULL)
+ if (db_get_b(ack->hContact, ack->szModule, "ChatRoom", 0) != 0)
+ return 0;
+
+ if (ack->hContact) {
+ char *val = db_get_sa(ack->hContact, "CList", "StatusMsg");
+ if (val) {
+ if (!mir_bool_strcmpi(val, ""))
+ db_set_s(ack->hContact, "CList", "StatusMsg", "");
+ else
+ gtaRenewText(ack->hContact);
+ mir_free(val);
+ }
+ }
+ //pcli->pfnClcBroadcast(INTM_STATUSMSGCHANGED,(WPARAM)ack->hContact,&a);
+ }
+ }
+ else if (ack->type == ACKTYPE_AVATAR) {
+ if (ack->result == ACKRESULT_SUCCESS) {
+ PROTO_AVATAR_INFORMATIONT *pai = (PROTO_AVATAR_INFORMATIONT*)ack->hProcess;
+ if (pai != NULL && pai->hContact != NULL)
+ pcli->pfnClcBroadcast(INTM_AVATARCHANGED, (WPARAM)pai->hContact, 0);
+ }
+ }
+ else if (ack->type == ACKTYPE_EMAIL) {
+ CLUIUnreadEmailCountChanged(0, 0);
+ }
+ return 0;
+}
+
+int ClcGetShortData(ClcData* pData, struct SHORTDATA *pShortData)
+{
+ if (!pData || !pShortData)
+ return -1;
+
+ pShortData->hWnd = pData->hWnd;
+ pShortData->text_replace_smileys = pData->text_replace_smileys;
+ pShortData->text_smiley_height = pData->text_smiley_height;
+ pShortData->text_use_protocol_smileys = pData->text_use_protocol_smileys;
+ pShortData->contact_time_show_only_if_different = pData->contact_time_show_only_if_different;
+ // Second line
+ pShortData->second_line_show = pData->second_line_show;
+ pShortData->second_line_draw_smileys = pData->second_line_draw_smileys;
+ pShortData->second_line_type = pData->second_line_type;
+
+ _tcsncpy(pShortData->second_line_text, pData->second_line_text, TEXT_TEXT_MAX_LENGTH);
+
+ pShortData->second_line_xstatus_has_priority = pData->second_line_xstatus_has_priority;
+ pShortData->second_line_show_status_if_no_away = pData->second_line_show_status_if_no_away;
+ pShortData->second_line_show_listening_if_no_away = pData->second_line_show_listening_if_no_away;
+ pShortData->second_line_use_name_and_message_for_xstatus = pData->second_line_use_name_and_message_for_xstatus;
+
+ pShortData->third_line_show = pData->third_line_show;
+ pShortData->third_line_draw_smileys = pData->third_line_draw_smileys;
+ pShortData->third_line_type = pData->third_line_type;
+
+ _tcsncpy(pShortData->third_line_text, pData->third_line_text, TEXT_TEXT_MAX_LENGTH);
+
+ pShortData->third_line_xstatus_has_priority = pData->third_line_xstatus_has_priority;
+ pShortData->third_line_show_status_if_no_away = pData->third_line_show_status_if_no_away;
+ pShortData->third_line_show_listening_if_no_away = pData->third_line_show_listening_if_no_away;
+ pShortData->third_line_use_name_and_message_for_xstatus = pData->third_line_use_name_and_message_for_xstatus;
+ return 0;
+}
+
+int ClcEnterDragToScroll(HWND hwnd, int Y)
+{
+ if (IsDragToScrollMode)
+ return 0;
+
+ ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0);
+ if (!dat)
+ return 0;
+
+ StartDragPos = Y;
+ StartScrollPos = dat->yScroll;
+ IsDragToScrollMode = 1;
+ SetCapture(hwnd);
+ return 1;
+}
+
+
+/*
+* Contact list control window procedure
+*/
+LRESULT CALLBACK cli_ContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+
+#define CASE_MSG_RET(msg, handler) case msg: return handler(dat, hwnd, msg, wParam, lParam);
+
+ ClcData *dat = (ClcData*)GetWindowLongPtr(hwnd, 0);
+
+ if (msg >= CLM_FIRST && msg < CLM_LAST)
+ return cli_ProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
+
+ switch (msg) {
+ CASE_MSG_RET(INTM_GROUPCHANGED, clcOnIntmGroupChanged);
+ CASE_MSG_RET(INTM_ICONCHANGED, clcOnIntmIconChanged);
+ CASE_MSG_RET(INTM_AVATARCHANGED, clcOnIntmAvatarChanged);
+ CASE_MSG_RET(INTM_TIMEZONECHANGED, clcOnIntmTimeZoneChanged);
+ CASE_MSG_RET(INTM_NAMECHANGED, clcOnIntmNameChanged);
+ CASE_MSG_RET(INTM_APPARENTMODECHANGED, clcOnIntmApparentModeChanged);
+ CASE_MSG_RET(INTM_STATUSMSGCHANGED, clcOnIntmStatusMsgChanged);
+ CASE_MSG_RET(INTM_NOTONLISTCHANGED, clcOnIntmNotOnListChanged);
+ CASE_MSG_RET(INTM_SCROLLBARCHANGED, clcOnIntmScrollBarChanged);
+ CASE_MSG_RET(INTM_STATUSCHANGED, clcOnIntmStatusChanged);
+ CASE_MSG_RET(INTM_RELOADOPTIONS, clcOnIntmReloadOptions);
+
+ CASE_MSG_RET(WM_CREATE, clcOnCreate);
+ CASE_MSG_RET(WM_NCHITTEST, clcOnHitTest);
+ CASE_MSG_RET(WM_COMMAND, clcOnCommand);
+ CASE_MSG_RET(WM_SIZE, clcOnSize);
+ CASE_MSG_RET(WM_CHAR, clcOnChar);
+ CASE_MSG_RET(WM_PAINT, clcOnPaint);
+ CASE_MSG_RET(WM_ERASEBKGND, clcOnEraseBkGround);
+ CASE_MSG_RET(WM_KEYDOWN, clcOnKeyDown);
+ CASE_MSG_RET(WM_TIMER, clcOnTimer);
+ CASE_MSG_RET(WM_ACTIVATE, clcOnActivate);
+ CASE_MSG_RET(WM_SETCURSOR, clcOnSetCursor);
+ CASE_MSG_RET(WM_LBUTTONDOWN, clcOnLButtonDown);
+ CASE_MSG_RET(WM_CAPTURECHANGED, clcOnCaptureChanged);
+ CASE_MSG_RET(WM_MOUSEMOVE, clcOnMouseMove);
+ CASE_MSG_RET(WM_LBUTTONUP, clcOnLButtonUp);
+ CASE_MSG_RET(WM_LBUTTONDBLCLK, clcOnLButtonDblClick);
+ CASE_MSG_RET(WM_DESTROY, clcOnDestroy);
+
+ default:
+ return corecli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
+ }
+ return TRUE;
+}
diff --git a/plugins/Clist_modern/src/modern_clcitems.cpp b/plugins/Clist_modern/src/modern_clcitems.cpp
index 402a242098..9c5ecc6c1e 100644
--- a/plugins/Clist_modern/src/modern_clcitems.cpp
+++ b/plugins/Clist_modern/src/modern_clcitems.cpp
@@ -1,747 +1,746 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
-Copyright (c) 2000-08 Miranda ICQ/IM project,
-all portions of this codebase are copyrighted to the people
-listed in contributors.txt.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#include "hdr/modern_commonheaders.h"
-#include "hdr/modern_clc.h"
-#include "hdr/modern_clist.h"
-#include "m_metacontacts.h"
-#include "hdr/modern_commonprototypes.h"
-
-void AddSubcontacts(ClcData *dat, ClcContact *cont, BOOL showOfflineHereGroup)
-{
- ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(cont->hContact);
- cont->SubExpanded = (db_get_b(cont->hContact, "CList", "Expanded", 0) && (db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT)));
- int subcount = db_mc_getSubCount(cont->hContact);
- if (subcount <= 0) {
- cont->isSubcontact = 0;
- cont->subcontacts = NULL;
- cont->SubAllocated = 0;
- return;
- }
-
- cont->isSubcontact = 0;
- mir_free(cont->subcontacts);
- cont->subcontacts = (ClcContact *)mir_calloc(sizeof(ClcContact)*subcount);
- cont->SubAllocated = subcount;
- int i = 0;
- int bHideOffline = db_get_b(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
- for (int j = 0; j < subcount; j++) {
- MCONTACT hsub = db_mc_getSub(cont->hContact, j);
- cacheEntry = pcli->pfnGetCacheEntry(hsub);
- WORD wStatus = pdnce___GetStatus(cacheEntry);
-
- if (!showOfflineHereGroup && bHideOffline && !cacheEntry->m_cache_nNoHiddenOffline && wStatus == ID_STATUS_OFFLINE)
- continue;
-
- ClcContact& p = cont->subcontacts[i];
- p.hContact = cacheEntry->hContact;
-
- p.avatar_pos = AVATAR_POS_DONT_HAVE;
- Cache_GetAvatar(dat, &p);
-
- p.iImage = corecli.pfnGetContactIcon(cacheEntry->hContact);
- memset(p.iExtraImage, 0xFF, sizeof(p.iExtraImage));
- p.proto = cacheEntry->m_cache_cszProto;
- p.type = CLCIT_CONTACT;
- p.flags = 0;//CONTACTF_ONLINE;
- p.isSubcontact = i + 1;
- p.lastPaintCounter = 0;
- p.subcontacts = cont;
- p.image_is_special = FALSE;
- //p.status = cacheEntry->status;
- Cache_GetTimezone(dat, (&p)->hContact);
- Cache_GetText(dat, &p, 1);
-
- char *szProto = cacheEntry->m_cache_cszProto;
- if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, wStatus))
- p.flags |= CONTACTF_ONLINE;
- int apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0;
- if (apparentMode == ID_STATUS_OFFLINE) p.flags |= CONTACTF_INVISTO;
- else if (apparentMode == ID_STATUS_ONLINE) p.flags |= CONTACTF_VISTO;
- else if (apparentMode) p.flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
- if (cacheEntry->NotOnList) p.flags |= CONTACTF_NOTONLIST;
- int idleMode = szProto != NULL ? cacheEntry->IdleTS : 0;
- if (idleMode) p.flags |= CONTACTF_IDLE;
- i++;
- }
-
- cont->SubAllocated = i;
- if (!i && cont->subcontacts != NULL)
- mir_free_and_nil(cont->subcontacts);
-}
-
-int cli_AddItemToGroup(ClcGroup *group, int iAboveItem)
-{
- if (group == NULL)
- return 0;
-
- iAboveItem = corecli.pfnAddItemToGroup(group, iAboveItem);
- ClearRowByIndexCache();
- return iAboveItem;
-}
-
-ClcGroup* cli_AddGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
-{
- ClearRowByIndexCache();
- if (!dat->force_in_dialog && !(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN))
- if (!lstrcmp(_T("-@-HIDDEN-GROUP-@-"), szName)) { //group is hidden
- ClearRowByIndexCache();
- return NULL;
- }
-
- ClcGroup *result = corecli.pfnAddGroup(hwnd, dat, szName, flags, groupId, calcTotalMembers);
- ClearRowByIndexCache();
- return result;
-}
-
-void cli_FreeContact(ClcContact *p)
-{
- if (p->SubAllocated) {
- if (p->subcontacts && !p->isSubcontact) {
- for (int i = 0; i < p->SubAllocated; i++) {
- p->subcontacts[i].ssText.DestroySmileyList();
- if (p->subcontacts[i].avatar_pos == AVATAR_POS_ANIMATED)
- AniAva_RemoveAvatar(p->subcontacts[i].hContact);
- p->subcontacts[i].avatar_pos = AVATAR_POS_DONT_HAVE;
- }
- mir_free_and_nil(p->subcontacts);
- }
- }
-
- p->ssText.DestroySmileyList();
- if (p->avatar_pos == AVATAR_POS_ANIMATED)
- AniAva_RemoveAvatar(p->hContact);
- p->avatar_pos = AVATAR_POS_DONT_HAVE;
- corecli.pfnFreeContact(p);
-}
-
-void cli_FreeGroup(ClcGroup* group)
-{
- corecli.pfnFreeGroup(group);
- ClearRowByIndexCache();
-}
-
-int cli_AddInfoItemToGroup(ClcGroup *group, int flags, const TCHAR *pszText)
-{
- int i = corecli.pfnAddInfoItemToGroup(group, flags, pszText);
- ClearRowByIndexCache();
- return i;
-}
-
-static void _LoadDataToContact(ClcContact *cont, ClcGroup *group, ClcData *dat, MCONTACT hContact)
-{
- if (!cont)
- return;
-
- cont->type = CLCIT_CONTACT;
- cont->SubAllocated = 0;
- cont->isSubcontact = 0;
- cont->subcontacts = NULL;
- cont->szText[0] = 0;
- cont->lastPaintCounter = 0;
- cont->image_is_special = FALSE;
- cont->hContact = hContact;
-
- pcli->pfnInvalidateDisplayNameCacheEntry(hContact);
-
- ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
- char *szProto = cacheEntry->m_cache_cszProto;
- cont->proto = szProto;
-
- if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, pdnce___GetStatus(cacheEntry)))
- cont->flags |= CONTACTF_ONLINE;
-
- WORD apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0;
-
- if (apparentMode)
- switch (apparentMode) {
- case ID_STATUS_OFFLINE:
- cont->flags |= CONTACTF_INVISTO;
- break;
- case ID_STATUS_ONLINE:
- cont->flags |= CONTACTF_VISTO;
- break;
- default:
- cont->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
- }
-
- if (cacheEntry->NotOnList)
- cont->flags |= CONTACTF_NOTONLIST;
-
- DWORD idleMode = szProto != NULL ? cacheEntry->IdleTS : 0;
- if (idleMode)
- cont->flags |= CONTACTF_IDLE;
-
- // Add subcontacts
- if (szProto)
- if (dat->IsMetaContactsEnabled && mir_strcmp(cont->proto, META_PROTO) == 0)
- AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group));
-
- cont->lastPaintCounter = 0;
- cont->avatar_pos = AVATAR_POS_DONT_HAVE;
- Cache_GetAvatar(dat, cont);
- Cache_GetText(dat, cont, 1);
- Cache_GetTimezone(dat, cont->hContact);
- cont->iImage = corecli.pfnGetContactIcon(hContact);
- cont->bContactRate = db_get_b(hContact, "CList", "Rate", 0);
-}
-
-static ClcContact* AddContactToGroup(ClcData *dat, ClcGroup *group, ClcCacheEntry *cacheEntry)
-{
- if (cacheEntry == NULL) return NULL;
- if (group == NULL) return NULL;
- if (dat == NULL) return NULL;
- MCONTACT hContact = cacheEntry->hContact;
- dat->needsResort = 1;
- int i;
- for (i = group->cl.count - 1; i >= 0; i--)
- if (group->cl.items[i]->type != CLCIT_INFO || !(group->cl.items[i]->flags&CLCIIF_BELOWCONTACTS)) break;
- i = cli_AddItemToGroup(group, i + 1);
-
- _LoadDataToContact(group->cl.items[i], group, dat, hContact);
- cacheEntry = pcli->pfnGetCacheEntry(hContact);
- ClearRowByIndexCache();
- return group->cl.items[i];
-}
-
-void* AddTempGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
-{
- int i = 0;
- int f = 0;
- DWORD groupFlags;
-
- if (wildcmp(_T2A(szName), "-@-HIDDEN-GROUP-@-"))
- return NULL;
-
- for (i = 1;; i++) {
- TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags);
- if (szGroupName == NULL) break;
- if (!mir_tstrcmpi(szGroupName, szName)) f = 1;
- }
-
- if (f)
- return NULL;
-
- char buf[20];
- _itoa_s(i-1, buf, 10);
-
- TCHAR b2[255];
- mir_sntprintf(b2, SIZEOF(b2), _T("#%s"), szName);
- b2[0] = 1 | GROUPF_EXPANDED;
- db_set_ws(NULL, "CListGroups", buf, b2);
- pcli->pfnGetGroupName(i, &groupFlags);
- return cli_AddGroup(hwnd, dat, szName, groupFlags, i, 0);
-}
-
-void cli_AddContactToTree(HWND hwnd, ClcData *dat, MCONTACT hContact, int updateTotalCount, int checkHideOffline)
-{
- ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
- if (dat->IsMetaContactsEnabled && cacheEntry && cacheEntry->m_bIsSub)
- return; //contact should not be added
-
- if (!dat->IsMetaContactsEnabled && cacheEntry && !mir_strcmp(cacheEntry->m_cache_cszProto, META_PROTO))
- return;
-
- corecli.pfnAddContactToTree(hwnd, dat, hContact, updateTotalCount, checkHideOffline);
-
- ClcGroup *group;
- ClcContact *cont;
- if (FindItem(hwnd, dat, hContact, &cont, &group, NULL, FALSE))
- _LoadDataToContact(cont, group, dat, hContact);
-}
-
-void cli_DeleteItemFromTree(HWND hwnd, MCONTACT hItem)
-{
- ClcData *dat = (ClcData *)GetWindowLongPtr(hwnd, 0);
- ClearRowByIndexCache();
- corecli.pfnDeleteItemFromTree(hwnd, hItem);
-
- // check here contacts are not resorting
- if (hwnd == pcli->hwndContactTree)
- pcli->pfnFreeCacheItem(pcli->pfnGetCacheEntry(hItem));
- dat->needsResort = 1;
- ClearRowByIndexCache();
-}
-
-__inline BOOL CLCItems_IsShowOfflineGroup(ClcGroup* group)
-{
- DWORD groupFlags = 0;
- if (!group) return FALSE;
- if (group->hideOffline) return FALSE;
- pcli->pfnGetGroupName(group->groupId, &groupFlags);
- return (groupFlags&GROUPF_SHOWOFFLINE) != 0;
-}
-
-MCONTACT SaveSelection(ClcData *dat)
-{
- ClcContact *selcontact = NULL;
- if (pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
- return NULL;
-
- return (MCONTACT)pcli->pfnContactToHItem(selcontact);
-}
-
-int RestoreSelection(ClcData *dat, MCONTACT hSelected)
-{
- ClcContact *selcontact = NULL;
- ClcGroup *selgroup = NULL;
-
- if (!hSelected || !pcli->pfnFindItem(dat->hWnd, dat, hSelected, &selcontact, &selgroup, NULL)) {
- dat->selection = -1;
- return dat->selection;
- }
-
- if (!selcontact->isSubcontact)
- dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact));
- else {
- dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact->subcontacts));
-
- if (dat->selection != -1)
- dat->selection += selcontact->isSubcontact;
- }
- return dat->selection;
-}
-
-void cliRebuildEntireList(HWND hwnd, ClcData *dat)
-{
- DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
- ClcGroup *group;
- static int rebuildCounter = 0;
-
- BOOL PlaceOfflineToRoot = db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOFFLINETOROOT_DEFAULT);
- KillTimer(hwnd, TIMERID_REBUILDAFTER);
-
- ClearRowByIndexCache();
- ImageArray_Clear(&dat->avatar_cache);
- RowHeights_Clear(dat);
- RowHeights_GetMaxRowHeight(dat, hwnd);
- TRACEVAR("Rebuild Entire List %d times\n", ++rebuildCounter);
-
- dat->list.expanded = 1;
- dat->list.hideOffline = db_get_b(NULL, "CLC", "HideOfflineRoot", SETTING_HIDEOFFLINEATROOT_DEFAULT) && style&CLS_USEGROUPS;
- dat->list.cl.count = dat->list.cl.limit = 0;
- dat->list.cl.increment = 50;
- dat->needsResort = 1;
-
- MCONTACT hSelected = SaveSelection(dat);
- dat->selection = -1;
- dat->HiLightMode = db_get_b(NULL, "CLC", "HiLightMode", SETTING_HILIGHTMODE_DEFAULT);
-
- for (int i = 1;; i++) {
- DWORD groupFlags;
- TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags); //UNICODE
- if (szGroupName == NULL)
- break;
- cli_AddGroup(hwnd, dat, szGroupName, groupFlags, i, 0);
- }
-
- for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
- ClcContact *cont = NULL;
- ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
-
- int nHiddenStatus = CLVM_GetContactHiddenStatus(hContact, NULL, dat);
- if ((style & CLS_SHOWHIDDEN && nHiddenStatus != -1) || !nHiddenStatus) {
- if (lstrlen(cacheEntry->tszGroup) == 0)
- group = &dat->list;
- else
- group = cli_AddGroup(hwnd, dat, cacheEntry->tszGroup, (DWORD)-1, 0, 0);
-
- if (group != NULL) {
- WORD wStatus = pdnce___GetStatus(cacheEntry);
- if (wStatus == ID_STATUS_OFFLINE && PlaceOfflineToRoot)
- group = &dat->list;
-
- group->totalMembers++;
-
- if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
- if (cacheEntry->m_cache_cszProto == NULL) {
- if (!pcli->pfnIsHiddenMode(dat, ID_STATUS_OFFLINE) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group))
- cont = AddContactToGroup(dat, group, cacheEntry);
- }
- else if (!pcli->pfnIsHiddenMode(dat, wStatus) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group))
- cont = AddContactToGroup(dat, group, cacheEntry);
- }
- else cont = AddContactToGroup(dat, group, cacheEntry);
- }
- }
- if (cont) {
- cont->SubAllocated = 0;
- if (cont->proto && dat->IsMetaContactsEnabled && strcmp(cont->proto, META_PROTO) == 0)
- AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group));
- }
- }
-
- if (style & CLS_HIDEEMPTYGROUPS) {
- group = &dat->list;
- group->scanIndex = 0;
- for (;;) {
- if (group->scanIndex == group->cl.count) {
- group = group->parent;
- if (group == NULL)
- break;
- }
- else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
- if (group->cl.items[group->scanIndex]->group->cl.count == 0)
- group = pcli->pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0);
- else {
- group = group->cl.items[group->scanIndex]->group;
- group->scanIndex = 0;
- }
- continue;
- }
- group->scanIndex++;
- }
- }
-
- pcli->pfnSortCLC(hwnd, dat, 0);
-
- RestoreSelection(dat, hSelected);
-}
-
-void cli_SortCLC(HWND hwnd, ClcData *dat, int useInsertionSort)
-{
- MCONTACT hSelected = SaveSelection(dat);
- corecli.pfnSortCLC(hwnd, dat, useInsertionSort);
- RestoreSelection(dat, hSelected);
-}
-
-int GetNewSelection(ClcGroup *group, int selection, int direction)
-{
- if (selection < 0)
- return 0;
-
- int lastcount = 0, count = 0;
-
- group->scanIndex = 0;
- for (;;) {
- if (group->scanIndex == group->cl.count) {
- group = group->parent;
- if (group == NULL) break;
- group->scanIndex++;
- continue;
- }
-
- if (count >= selection)
- return count;
-
- lastcount = count;
- count++;
- if (!direction && count > selection)
- return lastcount;
-
- if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (group->cl.items[group->scanIndex]->group->expanded)) {
- group = group->cl.items[group->scanIndex]->group;
- group->scanIndex = 0;
- continue;
- }
- group->scanIndex++;
- }
- return lastcount;
-}
-
-struct SavedContactState_t {
- MCONTACT hContact;
- WORD iExtraImage[EXTRA_ICON_COUNT];
- int checked;
-};
-
-struct SavedGroupState_t {
- int groupId, expanded;
-};
-
-struct SavedInfoState_t {
- int parentId;
- ClcContact contact;
-};
-
-BOOL LOCK_RECALC_SCROLLBAR = FALSE;
-void cli_SaveStateAndRebuildList(HWND hwnd, ClcData *dat)
-{
- LOCK_RECALC_SCROLLBAR = TRUE;
-
- NMCLISTCONTROL nm;
- int i, j;
- OBJLIST<SavedGroupState_t> savedGroup(4);
- OBJLIST<SavedContactState_t> savedContact(4);
- OBJLIST<SavedInfoState_t> savedInfo(4);
-
- ClcGroup *group;
- ClcContact *contact;
-
- pcli->pfnHideInfoTip(hwnd, dat);
- KillTimer(hwnd, TIMERID_INFOTIP);
- KillTimer(hwnd, TIMERID_RENAME);
- pcli->pfnEndRename(hwnd, dat, 1);
-
- dat->needsResort = 1;
- group = &dat->list;
- group->scanIndex = 0;
- for (;;) {
- if (group->scanIndex == group->cl.count) {
- group = group->parent;
- if (group == NULL)
- break;
- }
- else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
- group = group->cl.items[group->scanIndex]->group;
- group->scanIndex = 0;
-
- SavedGroupState_t* p = new SavedGroupState_t;
- p->groupId = group->groupId;
- p->expanded = group->expanded;
- savedGroup.insert(p);
- continue;
- }
- else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
- SavedContactState_t* p = new SavedContactState_t;
- p->hContact = group->cl.items[group->scanIndex]->hContact;
- memcpy(p->iExtraImage, group->cl.items[group->scanIndex]->iExtraImage, sizeof(p->iExtraImage));
- p->checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED;
- savedContact.insert(p);
- }
- else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) {
- SavedInfoState_t *p = new SavedInfoState_t;
- memset(p, 0, sizeof(SavedInfoState_t));
- if (group->parent == NULL)
- p->parentId = -1;
- else
- p->parentId = group->groupId;
- p->contact = *group->cl.items[group->scanIndex];
- savedInfo.insert(p);
- }
- group->scanIndex++;
- }
-
- pcli->pfnFreeGroup(&dat->list);
- pcli->pfnRebuildEntireList(hwnd, dat);
-
- group = &dat->list;
- group->scanIndex = 0;
- for (;;) {
- if (group->scanIndex == group->cl.count) {
- group = group->parent;
- if (group == NULL)
- break;
- }
- else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
- group = group->cl.items[group->scanIndex]->group;
- group->scanIndex = 0;
- for (i = 0; i < savedGroup.getCount(); i++)
- if (savedGroup[i].groupId == group->groupId) {
- group->expanded = savedGroup[i].expanded;
- break;
- }
- continue;
- }
- else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
- for (i = 0; i < savedContact.getCount(); i++)
- if (savedContact[i].hContact == group->cl.items[group->scanIndex]->hContact) {
- memcpy(group->cl.items[group->scanIndex]->iExtraImage, savedContact[i].iExtraImage, sizeof(contact->iExtraImage));
- if (savedContact[i].checked)
- group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED;
- break;
- }
- }
- group->scanIndex++;
- }
-
- for (i = 0; i < savedInfo.getCount(); i++) {
- if (savedInfo[i].parentId == -1)
- group = &dat->list;
- else {
- if (!pcli->pfnFindItem(hwnd, dat, savedInfo[i].parentId | HCONTACT_ISGROUP, &contact, NULL, NULL))
- continue;
- group = contact->group;
- }
- j = pcli->pfnAddInfoItemToGroup(group, savedInfo[i].contact.flags, _T(""));
- *group->cl.items[j] = savedInfo[i].contact;
- }
-
- LOCK_RECALC_SCROLLBAR = FALSE;
- pcli->pfnRecalculateGroupCheckboxes(hwnd, dat);
-
- pcli->pfnRecalcScrollBar(hwnd, dat);
- nm.hdr.code = CLN_LISTREBUILT;
- nm.hdr.hwndFrom = hwnd;
- nm.hdr.idFrom = GetDlgCtrlID(hwnd);
- SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm);
-}
-
-
-WORD pdnce___GetStatus(ClcCacheEntry *pdnce)
-{
- return (!pdnce) ? ID_STATUS_OFFLINE : pdnce->m_cache_nStatus;
-}
-
-ClcContact* cliCreateClcContact()
-{
- ClcContact* contact = (ClcContact*)mir_calloc(sizeof(ClcContact));
- memset(contact->iExtraImage, 0xFF, sizeof(contact->iExtraImage));
- return contact;
-}
-
-ClcCacheEntry* cliCreateCacheItem(MCONTACT hContact)
-{
- ClcCacheEntry *p = (ClcCacheEntry *)mir_calloc(sizeof(ClcCacheEntry));
- if (p == NULL)
- return NULL;
-
- p->hContact = hContact;
- InvalidateDNCEbyPointer(hContact, p, 0);
- p->szSecondLineText = NULL;
- p->szThirdLineText = NULL;
- p->ssSecondLine.plText = NULL;
- p->ssThirdLine.plText = NULL;
- return p;
-}
-
-void cliInvalidateDisplayNameCacheEntry(MCONTACT hContact)
-{
- if (hContact == INVALID_CONTACT_ID)
- corecli.pfnInvalidateDisplayNameCacheEntry(INVALID_CONTACT_ID);
- else {
- ClcCacheEntry *p = pcli->pfnGetCacheEntry(hContact);
- if (p)
- InvalidateDNCEbyPointer(hContact, p, 0);
- }
-}
-
-void cli_SetContactCheckboxes(ClcContact *cc, int checked)
-{
- corecli.pfnSetContactCheckboxes(cc, checked);
-
- for (int i = 0; i < cc->SubAllocated; i++)
- corecli.pfnSetContactCheckboxes(&cc->subcontacts[i], checked);
-}
-
-char* cli_GetGroupCountsText(ClcData *dat, ClcContact *contact)
-{
- return corecli.pfnGetGroupCountsText(dat, contact);
-}
-
-int cliGetGroupContentsCount(ClcGroup *group, int visibleOnly)
-{
- int count = group->cl.count;
- ClcGroup *topgroup = group;
-
- group->scanIndex = 0;
- for (;;) {
- if (group->scanIndex == group->cl.count) {
- if (group == topgroup)
- break;
- group = group->parent;
- }
- else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (!(visibleOnly & 0x01) || group->cl.items[group->scanIndex]->group->expanded)) {
- group = group->cl.items[group->scanIndex]->group;
- group->scanIndex = 0;
- count += group->cl.count;
- continue;
- }
- else if ((group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) &&
- (group->cl.items[group->scanIndex]->subcontacts != NULL) &&
- ((group->cl.items[group->scanIndex]->SubExpanded || (!visibleOnly)))) {
- count += group->cl.items[group->scanIndex]->SubAllocated;
- }
- group->scanIndex++;
- }
- return count;
-}
-
-/*
-* checks the currently active view mode filter and returns true, if the contact should be hidden
-* if no view mode is active, it returns the CList/Hidden setting
-* also cares about sub contacts (if meta is active)
-*/
-
-int __fastcall CLVM_GetContactHiddenStatus(MCONTACT hContact, char *szProto, ClcData *dat)
-{
- int dbHidden = db_get_b(hContact, "CList", "Hidden", 0); // default hidden state, always respect it.
- int filterResult = 1;
- int searchResult = 0;
- DBVARIANT dbv = { 0 };
- char szTemp[64];
- TCHAR szGroupMask[256];
- DWORD dwLocalMask;
- ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
- BOOL fEmbedded = dat->force_in_dialog;
- // always hide subcontacts (but show them on embedded contact lists)
-
- if (dat != NULL && dat->IsMetaContactsEnabled && db_mc_isSub(hContact))
- return -1; //subcontact
- if (pdnce && pdnce->isUnknown && !fEmbedded)
- return 1; //'Unknown Contact'
- if (dat->filterSearch && dat->szQuickSearch && pdnce->tszName) {
- // search filtering
- TCHAR *lowered_name = CharLowerW(NEWTSTR_ALLOCA(pdnce->tszName));
- TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch));
- searchResult = _tcsstr(lowered_name, lowered_search) ? 0 : 1;
- }
- if (pdnce && g_CluiData.bFilterEffective && !fEmbedded) {
- if (szProto == NULL)
- szProto = GetContactProto(hContact);
- // check stickies first (priority), only if we really have stickies defined (CLVM_STICKY_CONTACTS is set).
- if (g_CluiData.bFilterEffective & CLVM_STICKY_CONTACTS) {
- if ((dwLocalMask = db_get_dw(hContact, CLVM_MODULE, g_CluiData.current_viewmode, 0)) != 0) {
- if (g_CluiData.bFilterEffective & CLVM_FILTER_STICKYSTATUS) {
- WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
- return !((1 << (wStatus - ID_STATUS_OFFLINE)) & HIWORD(dwLocalMask)) | searchResult;
- }
- return 0 | searchResult;
- }
- }
- // check the proto, use it as a base filter result for all further checks
- if (g_CluiData.bFilterEffective & CLVM_FILTER_PROTOS) {
- mir_snprintf(szTemp, SIZEOF(szTemp), "%s|", szProto);
- filterResult = strstr(g_CluiData.protoFilter, szTemp) ? 1 : 0;
- }
- if (g_CluiData.bFilterEffective & CLVM_FILTER_GROUPS) {
- if (!db_get_ts(hContact, "CList", "Group", &dbv)) {
- mir_sntprintf(szGroupMask, SIZEOF(szGroupMask), _T("%s|"), &dbv.ptszVal[0]);
- filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? (filterResult | (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0)) : (filterResult & (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0));
- mir_free(dbv.ptszVal);
- }
- else if (g_CluiData.filterFlags & CLVM_INCLUDED_UNGROUPED)
- filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 1;
- else
- filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 0;
- }
- if (g_CluiData.bFilterEffective & CLVM_FILTER_STATUS) {
- WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
- filterResult = (g_CluiData.filterFlags & CLVM_GROUPSTATUS_OP) ? ((filterResult | ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0))) : (filterResult & ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0));
- }
- if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG) {
- if (pdnce && pdnce->dwLastMsgTime != -1) {
- DWORD now = g_CluiData.t_now;
- now -= g_CluiData.lastMsgFilter;
- if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_OLDERTHAN)
- filterResult = filterResult & (pdnce->dwLastMsgTime < now);
- else if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_NEWERTHAN)
- filterResult = filterResult & (pdnce->dwLastMsgTime > now);
- }
- }
- return (dbHidden | !filterResult | searchResult);
- }
-
- return dbHidden | searchResult;
-}
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
+Copyright (c) 2000-08 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "hdr/modern_commonheaders.h"
+#include "hdr/modern_clc.h"
+#include "hdr/modern_clist.h"
+#include "m_metacontacts.h"
+#include "hdr/modern_commonprototypes.h"
+
+void AddSubcontacts(ClcData *dat, ClcContact *cont, BOOL showOfflineHereGroup)
+{
+ ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(cont->hContact);
+ cont->SubExpanded = (db_get_b(cont->hContact, "CList", "Expanded", 0) && (db_get_b(NULL, "CLC", "MetaExpanding", SETTING_METAEXPANDING_DEFAULT)));
+ int subcount = db_mc_getSubCount(cont->hContact);
+ if (subcount <= 0) {
+ cont->isSubcontact = 0;
+ cont->subcontacts = NULL;
+ cont->SubAllocated = 0;
+ return;
+ }
+
+ cont->isSubcontact = 0;
+ mir_free(cont->subcontacts);
+ cont->subcontacts = (ClcContact *)mir_calloc(sizeof(ClcContact)*subcount);
+ cont->SubAllocated = subcount;
+ int i = 0;
+ int bHideOffline = db_get_b(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
+ for (int j = 0; j < subcount; j++) {
+ MCONTACT hsub = db_mc_getSub(cont->hContact, j);
+ cacheEntry = pcli->pfnGetCacheEntry(hsub);
+ WORD wStatus = pdnce___GetStatus(cacheEntry);
+
+ if (!showOfflineHereGroup && bHideOffline && !cacheEntry->m_cache_nNoHiddenOffline && wStatus == ID_STATUS_OFFLINE)
+ continue;
+
+ ClcContact& p = cont->subcontacts[i];
+ p.hContact = cacheEntry->hContact;
+
+ p.avatar_pos = AVATAR_POS_DONT_HAVE;
+ Cache_GetAvatar(dat, &p);
+
+ p.iImage = corecli.pfnGetContactIcon(cacheEntry->hContact);
+ memset(p.iExtraImage, 0xFF, sizeof(p.iExtraImage));
+ p.proto = cacheEntry->m_cache_cszProto;
+ p.type = CLCIT_CONTACT;
+ p.flags = 0;//CONTACTF_ONLINE;
+ p.isSubcontact = i + 1;
+ p.lastPaintCounter = 0;
+ p.subcontacts = cont;
+ p.image_is_special = FALSE;
+ //p.status = cacheEntry->status;
+ Cache_GetTimezone(dat, (&p)->hContact);
+ Cache_GetText(dat, &p, 1);
+
+ char *szProto = cacheEntry->m_cache_cszProto;
+ if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, wStatus))
+ p.flags |= CONTACTF_ONLINE;
+ int apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0;
+ if (apparentMode == ID_STATUS_OFFLINE) p.flags |= CONTACTF_INVISTO;
+ else if (apparentMode == ID_STATUS_ONLINE) p.flags |= CONTACTF_VISTO;
+ else if (apparentMode) p.flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ if (cacheEntry->NotOnList) p.flags |= CONTACTF_NOTONLIST;
+ int idleMode = szProto != NULL ? cacheEntry->IdleTS : 0;
+ if (idleMode) p.flags |= CONTACTF_IDLE;
+ i++;
+ }
+
+ cont->SubAllocated = i;
+ if (!i && cont->subcontacts != NULL)
+ mir_free_and_nil(cont->subcontacts);
+}
+
+int cli_AddItemToGroup(ClcGroup *group, int iAboveItem)
+{
+ if (group == NULL)
+ return 0;
+
+ iAboveItem = corecli.pfnAddItemToGroup(group, iAboveItem);
+ ClearRowByIndexCache();
+ return iAboveItem;
+}
+
+ClcGroup* cli_AddGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
+{
+ ClearRowByIndexCache();
+ if (!dat->force_in_dialog && !(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN))
+ if (!lstrcmp(_T("-@-HIDDEN-GROUP-@-"), szName)) { //group is hidden
+ ClearRowByIndexCache();
+ return NULL;
+ }
+
+ ClcGroup *result = corecli.pfnAddGroup(hwnd, dat, szName, flags, groupId, calcTotalMembers);
+ ClearRowByIndexCache();
+ return result;
+}
+
+void cli_FreeContact(ClcContact *p)
+{
+ if (p->SubAllocated) {
+ if (p->subcontacts && !p->isSubcontact) {
+ for (int i = 0; i < p->SubAllocated; i++) {
+ p->subcontacts[i].ssText.DestroySmileyList();
+ if (p->subcontacts[i].avatar_pos == AVATAR_POS_ANIMATED)
+ AniAva_RemoveAvatar(p->subcontacts[i].hContact);
+ p->subcontacts[i].avatar_pos = AVATAR_POS_DONT_HAVE;
+ }
+ mir_free_and_nil(p->subcontacts);
+ }
+ }
+
+ p->ssText.DestroySmileyList();
+ if (p->avatar_pos == AVATAR_POS_ANIMATED)
+ AniAva_RemoveAvatar(p->hContact);
+ p->avatar_pos = AVATAR_POS_DONT_HAVE;
+ corecli.pfnFreeContact(p);
+}
+
+void cli_FreeGroup(ClcGroup* group)
+{
+ corecli.pfnFreeGroup(group);
+ ClearRowByIndexCache();
+}
+
+int cli_AddInfoItemToGroup(ClcGroup *group, int flags, const TCHAR *pszText)
+{
+ int i = corecli.pfnAddInfoItemToGroup(group, flags, pszText);
+ ClearRowByIndexCache();
+ return i;
+}
+
+static void _LoadDataToContact(ClcContact *cont, ClcGroup *group, ClcData *dat, MCONTACT hContact)
+{
+ if (!cont)
+ return;
+
+ cont->type = CLCIT_CONTACT;
+ cont->SubAllocated = 0;
+ cont->isSubcontact = 0;
+ cont->subcontacts = NULL;
+ cont->szText[0] = 0;
+ cont->lastPaintCounter = 0;
+ cont->image_is_special = FALSE;
+ cont->hContact = hContact;
+
+ pcli->pfnInvalidateDisplayNameCacheEntry(hContact);
+
+ ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
+ char *szProto = cacheEntry->m_cache_cszProto;
+ cont->proto = szProto;
+
+ if (szProto != NULL && !pcli->pfnIsHiddenMode(dat, pdnce___GetStatus(cacheEntry)))
+ cont->flags |= CONTACTF_ONLINE;
+
+ WORD apparentMode = szProto != NULL ? cacheEntry->ApparentMode : 0;
+
+ if (apparentMode)
+ switch (apparentMode) {
+ case ID_STATUS_OFFLINE:
+ cont->flags |= CONTACTF_INVISTO;
+ break;
+ case ID_STATUS_ONLINE:
+ cont->flags |= CONTACTF_VISTO;
+ break;
+ default:
+ cont->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ }
+
+ if (cacheEntry->NotOnList)
+ cont->flags |= CONTACTF_NOTONLIST;
+
+ DWORD idleMode = szProto != NULL ? cacheEntry->IdleTS : 0;
+ if (idleMode)
+ cont->flags |= CONTACTF_IDLE;
+
+ // Add subcontacts
+ if (szProto)
+ if (dat->IsMetaContactsEnabled && mir_strcmp(cont->proto, META_PROTO) == 0)
+ AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group));
+
+ cont->lastPaintCounter = 0;
+ cont->avatar_pos = AVATAR_POS_DONT_HAVE;
+ Cache_GetAvatar(dat, cont);
+ Cache_GetText(dat, cont, 1);
+ Cache_GetTimezone(dat, cont->hContact);
+ cont->iImage = corecli.pfnGetContactIcon(hContact);
+ cont->bContactRate = db_get_b(hContact, "CList", "Rate", 0);
+}
+
+static ClcContact* AddContactToGroup(ClcData *dat, ClcGroup *group, ClcCacheEntry *cacheEntry)
+{
+ if (cacheEntry == NULL) return NULL;
+ if (group == NULL) return NULL;
+ if (dat == NULL) return NULL;
+ MCONTACT hContact = cacheEntry->hContact;
+ dat->needsResort = 1;
+ int i;
+ for (i = group->cl.count - 1; i >= 0; i--)
+ if (group->cl.items[i]->type != CLCIT_INFO || !(group->cl.items[i]->flags&CLCIIF_BELOWCONTACTS)) break;
+ i = cli_AddItemToGroup(group, i + 1);
+
+ _LoadDataToContact(group->cl.items[i], group, dat, hContact);
+ cacheEntry = pcli->pfnGetCacheEntry(hContact);
+ ClearRowByIndexCache();
+ return group->cl.items[i];
+}
+
+void* AddTempGroup(HWND hwnd, ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
+{
+ int i = 0;
+ int f = 0;
+ DWORD groupFlags;
+
+ if (wildcmp(_T2A(szName), "-@-HIDDEN-GROUP-@-"))
+ return NULL;
+
+ for (i = 1;; i++) {
+ TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL) break;
+ if (!mir_tstrcmpi(szGroupName, szName)) f = 1;
+ }
+
+ if (f)
+ return NULL;
+
+ char buf[20];
+ _itoa_s(i-1, buf, 10);
+
+ TCHAR b2[255];
+ mir_sntprintf(b2, SIZEOF(b2), _T("#%s"), szName);
+ b2[0] = 1 | GROUPF_EXPANDED;
+ db_set_ws(NULL, "CListGroups", buf, b2);
+ pcli->pfnGetGroupName(i, &groupFlags);
+ return cli_AddGroup(hwnd, dat, szName, groupFlags, i, 0);
+}
+
+void cli_AddContactToTree(HWND hwnd, ClcData *dat, MCONTACT hContact, int updateTotalCount, int checkHideOffline)
+{
+ ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
+ if (dat->IsMetaContactsEnabled && cacheEntry && cacheEntry->m_bIsSub)
+ return; //contact should not be added
+
+ if (!dat->IsMetaContactsEnabled && cacheEntry && !mir_strcmp(cacheEntry->m_cache_cszProto, META_PROTO))
+ return;
+
+ corecli.pfnAddContactToTree(hwnd, dat, hContact, updateTotalCount, checkHideOffline);
+
+ ClcGroup *group;
+ ClcContact *cont;
+ if (FindItem(hwnd, dat, hContact, &cont, &group, NULL, FALSE))
+ _LoadDataToContact(cont, group, dat, hContact);
+}
+
+void cli_DeleteItemFromTree(HWND hwnd, MCONTACT hItem)
+{
+ ClcData *dat = (ClcData *)GetWindowLongPtr(hwnd, 0);
+ ClearRowByIndexCache();
+ corecli.pfnDeleteItemFromTree(hwnd, hItem);
+
+ // check here contacts are not resorting
+ if (hwnd == pcli->hwndContactTree)
+ pcli->pfnFreeCacheItem(pcli->pfnGetCacheEntry(hItem));
+ dat->needsResort = 1;
+ ClearRowByIndexCache();
+}
+
+__inline BOOL CLCItems_IsShowOfflineGroup(ClcGroup* group)
+{
+ DWORD groupFlags = 0;
+ if (!group) return FALSE;
+ if (group->hideOffline) return FALSE;
+ pcli->pfnGetGroupName(group->groupId, &groupFlags);
+ return (groupFlags&GROUPF_SHOWOFFLINE) != 0;
+}
+
+MCONTACT SaveSelection(ClcData *dat)
+{
+ ClcContact *selcontact = NULL;
+ if (pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
+ return NULL;
+
+ return (MCONTACT)pcli->pfnContactToHItem(selcontact);
+}
+
+int RestoreSelection(ClcData *dat, MCONTACT hSelected)
+{
+ ClcContact *selcontact = NULL;
+ ClcGroup *selgroup = NULL;
+
+ if (!hSelected || !pcli->pfnFindItem(dat->hWnd, dat, hSelected, &selcontact, &selgroup, NULL)) {
+ dat->selection = -1;
+ return dat->selection;
+ }
+
+ if (!selcontact->isSubcontact)
+ dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact));
+ else {
+ dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact->subcontacts));
+
+ if (dat->selection != -1)
+ dat->selection += selcontact->isSubcontact;
+ }
+ return dat->selection;
+}
+
+void cliRebuildEntireList(HWND hwnd, ClcData *dat)
+{
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ ClcGroup *group;
+ static int rebuildCounter = 0;
+
+ BOOL PlaceOfflineToRoot = db_get_b(NULL, "CList", "PlaceOfflineToRoot", SETTING_PLACEOFFLINETOROOT_DEFAULT);
+ KillTimer(hwnd, TIMERID_REBUILDAFTER);
+
+ ClearRowByIndexCache();
+ ImageArray_Clear(&dat->avatar_cache);
+ RowHeights_Clear(dat);
+ RowHeights_GetMaxRowHeight(dat, hwnd);
+ TRACEVAR("Rebuild Entire List %d times\n", ++rebuildCounter);
+
+ dat->list.expanded = 1;
+ dat->list.hideOffline = db_get_b(NULL, "CLC", "HideOfflineRoot", SETTING_HIDEOFFLINEATROOT_DEFAULT) && style&CLS_USEGROUPS;
+ dat->list.cl.count = dat->list.cl.limit = 0;
+ dat->list.cl.increment = 50;
+ dat->needsResort = 1;
+
+ MCONTACT hSelected = SaveSelection(dat);
+ dat->selection = -1;
+ dat->HiLightMode = db_get_b(NULL, "CLC", "HiLightMode", SETTING_HILIGHTMODE_DEFAULT);
+
+ for (int i = 1;; i++) {
+ DWORD groupFlags;
+ TCHAR *szGroupName = pcli->pfnGetGroupName(i, &groupFlags); //UNICODE
+ if (szGroupName == NULL)
+ break;
+ cli_AddGroup(hwnd, dat, szGroupName, groupFlags, i, 0);
+ }
+
+ for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
+ ClcContact *cont = NULL;
+ ClcCacheEntry *cacheEntry = pcli->pfnGetCacheEntry(hContact);
+
+ int nHiddenStatus = CLVM_GetContactHiddenStatus(hContact, NULL, dat);
+ if ((style & CLS_SHOWHIDDEN && nHiddenStatus != -1) || !nHiddenStatus) {
+ if (lstrlen(cacheEntry->tszGroup) == 0)
+ group = &dat->list;
+ else
+ group = cli_AddGroup(hwnd, dat, cacheEntry->tszGroup, (DWORD)-1, 0, 0);
+
+ if (group != NULL) {
+ WORD wStatus = pdnce___GetStatus(cacheEntry);
+ if (wStatus == ID_STATUS_OFFLINE && PlaceOfflineToRoot)
+ group = &dat->list;
+
+ group->totalMembers++;
+
+ if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ if (cacheEntry->m_cache_cszProto == NULL) {
+ if (!pcli->pfnIsHiddenMode(dat, ID_STATUS_OFFLINE) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group))
+ cont = AddContactToGroup(dat, group, cacheEntry);
+ }
+ else if (!pcli->pfnIsHiddenMode(dat, wStatus) || cacheEntry->m_cache_nNoHiddenOffline || CLCItems_IsShowOfflineGroup(group))
+ cont = AddContactToGroup(dat, group, cacheEntry);
+ }
+ else cont = AddContactToGroup(dat, group, cacheEntry);
+ }
+ }
+ if (cont) {
+ cont->SubAllocated = 0;
+ if (cont->proto && dat->IsMetaContactsEnabled && strcmp(cont->proto, META_PROTO) == 0)
+ AddSubcontacts(dat, cont, CLCItems_IsShowOfflineGroup(group));
+ }
+ }
+
+ if (style & CLS_HIDEEMPTYGROUPS) {
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group->cl.count == 0)
+ group = pcli->pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0);
+ else {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ }
+ continue;
+ }
+ group->scanIndex++;
+ }
+ }
+
+ pcli->pfnSortCLC(hwnd, dat, 0);
+
+ RestoreSelection(dat, hSelected);
+}
+
+void cli_SortCLC(HWND hwnd, ClcData *dat, int useInsertionSort)
+{
+ MCONTACT hSelected = SaveSelection(dat);
+ corecli.pfnSortCLC(hwnd, dat, useInsertionSort);
+ RestoreSelection(dat, hSelected);
+}
+
+int GetNewSelection(ClcGroup *group, int selection, int direction)
+{
+ if (selection < 0)
+ return 0;
+
+ int lastcount = 0, count = 0;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL) break;
+ group->scanIndex++;
+ continue;
+ }
+
+ if (count >= selection)
+ return count;
+
+ lastcount = count;
+ count++;
+ if (!direction && count > selection)
+ return lastcount;
+
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (group->cl.items[group->scanIndex]->group->expanded)) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return lastcount;
+}
+
+struct SavedContactState_t {
+ MCONTACT hContact;
+ WORD iExtraImage[EXTRA_ICON_COUNT];
+ int checked;
+};
+
+struct SavedGroupState_t {
+ int groupId, expanded;
+};
+
+struct SavedInfoState_t {
+ int parentId;
+ ClcContact contact;
+};
+
+BOOL LOCK_RECALC_SCROLLBAR = FALSE;
+void cli_SaveStateAndRebuildList(HWND hwnd, ClcData *dat)
+{
+ LOCK_RECALC_SCROLLBAR = TRUE;
+
+ NMCLISTCONTROL nm;
+ int i, j;
+ OBJLIST<SavedGroupState_t> savedGroup(4);
+ OBJLIST<SavedContactState_t> savedContact(4);
+ OBJLIST<SavedInfoState_t> savedInfo(4);
+
+ ClcGroup *group;
+ ClcContact *contact;
+
+ pcli->pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ pcli->pfnEndRename(hwnd, dat, 1);
+
+ dat->needsResort = 1;
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+
+ SavedGroupState_t* p = new SavedGroupState_t;
+ p->groupId = group->groupId;
+ p->expanded = group->expanded;
+ savedGroup.insert(p);
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ SavedContactState_t* p = new SavedContactState_t;
+ p->hContact = group->cl.items[group->scanIndex]->hContact;
+ memcpy(p->iExtraImage, group->cl.items[group->scanIndex]->iExtraImage, sizeof(p->iExtraImage));
+ p->checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED;
+ savedContact.insert(p);
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) {
+ SavedInfoState_t *p = new SavedInfoState_t;
+ memset(p, 0, sizeof(SavedInfoState_t));
+ if (group->parent == NULL)
+ p->parentId = -1;
+ else
+ p->parentId = group->groupId;
+ p->contact = *group->cl.items[group->scanIndex];
+ savedInfo.insert(p);
+ }
+ group->scanIndex++;
+ }
+
+ pcli->pfnFreeGroup(&dat->list);
+ pcli->pfnRebuildEntireList(hwnd, dat);
+
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ for (i = 0; i < savedGroup.getCount(); i++)
+ if (savedGroup[i].groupId == group->groupId) {
+ group->expanded = savedGroup[i].expanded;
+ break;
+ }
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ for (i = 0; i < savedContact.getCount(); i++)
+ if (savedContact[i].hContact == group->cl.items[group->scanIndex]->hContact) {
+ memcpy(group->cl.items[group->scanIndex]->iExtraImage, savedContact[i].iExtraImage, sizeof(contact->iExtraImage));
+ if (savedContact[i].checked)
+ group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED;
+ break;
+ }
+ }
+ group->scanIndex++;
+ }
+
+ for (i = 0; i < savedInfo.getCount(); i++) {
+ if (savedInfo[i].parentId == -1)
+ group = &dat->list;
+ else {
+ if (!pcli->pfnFindItem(hwnd, dat, savedInfo[i].parentId | HCONTACT_ISGROUP, &contact, NULL, NULL))
+ continue;
+ group = contact->group;
+ }
+ j = pcli->pfnAddInfoItemToGroup(group, savedInfo[i].contact.flags, _T(""));
+ *group->cl.items[j] = savedInfo[i].contact;
+ }
+
+ LOCK_RECALC_SCROLLBAR = FALSE;
+ pcli->pfnRecalculateGroupCheckboxes(hwnd, dat);
+
+ pcli->pfnRecalcScrollBar(hwnd, dat);
+ nm.hdr.code = CLN_LISTREBUILT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm);
+}
+
+
+WORD pdnce___GetStatus(ClcCacheEntry *pdnce)
+{
+ return (!pdnce) ? ID_STATUS_OFFLINE : pdnce->m_cache_nStatus;
+}
+
+ClcContact* cliCreateClcContact()
+{
+ ClcContact* contact = (ClcContact*)mir_calloc(sizeof(ClcContact));
+ memset(contact->iExtraImage, 0xFF, sizeof(contact->iExtraImage));
+ return contact;
+}
+
+ClcCacheEntry* cliCreateCacheItem(MCONTACT hContact)
+{
+ ClcCacheEntry *p = (ClcCacheEntry *)mir_calloc(sizeof(ClcCacheEntry));
+ if (p == NULL)
+ return NULL;
+
+ p->hContact = hContact;
+ InvalidateDNCEbyPointer(hContact, p, 0);
+ p->szSecondLineText = NULL;
+ p->szThirdLineText = NULL;
+ p->ssSecondLine.plText = NULL;
+ p->ssThirdLine.plText = NULL;
+ return p;
+}
+
+void cliInvalidateDisplayNameCacheEntry(MCONTACT hContact)
+{
+ if (hContact == INVALID_CONTACT_ID)
+ corecli.pfnInvalidateDisplayNameCacheEntry(INVALID_CONTACT_ID);
+ else {
+ ClcCacheEntry *p = pcli->pfnGetCacheEntry(hContact);
+ if (p)
+ InvalidateDNCEbyPointer(hContact, p, 0);
+ }
+}
+
+void cli_SetContactCheckboxes(ClcContact *cc, int checked)
+{
+ corecli.pfnSetContactCheckboxes(cc, checked);
+
+ for (int i = 0; i < cc->SubAllocated; i++)
+ corecli.pfnSetContactCheckboxes(&cc->subcontacts[i], checked);
+}
+
+char* cli_GetGroupCountsText(ClcData *dat, ClcContact *contact)
+{
+ return corecli.pfnGetGroupCountsText(dat, contact);
+}
+
+int cliGetGroupContentsCount(ClcGroup *group, int visibleOnly)
+{
+ int count = group->cl.count;
+ ClcGroup *topgroup = group;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ if (group == topgroup)
+ break;
+ group = group->parent;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (!(visibleOnly & 0x01) || group->cl.items[group->scanIndex]->group->expanded)) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ count += group->cl.count;
+ continue;
+ }
+ else if ((group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) &&
+ (group->cl.items[group->scanIndex]->subcontacts != NULL) &&
+ ((group->cl.items[group->scanIndex]->SubExpanded || (!visibleOnly)))) {
+ count += group->cl.items[group->scanIndex]->SubAllocated;
+ }
+ group->scanIndex++;
+ }
+ return count;
+}
+
+/*
+* checks the currently active view mode filter and returns true, if the contact should be hidden
+* if no view mode is active, it returns the CList/Hidden setting
+* also cares about sub contacts (if meta is active)
+*/
+
+int __fastcall CLVM_GetContactHiddenStatus(MCONTACT hContact, char *szProto, ClcData *dat)
+{
+ int dbHidden = db_get_b(hContact, "CList", "Hidden", 0); // default hidden state, always respect it.
+ int filterResult = 1;
+ int searchResult = 0;
+ DBVARIANT dbv = { 0 };
+ char szTemp[64];
+ TCHAR szGroupMask[256];
+ DWORD dwLocalMask;
+ ClcCacheEntry *pdnce = pcli->pfnGetCacheEntry(hContact);
+ // always hide subcontacts (but show them on embedded contact lists)
+
+ if (dat != NULL && dat->IsMetaContactsEnabled && db_mc_isSub(hContact))
+ return -1; //subcontact
+ if (pdnce && pdnce->isUnknown && dat != NULL && !dat->force_in_dialog)
+ return 1; //'Unknown Contact'
+ if (dat != NULL && dat->filterSearch && dat->szQuickSearch && pdnce && pdnce->tszName) {
+ // search filtering
+ TCHAR *lowered_name = CharLowerW(NEWTSTR_ALLOCA(pdnce->tszName));
+ TCHAR *lowered_search = CharLowerW(NEWTSTR_ALLOCA(dat->szQuickSearch));
+ searchResult = _tcsstr(lowered_name, lowered_search) ? 0 : 1;
+ }
+ if (pdnce && g_CluiData.bFilterEffective && dat != NULL && !dat->force_in_dialog) {
+ if (szProto == NULL)
+ szProto = GetContactProto(hContact);
+ // check stickies first (priority), only if we really have stickies defined (CLVM_STICKY_CONTACTS is set).
+ if (g_CluiData.bFilterEffective & CLVM_STICKY_CONTACTS) {
+ if ((dwLocalMask = db_get_dw(hContact, CLVM_MODULE, g_CluiData.current_viewmode, 0)) != 0) {
+ if (g_CluiData.bFilterEffective & CLVM_FILTER_STICKYSTATUS) {
+ WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ return !((1 << (wStatus - ID_STATUS_OFFLINE)) & HIWORD(dwLocalMask)) | searchResult;
+ }
+ return 0 | searchResult;
+ }
+ }
+ // check the proto, use it as a base filter result for all further checks
+ if (g_CluiData.bFilterEffective & CLVM_FILTER_PROTOS) {
+ mir_snprintf(szTemp, SIZEOF(szTemp), "%s|", szProto);
+ filterResult = strstr(g_CluiData.protoFilter, szTemp) ? 1 : 0;
+ }
+ if (g_CluiData.bFilterEffective & CLVM_FILTER_GROUPS) {
+ if (!db_get_ts(hContact, "CList", "Group", &dbv)) {
+ mir_sntprintf(szGroupMask, SIZEOF(szGroupMask), _T("%s|"), &dbv.ptszVal[0]);
+ filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? (filterResult | (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0)) : (filterResult & (_tcsstr(g_CluiData.groupFilter, szGroupMask) ? 1 : 0));
+ mir_free(dbv.ptszVal);
+ }
+ else if (g_CluiData.filterFlags & CLVM_INCLUDED_UNGROUPED)
+ filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 1;
+ else
+ filterResult = (g_CluiData.filterFlags & CLVM_PROTOGROUP_OP) ? filterResult : filterResult & 0;
+ }
+ if (g_CluiData.bFilterEffective & CLVM_FILTER_STATUS) {
+ WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ filterResult = (g_CluiData.filterFlags & CLVM_GROUPSTATUS_OP) ? ((filterResult | ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0))) : (filterResult & ((1 << (wStatus - ID_STATUS_OFFLINE)) & g_CluiData.statusMaskFilter ? 1 : 0));
+ }
+ if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG) {
+ if (pdnce->dwLastMsgTime != -1) {
+ DWORD now = g_CluiData.t_now;
+ now -= g_CluiData.lastMsgFilter;
+ if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_OLDERTHAN)
+ filterResult = filterResult & (pdnce->dwLastMsgTime < now);
+ else if (g_CluiData.bFilterEffective & CLVM_FILTER_LASTMSG_NEWERTHAN)
+ filterResult = filterResult & (pdnce->dwLastMsgTime > now);
+ }
+ }
+ return (dbHidden | !filterResult | searchResult);
+ }
+
+ return dbHidden | searchResult;
+}
diff --git a/plugins/Clist_modern/src/modern_row.cpp b/plugins/Clist_modern/src/modern_row.cpp
index 4916f60d3f..a6bac28ed0 100644
--- a/plugins/Clist_modern/src/modern_row.cpp
+++ b/plugins/Clist_modern/src/modern_row.cpp
@@ -1,761 +1,762 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
-Copyright (c) 2000-08 Miranda ICQ/IM project,
-all portions of this codebase are copyrighted to the people
-listed in contributors.txt.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-Created by Anton Senko aka ZORG , tweaked by Artem Shpynov aka FYR
-*/
-
-#include "hdr/modern_commonheaders.h"
-
-/*
-#include <windows.h>
-#include <commctrl.h>
-#include <stdio.h>
-#include <time.h>
-#include <stddef.h>
-#include <process.h>
-#include <io.h>
-#include <string.h>
-#include <direct.h>
-#include "resource.h"
-#include "hdr/modern_commonheaders.h"
-*/
-#include "hdr/modern_row.h"
-
-//Futher declaration
-void rowCalculateMinSize(ROWCELL* cell);
-void rowEqualize(ROWCELL* cell);
-void rowResetEmptyRects(ROWCELL* cell);
-void rowDeleteTree(ROWCELL* cell);
-////////
-
-
-
-//extern ROWCELL * gl_RowRoot; // Óêàçàòåëü íà êîðíåâîé òýã < contact> â øàáëîíå
-//ROWOBJECTS RowTA; // Ñòðóêòóðà, ÷åðåç êîòîðóþ îñóùåñòâëÿåòñÿ äîñòóï ê ýëåìåíòàì êîíòàêòà.
-// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam
-
-
-// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam
-
-char *tmplbuf; // Áóôåð äëÿ õðàíåíèÿ øàáëîíà â òåêñòîâîì âèäå
-
-ROWCELL *cppInitModernRow(ROWCELL ** tabAccess)
-{
- int fsize;
- int seq = 0;
- ROWCELL * RowRoot = NULL;
- FILE * hFile;
- int i=0;
- if (!db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT)) return NULL;
- tmplbuf = NULL;
- if ( db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT) == 1)
- tmplbuf = db_get_sa(NULL,"ModernData","RowTemplate");
- if (tmplbuf) {
- rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess);
- mir_free(tmplbuf);
- return RowRoot;
- }
- if (hFile = fopen("template.txt", "rb"))
- {
- fsize = _filelength(_fileno(hFile));
- tmplbuf = (char*)malloc(fsize+1);
- ZeroMemory(tmplbuf, fsize+1);
-
- for (i=0; i < fsize; i++) tmplbuf[i] = getc(hFile);
- tmplbuf[i] = 0;
- i=0;
- rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess);
- db_set_s(NULL,"ModernData","RowTemplate",tmplbuf);
- free(tmplbuf);
- fclose(hFile);
- return RowRoot;
- }
- return NULL;
-
-}
-
-void cppDeleteTree(ROWCELL * RowRoot)
-{
- ROWCELL *rc = RowRoot;
- rowDeleteTree(rc);
-}
-
-int cppCalculateRowHeight(ROWCELL *RowRoot)
-{
- RowRoot->h = 0;
- RowRoot->w = 0;
- rowResetEmptyRects(RowRoot);
- rowCalculateMinSize(RowRoot);
- rowEqualize(RowRoot);
- if (RowRoot) return RowRoot->r.bottom;
- return 0;
-}
-void cppCalculateRowItemsPos(ROWCELL *RowRoot, int width)
-{
- rowSizeWithReposition(RowRoot, width);
-}
-
-// rowAddCell
-// Âûäåëÿåò íåîáõîäèìîå êîë-âî äèí. ïàìÿòè äëÿ ñòðóêòóðû ROWCELL
-// è ñâÿçûâàåò åå ñ äåðåâîì îïèñàíèÿ êîíòàêòà
-// link - ïîëå child èëè next, ðîäèòåëüñêîé ñòðóêòóðû ROWCELL
-// cont - òèï êîíòåéíåðà: ñòðîêà, ñòîëáåö èëè êîðíåâîé óçåë
-//
-//
-const ROWCELL * rowAddCell(ROWCELL* &link, int cont)
-{
- link = (ROWCELL*)malloc(sizeof(ROWCELL));
- ZeroMemory(link, sizeof(ROWCELL));
- link->cont = cont;
- return link;
-}
-
-// rowDeleteTree
-// Îñâîáîæäàåò ïàìÿòü çàíÿòóþ äåðåâîì îïèñàíèÿ êîíòàêòà
-// cell - àäðåñ êîðíåâîãî óçëà äåðåâà îïèñàíèÿ êîíòàêòà
-//
-//
-void rowDeleteTree(ROWCELL* cell)
-{
- if (!cell) return;
- if (cell->child)
- rowDeleteTree((ROWCELL*)(cell->child));
- if (cell->next)
- rowDeleteTree((ROWCELL*)(cell->next));
- free(cell);
- cell = NULL;
- return;
-}
-
-// rowParserGetNextWord
-// Âûáèðàåò èç ïîòîêà äàííûõ (ñåé÷àñ ôàéëîâîãî) î÷åðåäíîå ñëîâî.
-// Ñëîâîì ñ÷èòàåòñÿ ïîñëåäîâàòåëüíîñòü ñèìâîëîâ, îãðàíè÷åííàÿ çíàêàìè: SP, < , >, ;, TAB, CR, LF
-// ñèìâîëû îò ; è äî êîíöà ñòðîêè ñ÷èòàþòñÿ êîììåíòàðèåì.
-// NOTE: Äàííàÿ ðåàëèçàöèÿ íå ñîâñåì ïîäõîäèò äëÿ âêëþ÷åíèÿ åå â ModernCL,
-// à ïî ñåìó, òóò íàäî áóäåò ïåðåäåëûâàòü
-// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
-// hbuf - óêàçàòåëü áóôåðà
-//
-//
-char * rowParserGetNextWord(char *tbuf, int &hbuf)
-{
- static char buf[256];
- char ch;
-
- int j = -1;
-
- ZeroMemory(buf, 256);
-
- while(tbuf[hbuf] != 0)
- {
- ch = tbuf[hbuf];
-
- // Remark found
- if (ch == ';')
- {
- if (j >= 0) return buf;
-
- while (tbuf[hbuf] != 10 && tbuf[hbuf] != 13) hbuf++;
- }
-
- // Tag-bracers found
- if (!(ch == '>' && j < 0)) //not single '>' found
- {
- if ((ch == '<' || ch == '>') && j >= 0)
- {
- if (ch == '>')
- {
- if (buf[0] == '/' || buf[0] == '<') buf[++j] = ch;
- hbuf++;
- }
- return buf;
- }
-
- if (ch == ' ' || ch == 9 || ch == 10 || ch == 13 || ch == ';' || ch == '>')
- {
- if (ch == '>')
- {
- buf[++j] = ch;
- hbuf++;
- }
-
- if (j >= 0) return buf; // Word is selected
- }
- else
- buf[++j] = ch;
- }
- hbuf++;
- }
- return NULL;
-}
-
-// rowParserGetParam
-// èùåò è èíòåðïðåòèðóåò ñëîâà â øàáëîíå, çàêëþ÷åííûå ìåæäó òýãàìè
-// cell - óêàçàòåëü íà òåêóùèé èíòåðïðåòèðóåìûé êîíòåéíåð øàáëîíà
-// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
-// hbuf - óêàçàòåëü áóôåðà
-//
-//
-void rowParserGetParam(ROWCELL* &cell, char *tbuf, int &hbuf)
-{
- char * word = rowParserGetNextWord(tbuf, hbuf);
- int param = 0;
-
- if (!_strnicmp(word, "avatar", strlen(word))) param = TC_AVATAR;
- else if (!_strnicmp(word, "text1", strlen(word))) param = TC_TEXT1;
- else if (!_strnicmp(word, "text2", strlen(word))) param = TC_TEXT2;
- else if (!_strnicmp(word, "text3", strlen(word))) param = TC_TEXT3;
- else if (!_strnicmp(word, "status", strlen(word))) param = TC_STATUS;
- else if (!_strnicmp(word, "extra", strlen(word))) param = TC_EXTRA;
- else if (!_strnicmp(word, "extra1", strlen(word))) param = TC_EXTRA1;
- else if (!_strnicmp(word, "extra2", strlen(word))) param = TC_EXTRA2;
- else if (!_strnicmp(word, "extra3", strlen(word))) param = TC_EXTRA3;
- else if (!_strnicmp(word, "extra4", strlen(word))) param = TC_EXTRA4;
- else if (!_strnicmp(word, "extra5", strlen(word))) param = TC_EXTRA5;
- else if (!_strnicmp(word, "extra6", strlen(word))) param = TC_EXTRA6;
- else if (!_strnicmp(word, "extra7", strlen(word))) param = TC_EXTRA7;
- else if (!_strnicmp(word, "extra8", strlen(word))) param = TC_EXTRA8;
- else if (!_strnicmp(word, "extra9", strlen(word))) param = TC_EXTRA9;
- else if (!_strnicmp(word, "time", strlen(word))) param = TC_TIME;
- else if (!_strnicmp(word, "space", strlen(word))) param = TC_SPACE;
- else if (!_strnicmp(word, "fspace", strlen(word))) param = TC_FIXED;
-
- else if (!_strnicmp(word, "left", strlen(word))) param = TC_LEFT;
- else if (!_strnicmp(word, "top", strlen(word))) param = TC_TOP;
- else if (!_strnicmp(word, "vcenter", strlen(word))) param = TC_VCENTER;
- else if (!_strnicmp(word, "hcenter", strlen(word))) param = TC_HCENTER;
- else if (!_strnicmp(word, "right", strlen(word))) param = TC_RIGHT;
- else if (!_strnicmp(word, "bottom", strlen(word))) param = TC_BOTTOM;
-
- else if (!_strnicmp(word, "layer", strlen(word))) cell->layer = TRUE;
-
- else if (!_strnicmp(word, "width", strlen(word))) param = TC_WIDTH;
- else if (!_strnicmp(word, "height", strlen(word))) param = TC_HEIGHT;
-
- else
- {
- hbuf -= (int)strlen(word);
- return;
- }
-
- if (param>TC_TEXT3 && param != TC_SPACE) cell->hasfixed = 1;
-
- switch (param)
- {
- case TC_TEXT1:
- case TC_TEXT2:
- case TC_TEXT3:
- case TC_SPACE:
- cell->sizing = 1;
- case TC_STATUS:
- case TC_AVATAR:
- case TC_EXTRA:
- case TC_EXTRA1:
- case TC_EXTRA2:
- case TC_EXTRA3:
- case TC_EXTRA4:
- case TC_EXTRA5:
- case TC_EXTRA6:
- case TC_EXTRA7:
- case TC_EXTRA8:
- case TC_EXTRA9:
- case TC_TIME:
- case TC_FIXED:
-
- cell->type = param;
- break;
-
- case TC_HCENTER:
- case TC_RIGHT:
- cell->halign = param;
- break;
-
- case TC_VCENTER:
- case TC_BOTTOM:
- cell->valign = param;
- break;
-
- case TC_WIDTH:
- word = rowParserGetNextWord(tbuf, hbuf);
- param = atoi(word);
- cell->w = param;
- break;
-
- case TC_HEIGHT:
- word = rowParserGetNextWord(tbuf, hbuf);
- param = atoi(word);
- cell->h = param;
- }
-
- rowParserGetParam(cell, tbuf, hbuf);
- return;
-}
-// rowParse
-// Èùåò â øàáëîíå òåãè < contact>, < tr> è < tc>, è äîáàâëÿåò ñîîòâåòñòâóþùèå óçëû
-// â äåðåâî îïèñàíèÿ êîíòàêòà
-// cell - ïîëå child èëè next ðîäèòåëüñêîãî êîíòåéíåðà
-// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð
-// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
-// hbuf - óêàçàòåëü áóôåðà
-// sequence - íóæíî çàäàâàòü 0, ýòî î÷åðåäíîñòü íàõîæäåíèÿ
-//
-BOOL rowParse(ROWCELL* &cell, ROWCELL* parent, char *tbuf, int &hbuf, int &sequence, ROWCELL** RowTabAccess )
-{
- char * word;
- word = rowParserGetNextWord(tbuf, hbuf);
- int cont;
-
- if (!_strnicmp(word, "<tr", strlen(word)) || !_strnicmp(word, "<tr>", strlen(word))) cont = TC_ROW;
- else if (!_strnicmp(word, "<tc", strlen(word)) || !_strnicmp(word, "<tc>", strlen(word))) cont = TC_COL;
- else if (!_strnicmp(word, "/>", strlen(word)) ||
- !_strnicmp(word, "</tr>", strlen(word)) ||
- !_strnicmp(word, "</tc>", strlen(word))) return TRUE;
- else return FALSE;
-
- rowAddCell(cell, cont);
- rowParserGetParam(cell, tbuf, hbuf);
- if (cell->type != 0 && cell->type != TC_SPACE && cell->type != TC_FIXED)
- RowTabAccess[sequence++] = cell;
-
- if (!rowParse(cell->child, cell, tbuf, hbuf, sequence,RowTabAccess))
- return FALSE;
-
- if (!parent)
- {
- RowTabAccess[sequence] = NULL;
- return TRUE;
- }
-
- if (!rowParse(cell->next, parent, tbuf, hbuf, sequence,RowTabAccess))
- return FALSE;
-
- parent->sizing |= cell->sizing;
- parent->hasfixed |= cell->hasfixed;
- return TRUE;
-}
-
-void rowResetEmptyRects(ROWCELL* cell)
-{
- if (!cell) return;
- if (cell->type == 0)
- {
- SetRect(&(cell->r), 0, 0, 0, 0);
- cell->full_width = 0;
- cell->fixed_width = 0;
- }
- rowResetEmptyRects(cell->child);
- rowResetEmptyRects(cell->next);
-}
-
-// rowCalculateMinSize
-// Âû÷èñëåíèå ìèíèìàëüíûõ ðàçìåðîâ êàæäîãî êîíòåéíåðà äåðåâà îïèñàíèÿ êîíòàêòà
-// Ýòà ôó-ÿ ÂÑÅÃÄÀ! äîëæíà âûçûâàòüñÿ íåïîñðåäñòâåííî ïåðåä rowPositioning
-// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
-// NOTE: Ïåðåä âûçûâîì rowCalculateMinSize íåîáõîäèìî çàïîëíèòü ïîëÿ w è h ñòðóêòóðû RowTA, äëÿ êàæäîãî ýëåìåíòà
-//
-void rowCalculateMinSize(ROWCELL* cell)
-{
- ROWCELL* curchild = NULL;
- int w = 0, h = 0;
- int wl = 0, hl = 0;
- int fullWidth = 0;
- if (!cell) return;
-
- cell->r.left = 0;
- cell->r.top = 0;
-
- if (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE)
- cell->r.right = cell->w;
- else
- cell->r.right = 0;
-
- cell->r.bottom = cell->h;
-
- rowCalculateMinSize(cell->child);
- rowCalculateMinSize(cell->next);
-
- if (!(curchild = cell->child)) return;
-
- if (cell->cont == TC_ROW)
- {
- do
- {
- h = max(h, curchild->r.bottom);
-
- if (curchild->layer)
- {
- //w = max(w, curchild->r.right);
- wl += curchild->r.right;
- fullWidth = max(fullWidth,max(curchild->full_width,curchild->w));
- }
- else
- {
- w += curchild->r.right;
- fullWidth += max(curchild->full_width,curchild->w);
- }
- }
- while (curchild = curchild->next);
- }
-
- if (cell->cont == TC_COL)
- {
- while (curchild)
- {
- w = max(w, curchild->r.right);
- fullWidth = max(fullWidth,max(curchild->full_width,curchild->w));
-
- if (curchild->layer)
- {
- hl = curchild->r.bottom;
- // h = max(h, curchild->r.bottom);
- }
- else
- h += curchild->r.bottom;
-
- curchild = curchild->next;
- }
- }
-
- cell->r.right = max(max(w, cell->r.right),wl);
- cell->r.bottom = max(max(h, cell->r.bottom),hl);
- cell->full_width = max(fullWidth,cell->full_width);
- cell->fixed_width = max(cell->fixed_width,cell->r.right);
- return;
-}
-
-// void rowEqualise(ROWCELL* cell)
-//
-// Óðàâíèâàåò âûñîòû äåòåé âíóòðè ñòðîê, è øèðèíû äåòåé âíóòðè ñòîáöîâ
-// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
-//
-void rowEqualize(ROWCELL* cell)
-{
- ROWCELL* curchild = NULL;
- if (!cell) return;
- rowEqualize(cell->child);
- rowEqualize(cell->next);
-
- if (!(curchild = cell->child)) return;
-
- if (cell->cont == TC_ROW)
- {
- do
- {
- if (curchild->layer) continue;
- curchild->r.bottom = cell->r.bottom;
- }
- while (curchild = curchild->next);
- }
-
- if (cell->cont == TC_COL)
- {
- do
- {
- if (curchild->layer) continue;
- curchild->r.right = cell->r.right;
- }
- while (curchild = curchild->next);
- }
-
-
- //rowEqualize(cell->child);
- //rowEqualize(cell->next);
-}
-
-// void rowPlacing(pttCell cell, pttCell parent)
-//
-// Ïîçèöèîíèðóåò ýëåìåíò ñòðîêè êîíòàêòà â åãî êîíòåéíåðå
-// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð
-//
-void rowPlacing(pROWCELL cell)
-{
- if (cell->type == 0) return;
-
- switch(cell->type)
- {
- case TC_TEXT1:
- case TC_TEXT2:
- case TC_TEXT3:
- case TC_SPACE:
- cell->r.right += cell->r.left;
- break;
- default:
- {
- switch(cell->halign)
- {
- case TC_LEFT:
- break;
- case TC_HCENTER:
- cell->r.left += (cell->r.right - cell->w)/2;
- break;
- case TC_RIGHT:
- cell->r.left += cell->r.right - cell->w;
- }
- cell->r.right = cell->r.left + cell->w;
- }
- }
-
- switch(cell->valign)
- {
- case TC_TOP:
- break;
- case TC_VCENTER:
- cell->r.top += (cell->r.bottom - cell->h)/2;
- break;
- case TC_BOTTOM:
- cell->r.top += cell->r.bottom - cell->h;
- }
- cell->r.bottom = cell->r.top + cell->h;
-}
-
-// void ttTLProc(pROWCELL cell, pROWCELL parent)
-//
-// Ïîçèöèîíèðóåò ïëàâàþùèé êîíòåéíåð, âíóòðè ðîäèòåëüñêîãî
-// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð
-// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð
-//
-void rowLayerProc(pROWCELL cell, pROWCELL parent)
-{
- if (cell->sizing)
- {
- cell->r.left = parent->r.left;
- //cell->r.right += cell->r.left;
- }
- else
- {
- switch(cell->halign)
- {
- case TC_LEFT:
- cell->r.left = parent->r.left;
- break;
- case TC_HCENTER:
- cell->r.left = parent->r.left + (parent->r.right - cell->r.right)/2;
- break;
- case TC_RIGHT:
- cell->r.left = parent->r.left + parent->r.right - cell->r.right;
- }
- }
-
- switch(cell->valign)
- {
- case TC_TOP:
- cell->r.top = parent->r.top;
- break;
- case TC_VCENTER:
- cell->r.top = parent->r.top + (parent->r.bottom - cell->r.bottom)/2;
- break;
- case TC_BOTTOM:
- cell->r.top = parent->r.top + parent->r.bottom - cell->r.bottom;
- break;
- }
-}
-
-// void rowPositioning(pROWCELL cell, int &dist)
-//
-// Âû÷èñëÿåò ïðÿìîóãîëüíèêè ýëåìåíòîâ êîíòàêòà, ó÷èòûâàÿ âûðàâíèâàíèå â êîíòåéíåðå
-// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
-// dist - íîâàÿ øèðèíà êîíòàêòà
-//
-void rowPositioning(pROWCELL cell, int &dist)
-{
- ROWCELL* curchild = NULL;
-
- int x = cell->r.left;
- int y = cell->r.top;
-
- int h = cell->r.bottom;
- int w = dist;
-
- int r = 0;
- int size = 0;
- int cw = 0;
- int fixedsized = 0;
- int autosized = 0;
- int dummy = 0;
-
- // Êîðððåêòèðîâêà íàçíà÷àåìîé øèðèíû dist
- if (w < cell->r.right && (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE) || !cell->sizing)
- dist = w = cell->r.right;
-
- cell->r.right = dist;
- dummy = dist;
- if (!(curchild = cell->child))
- {
- rowPlacing(cell);
- return;
- }
-
- // Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòðîêå
- if (cell->cont == TC_ROW)
- {
- fixedsized = cell->fixed_width;
- while (curchild)
- {
- // Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tc
- if (curchild->layer)
- {
- curchild = curchild->next;
- continue;
- }
-
- cw += curchild->r.right;
-
- if (curchild->sizing)
- {
- autosized += max(curchild->w,curchild->full_width);
- r++;
- }
- else
- size += curchild->r.right;
-
- curchild = curchild->next;
- }
-
- w -= size;
- fixedsized -= size;
-
- if (r == 0)
- {
- switch(cell->halign)
- {
- case TC_HCENTER:
- x += (dist - cw)/2;// - 1;
- break;
- case TC_RIGHT:
- x += dist - cw;
- break;
- }
- }
-
-
- curchild = cell->child;
-
- size = 0;
- while(curchild)
- {
- if (curchild->layer)
- {
- //int dummy = 0;
- rowLayerProc(curchild, cell);
- rowPositioning(curchild, dummy);
- }
- else
- {
- curchild->r.top = cell->r.top;
- curchild->r.left = x;
-
-
- w -= size;
- if (curchild->sizing)
- {
- size = w;
- r--;
- }
- else
- size = curchild->r.right;
-
- rowPositioning(curchild, size);
- x += size;
-
- if (!curchild->sizing)
- size = 0;
- }
-
- curchild = curchild->next;
- }
- }
-
- // Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòîëáöå
- if (cell->cont == TC_COL)
- {
- while (curchild)
- {
- // Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tr
- if (curchild->layer)
- {
- curchild = curchild->next;
- continue;
- }
-
- size += curchild->r.bottom;
- curchild = curchild->next;
- }
-
- if (h > size)
- {
- switch(cell->valign)
- {
- case TC_VCENTER:
- y += (h - size) / 2;
- break;
- case TC_BOTTOM:
- y += (h - size);
- break;
- }
- }
-
- curchild = cell->child;
- while(curchild)
- {
- if (curchild->layer)
- {
- rowLayerProc(curchild, cell);
- rowPositioning(curchild, dummy);
- }
- else
- {
- curchild->r.top = y;
- y += curchild->r.bottom;
-
- curchild->r.left = cell->r.left;
- curchild->r.right = dist;
-
- rowPositioning(curchild, size);
-
- }
-
- curchild = curchild->next;
- }
- }
-
- rowPlacing(cell);
-
-}
-
-// void rowSizeWithReposition(ROWCELL* &root, int width)
-//
-// Ïðîèçâîäèò ïðîñ÷åò è ïîçèöèîíèðîâàíèå ýëåìåíòîâ êîòàêòà
-// Ïåðåä âûçîâîì íåîáõîäèìî çàïîëíèòü ñòðóêòóðó RowTA
-//
-void rowSizeWithReposition(ROWCELL* &root, int width)
-{
- root->h = 0;
- root->w = 0;
- rowCalculateMinSize(root);
- rowEqualize(root);
- rowPositioning(root, width);
- root->h = root->r.bottom;
- root->w = root->r.right;
-}
-
-#undef _CPPCODE
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
+Copyright (c) 2000-08 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Created by Anton Senko aka ZORG , tweaked by Artem Shpynov aka FYR
+*/
+
+#include "hdr/modern_commonheaders.h"
+
+/*
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <string.h>
+#include <direct.h>
+#include "resource.h"
+#include "hdr/modern_commonheaders.h"
+*/
+#include "hdr/modern_row.h"
+
+//Futher declaration
+void rowCalculateMinSize(ROWCELL* cell);
+void rowEqualize(ROWCELL* cell);
+void rowResetEmptyRects(ROWCELL* cell);
+void rowDeleteTree(ROWCELL* cell);
+////////
+
+
+
+//extern ROWCELL * gl_RowRoot; // Óêàçàòåëü íà êîðíåâîé òýã < contact> â øàáëîíå
+//ROWOBJECTS RowTA; // Ñòðóêòóðà, ÷åðåç êîòîðóþ îñóùåñòâëÿåòñÿ äîñòóï ê ýëåìåíòàì êîíòàêòà.
+// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam
+
+
+// Ôîðìèðóåòñÿ ïðè âûïîëíåíèè ôó-è RowParce. Íåÿâíûé ïàðàìåòð ôóè rowParserGetParam
+
+char *tmplbuf; // Áóôåð äëÿ õðàíåíèÿ øàáëîíà â òåêñòîâîì âèäå
+
+ROWCELL *cppInitModernRow(ROWCELL ** tabAccess)
+{
+ int fsize;
+ int seq = 0;
+ ROWCELL * RowRoot = NULL;
+ FILE * hFile;
+ int i=0;
+ if (!db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT)) return NULL;
+ tmplbuf = NULL;
+ if ( db_get_b(NULL,"ModernData","UseAdvancedRowLayout",SETTING_ROW_ADVANCEDLAYOUT_DEFAULT) == 1)
+ tmplbuf = db_get_sa(NULL,"ModernData","RowTemplate");
+ if (tmplbuf) {
+ rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess);
+ mir_free(tmplbuf);
+ return RowRoot;
+ }
+ if (hFile = fopen("template.txt", "rb"))
+ {
+ fsize = _filelength(_fileno(hFile));
+ tmplbuf = (char*)malloc(fsize+1);
+ ZeroMemory(tmplbuf, fsize+1);
+
+ for (i=0; i < fsize; i++) tmplbuf[i] = getc(hFile);
+ tmplbuf[i] = 0;
+ i=0;
+ rowParse(RowRoot, RowRoot, tmplbuf, i, seq,tabAccess);
+ db_set_s(NULL,"ModernData","RowTemplate",tmplbuf);
+ free(tmplbuf);
+ fclose(hFile);
+ return RowRoot;
+ }
+ return NULL;
+
+}
+
+void cppDeleteTree(ROWCELL * RowRoot)
+{
+ ROWCELL *rc = RowRoot;
+ rowDeleteTree(rc);
+}
+
+int cppCalculateRowHeight(ROWCELL *RowRoot)
+{
+ if (RowRoot == NULL)
+ return 0;
+ RowRoot->h = 0;
+ RowRoot->w = 0;
+ rowResetEmptyRects(RowRoot);
+ rowCalculateMinSize(RowRoot);
+ rowEqualize(RowRoot);
+ return RowRoot->r.bottom;
+}
+void cppCalculateRowItemsPos(ROWCELL *RowRoot, int width)
+{
+ rowSizeWithReposition(RowRoot, width);
+}
+
+// rowAddCell
+// Âûäåëÿåò íåîáõîäèìîå êîë-âî äèí. ïàìÿòè äëÿ ñòðóêòóðû ROWCELL
+// è ñâÿçûâàåò åå ñ äåðåâîì îïèñàíèÿ êîíòàêòà
+// link - ïîëå child èëè next, ðîäèòåëüñêîé ñòðóêòóðû ROWCELL
+// cont - òèï êîíòåéíåðà: ñòðîêà, ñòîëáåö èëè êîðíåâîé óçåë
+//
+//
+const ROWCELL * rowAddCell(ROWCELL* &link, int cont)
+{
+ link = (ROWCELL*)malloc(sizeof(ROWCELL));
+ ZeroMemory(link, sizeof(ROWCELL));
+ link->cont = cont;
+ return link;
+}
+
+// rowDeleteTree
+// Îñâîáîæäàåò ïàìÿòü çàíÿòóþ äåðåâîì îïèñàíèÿ êîíòàêòà
+// cell - àäðåñ êîðíåâîãî óçëà äåðåâà îïèñàíèÿ êîíòàêòà
+//
+//
+void rowDeleteTree(ROWCELL* cell)
+{
+ if (!cell) return;
+ if (cell->child)
+ rowDeleteTree((ROWCELL*)(cell->child));
+ if (cell->next)
+ rowDeleteTree((ROWCELL*)(cell->next));
+ free(cell);
+ cell = NULL;
+ return;
+}
+
+// rowParserGetNextWord
+// Âûáèðàåò èç ïîòîêà äàííûõ (ñåé÷àñ ôàéëîâîãî) î÷åðåäíîå ñëîâî.
+// Ñëîâîì ñ÷èòàåòñÿ ïîñëåäîâàòåëüíîñòü ñèìâîëîâ, îãðàíè÷åííàÿ çíàêàìè: SP, < , >, ;, TAB, CR, LF
+// ñèìâîëû îò ; è äî êîíöà ñòðîêè ñ÷èòàþòñÿ êîììåíòàðèåì.
+// NOTE: Äàííàÿ ðåàëèçàöèÿ íå ñîâñåì ïîäõîäèò äëÿ âêëþ÷åíèÿ åå â ModernCL,
+// à ïî ñåìó, òóò íàäî áóäåò ïåðåäåëûâàòü
+// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
+// hbuf - óêàçàòåëü áóôåðà
+//
+//
+char * rowParserGetNextWord(char *tbuf, int &hbuf)
+{
+ static char buf[256];
+ char ch;
+
+ int j = -1;
+
+ ZeroMemory(buf, 256);
+
+ while(tbuf[hbuf] != 0)
+ {
+ ch = tbuf[hbuf];
+
+ // Remark found
+ if (ch == ';')
+ {
+ if (j >= 0) return buf;
+
+ while (tbuf[hbuf] != 10 && tbuf[hbuf] != 13) hbuf++;
+ }
+
+ // Tag-bracers found
+ if (!(ch == '>' && j < 0)) //not single '>' found
+ {
+ if ((ch == '<' || ch == '>') && j >= 0)
+ {
+ if (ch == '>')
+ {
+ if (buf[0] == '/' || buf[0] == '<') buf[++j] = ch;
+ hbuf++;
+ }
+ return buf;
+ }
+
+ if (ch == ' ' || ch == 9 || ch == 10 || ch == 13 || ch == ';' || ch == '>')
+ {
+ if (ch == '>')
+ {
+ buf[++j] = ch;
+ hbuf++;
+ }
+
+ if (j >= 0) return buf; // Word is selected
+ }
+ else
+ buf[++j] = ch;
+ }
+ hbuf++;
+ }
+ return NULL;
+}
+
+// rowParserGetParam
+// èùåò è èíòåðïðåòèðóåò ñëîâà â øàáëîíå, çàêëþ÷åííûå ìåæäó òýãàìè
+// cell - óêàçàòåëü íà òåêóùèé èíòåðïðåòèðóåìûé êîíòåéíåð øàáëîíà
+// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
+// hbuf - óêàçàòåëü áóôåðà
+//
+//
+void rowParserGetParam(ROWCELL* &cell, char *tbuf, int &hbuf)
+{
+ char * word = rowParserGetNextWord(tbuf, hbuf);
+ int param = 0;
+
+ if (!_strnicmp(word, "avatar", strlen(word))) param = TC_AVATAR;
+ else if (!_strnicmp(word, "text1", strlen(word))) param = TC_TEXT1;
+ else if (!_strnicmp(word, "text2", strlen(word))) param = TC_TEXT2;
+ else if (!_strnicmp(word, "text3", strlen(word))) param = TC_TEXT3;
+ else if (!_strnicmp(word, "status", strlen(word))) param = TC_STATUS;
+ else if (!_strnicmp(word, "extra", strlen(word))) param = TC_EXTRA;
+ else if (!_strnicmp(word, "extra1", strlen(word))) param = TC_EXTRA1;
+ else if (!_strnicmp(word, "extra2", strlen(word))) param = TC_EXTRA2;
+ else if (!_strnicmp(word, "extra3", strlen(word))) param = TC_EXTRA3;
+ else if (!_strnicmp(word, "extra4", strlen(word))) param = TC_EXTRA4;
+ else if (!_strnicmp(word, "extra5", strlen(word))) param = TC_EXTRA5;
+ else if (!_strnicmp(word, "extra6", strlen(word))) param = TC_EXTRA6;
+ else if (!_strnicmp(word, "extra7", strlen(word))) param = TC_EXTRA7;
+ else if (!_strnicmp(word, "extra8", strlen(word))) param = TC_EXTRA8;
+ else if (!_strnicmp(word, "extra9", strlen(word))) param = TC_EXTRA9;
+ else if (!_strnicmp(word, "time", strlen(word))) param = TC_TIME;
+ else if (!_strnicmp(word, "space", strlen(word))) param = TC_SPACE;
+ else if (!_strnicmp(word, "fspace", strlen(word))) param = TC_FIXED;
+
+ else if (!_strnicmp(word, "left", strlen(word))) param = TC_LEFT;
+ else if (!_strnicmp(word, "top", strlen(word))) param = TC_TOP;
+ else if (!_strnicmp(word, "vcenter", strlen(word))) param = TC_VCENTER;
+ else if (!_strnicmp(word, "hcenter", strlen(word))) param = TC_HCENTER;
+ else if (!_strnicmp(word, "right", strlen(word))) param = TC_RIGHT;
+ else if (!_strnicmp(word, "bottom", strlen(word))) param = TC_BOTTOM;
+
+ else if (!_strnicmp(word, "layer", strlen(word))) cell->layer = TRUE;
+
+ else if (!_strnicmp(word, "width", strlen(word))) param = TC_WIDTH;
+ else if (!_strnicmp(word, "height", strlen(word))) param = TC_HEIGHT;
+
+ else
+ {
+ hbuf -= (int)strlen(word);
+ return;
+ }
+
+ if (param>TC_TEXT3 && param != TC_SPACE) cell->hasfixed = 1;
+
+ switch (param)
+ {
+ case TC_TEXT1:
+ case TC_TEXT2:
+ case TC_TEXT3:
+ case TC_SPACE:
+ cell->sizing = 1;
+ case TC_STATUS:
+ case TC_AVATAR:
+ case TC_EXTRA:
+ case TC_EXTRA1:
+ case TC_EXTRA2:
+ case TC_EXTRA3:
+ case TC_EXTRA4:
+ case TC_EXTRA5:
+ case TC_EXTRA6:
+ case TC_EXTRA7:
+ case TC_EXTRA8:
+ case TC_EXTRA9:
+ case TC_TIME:
+ case TC_FIXED:
+
+ cell->type = param;
+ break;
+
+ case TC_HCENTER:
+ case TC_RIGHT:
+ cell->halign = param;
+ break;
+
+ case TC_VCENTER:
+ case TC_BOTTOM:
+ cell->valign = param;
+ break;
+
+ case TC_WIDTH:
+ word = rowParserGetNextWord(tbuf, hbuf);
+ param = atoi(word);
+ cell->w = param;
+ break;
+
+ case TC_HEIGHT:
+ word = rowParserGetNextWord(tbuf, hbuf);
+ param = atoi(word);
+ cell->h = param;
+ }
+
+ rowParserGetParam(cell, tbuf, hbuf);
+ return;
+}
+// rowParse
+// Èùåò â øàáëîíå òåãè < contact>, < tr> è < tc>, è äîáàâëÿåò ñîîòâåòñòâóþùèå óçëû
+// â äåðåâî îïèñàíèÿ êîíòàêòà
+// cell - ïîëå child èëè next ðîäèòåëüñêîãî êîíòåéíåðà
+// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð
+// tbuf - óêàçàòåëü íà áóôåð ñîäåðæàùèé òåêñò øàáëîíà
+// hbuf - óêàçàòåëü áóôåðà
+// sequence - íóæíî çàäàâàòü 0, ýòî î÷åðåäíîñòü íàõîæäåíèÿ
+//
+BOOL rowParse(ROWCELL* &cell, ROWCELL* parent, char *tbuf, int &hbuf, int &sequence, ROWCELL** RowTabAccess )
+{
+ char * word;
+ word = rowParserGetNextWord(tbuf, hbuf);
+ int cont;
+
+ if (!_strnicmp(word, "<tr", strlen(word)) || !_strnicmp(word, "<tr>", strlen(word))) cont = TC_ROW;
+ else if (!_strnicmp(word, "<tc", strlen(word)) || !_strnicmp(word, "<tc>", strlen(word))) cont = TC_COL;
+ else if (!_strnicmp(word, "/>", strlen(word)) ||
+ !_strnicmp(word, "</tr>", strlen(word)) ||
+ !_strnicmp(word, "</tc>", strlen(word))) return TRUE;
+ else return FALSE;
+
+ rowAddCell(cell, cont);
+ rowParserGetParam(cell, tbuf, hbuf);
+ if (cell->type != 0 && cell->type != TC_SPACE && cell->type != TC_FIXED)
+ RowTabAccess[sequence++] = cell;
+
+ if (!rowParse(cell->child, cell, tbuf, hbuf, sequence,RowTabAccess))
+ return FALSE;
+
+ if (!parent)
+ {
+ RowTabAccess[sequence] = NULL;
+ return TRUE;
+ }
+
+ if (!rowParse(cell->next, parent, tbuf, hbuf, sequence,RowTabAccess))
+ return FALSE;
+
+ parent->sizing |= cell->sizing;
+ parent->hasfixed |= cell->hasfixed;
+ return TRUE;
+}
+
+void rowResetEmptyRects(ROWCELL* cell)
+{
+ if (!cell) return;
+ if (cell->type == 0)
+ {
+ SetRect(&(cell->r), 0, 0, 0, 0);
+ cell->full_width = 0;
+ cell->fixed_width = 0;
+ }
+ rowResetEmptyRects(cell->child);
+ rowResetEmptyRects(cell->next);
+}
+
+// rowCalculateMinSize
+// Âû÷èñëåíèå ìèíèìàëüíûõ ðàçìåðîâ êàæäîãî êîíòåéíåðà äåðåâà îïèñàíèÿ êîíòàêòà
+// Ýòà ôó-ÿ ÂÑÅÃÄÀ! äîëæíà âûçûâàòüñÿ íåïîñðåäñòâåííî ïåðåä rowPositioning
+// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
+// NOTE: Ïåðåä âûçûâîì rowCalculateMinSize íåîáõîäèìî çàïîëíèòü ïîëÿ w è h ñòðóêòóðû RowTA, äëÿ êàæäîãî ýëåìåíòà
+//
+void rowCalculateMinSize(ROWCELL* cell)
+{
+ ROWCELL* curchild = NULL;
+ int w = 0, h = 0;
+ int wl = 0, hl = 0;
+ int fullWidth = 0;
+ if (!cell) return;
+
+ cell->r.left = 0;
+ cell->r.top = 0;
+
+ if (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE)
+ cell->r.right = cell->w;
+ else
+ cell->r.right = 0;
+
+ cell->r.bottom = cell->h;
+
+ rowCalculateMinSize(cell->child);
+ rowCalculateMinSize(cell->next);
+
+ if (!(curchild = cell->child)) return;
+
+ if (cell->cont == TC_ROW)
+ {
+ do
+ {
+ h = max(h, curchild->r.bottom);
+
+ if (curchild->layer)
+ {
+ //w = max(w, curchild->r.right);
+ wl += curchild->r.right;
+ fullWidth = max(fullWidth,max(curchild->full_width,curchild->w));
+ }
+ else
+ {
+ w += curchild->r.right;
+ fullWidth += max(curchild->full_width,curchild->w);
+ }
+ }
+ while (curchild = curchild->next);
+ }
+
+ if (cell->cont == TC_COL)
+ {
+ while (curchild)
+ {
+ w = max(w, curchild->r.right);
+ fullWidth = max(fullWidth,max(curchild->full_width,curchild->w));
+
+ if (curchild->layer)
+ {
+ hl = curchild->r.bottom;
+ // h = max(h, curchild->r.bottom);
+ }
+ else
+ h += curchild->r.bottom;
+
+ curchild = curchild->next;
+ }
+ }
+
+ cell->r.right = max(max(w, cell->r.right),wl);
+ cell->r.bottom = max(max(h, cell->r.bottom),hl);
+ cell->full_width = max(fullWidth,cell->full_width);
+ cell->fixed_width = max(cell->fixed_width,cell->r.right);
+ return;
+}
+
+// void rowEqualise(ROWCELL* cell)
+//
+// Óðàâíèâàåò âûñîòû äåòåé âíóòðè ñòðîê, è øèðèíû äåòåé âíóòðè ñòîáöîâ
+// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
+//
+void rowEqualize(ROWCELL* cell)
+{
+ ROWCELL* curchild = NULL;
+ if (!cell) return;
+ rowEqualize(cell->child);
+ rowEqualize(cell->next);
+
+ if (!(curchild = cell->child)) return;
+
+ if (cell->cont == TC_ROW)
+ {
+ do
+ {
+ if (curchild->layer) continue;
+ curchild->r.bottom = cell->r.bottom;
+ }
+ while (curchild = curchild->next);
+ }
+
+ if (cell->cont == TC_COL)
+ {
+ do
+ {
+ if (curchild->layer) continue;
+ curchild->r.right = cell->r.right;
+ }
+ while (curchild = curchild->next);
+ }
+
+
+ //rowEqualize(cell->child);
+ //rowEqualize(cell->next);
+}
+
+// void rowPlacing(pttCell cell, pttCell parent)
+//
+// Ïîçèöèîíèðóåò ýëåìåíò ñòðîêè êîíòàêòà â åãî êîíòåéíåðå
+// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð
+//
+void rowPlacing(pROWCELL cell)
+{
+ if (cell->type == 0) return;
+
+ switch(cell->type)
+ {
+ case TC_TEXT1:
+ case TC_TEXT2:
+ case TC_TEXT3:
+ case TC_SPACE:
+ cell->r.right += cell->r.left;
+ break;
+ default:
+ {
+ switch(cell->halign)
+ {
+ case TC_LEFT:
+ break;
+ case TC_HCENTER:
+ cell->r.left += (cell->r.right - cell->w)/2;
+ break;
+ case TC_RIGHT:
+ cell->r.left += cell->r.right - cell->w;
+ }
+ cell->r.right = cell->r.left + cell->w;
+ }
+ }
+
+ switch(cell->valign)
+ {
+ case TC_TOP:
+ break;
+ case TC_VCENTER:
+ cell->r.top += (cell->r.bottom - cell->h)/2;
+ break;
+ case TC_BOTTOM:
+ cell->r.top += cell->r.bottom - cell->h;
+ }
+ cell->r.bottom = cell->r.top + cell->h;
+}
+
+// void ttTLProc(pROWCELL cell, pROWCELL parent)
+//
+// Ïîçèöèîíèðóåò ïëàâàþùèé êîíòåéíåð, âíóòðè ðîäèòåëüñêîãî
+// cell - óêàçàòåëü íà ïëàâàþùèé êîíòåéíåð
+// parent - óêàçàòåëü íà ðîäèòåëüñêèé êîíòåéíåð
+//
+void rowLayerProc(pROWCELL cell, pROWCELL parent)
+{
+ if (cell->sizing)
+ {
+ cell->r.left = parent->r.left;
+ //cell->r.right += cell->r.left;
+ }
+ else
+ {
+ switch(cell->halign)
+ {
+ case TC_LEFT:
+ cell->r.left = parent->r.left;
+ break;
+ case TC_HCENTER:
+ cell->r.left = parent->r.left + (parent->r.right - cell->r.right)/2;
+ break;
+ case TC_RIGHT:
+ cell->r.left = parent->r.left + parent->r.right - cell->r.right;
+ }
+ }
+
+ switch(cell->valign)
+ {
+ case TC_TOP:
+ cell->r.top = parent->r.top;
+ break;
+ case TC_VCENTER:
+ cell->r.top = parent->r.top + (parent->r.bottom - cell->r.bottom)/2;
+ break;
+ case TC_BOTTOM:
+ cell->r.top = parent->r.top + parent->r.bottom - cell->r.bottom;
+ break;
+ }
+}
+
+// void rowPositioning(pROWCELL cell, int &dist)
+//
+// Âû÷èñëÿåò ïðÿìîóãîëüíèêè ýëåìåíòîâ êîíòàêòà, ó÷èòûâàÿ âûðàâíèâàíèå â êîíòåéíåðå
+// cell - óêàçàòåëü íà êîðíåâîé óçåë äåðåâà îïèñàíèÿ êîíòàêòà
+// dist - íîâàÿ øèðèíà êîíòàêòà
+//
+void rowPositioning(pROWCELL cell, int &dist)
+{
+ ROWCELL* curchild = NULL;
+
+ int x = cell->r.left;
+ int y = cell->r.top;
+
+ int h = cell->r.bottom;
+ int w = dist;
+
+ int r = 0;
+ int size = 0;
+ int cw = 0;
+ int fixedsized = 0;
+ int autosized = 0;
+ int dummy = 0;
+
+ // Êîðððåêòèðîâêà íàçíà÷àåìîé øèðèíû dist
+ if (w < cell->r.right && (cell->type < TC_TEXT1 || cell->type > TC_TEXT3 && cell->type != TC_SPACE) || !cell->sizing)
+ dist = w = cell->r.right;
+
+ cell->r.right = dist;
+ dummy = dist;
+ if (!(curchild = cell->child))
+ {
+ rowPlacing(cell);
+ return;
+ }
+
+ // Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòðîêå
+ if (cell->cont == TC_ROW)
+ {
+ fixedsized = cell->fixed_width;
+ while (curchild)
+ {
+ // Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tc
+ if (curchild->layer)
+ {
+ curchild = curchild->next;
+ continue;
+ }
+
+ cw += curchild->r.right;
+
+ if (curchild->sizing)
+ {
+ autosized += max(curchild->w,curchild->full_width);
+ r++;
+ }
+ else
+ size += curchild->r.right;
+
+ curchild = curchild->next;
+ }
+
+ w -= size;
+ fixedsized -= size;
+
+ if (r == 0)
+ {
+ switch(cell->halign)
+ {
+ case TC_HCENTER:
+ x += (dist - cw)/2;// - 1;
+ break;
+ case TC_RIGHT:
+ x += dist - cw;
+ break;
+ }
+ }
+
+
+ curchild = cell->child;
+
+ size = 0;
+ while(curchild)
+ {
+ if (curchild->layer)
+ {
+ //int dummy = 0;
+ rowLayerProc(curchild, cell);
+ rowPositioning(curchild, dummy);
+ }
+ else
+ {
+ curchild->r.top = cell->r.top;
+ curchild->r.left = x;
+
+
+ w -= size;
+ if (curchild->sizing)
+ {
+ size = w;
+ r--;
+ }
+ else
+ size = curchild->r.right;
+
+ rowPositioning(curchild, size);
+ x += size;
+
+ if (!curchild->sizing)
+ size = 0;
+ }
+
+ curchild = curchild->next;
+ }
+ }
+
+ // Ïîçèöèîíèðîâàíèå êîíòåéíåðîâ â ñòîëáöå
+ if (cell->cont == TC_COL)
+ {
+ while (curchild)
+ {
+ // Êîíòåéíåðû layer íå äîëæíû âëèÿòü íà ïîçèöèîíèðîâàíèå êîíòåéíåðîâ tr
+ if (curchild->layer)
+ {
+ curchild = curchild->next;
+ continue;
+ }
+
+ size += curchild->r.bottom;
+ curchild = curchild->next;
+ }
+
+ if (h > size)
+ {
+ switch(cell->valign)
+ {
+ case TC_VCENTER:
+ y += (h - size) / 2;
+ break;
+ case TC_BOTTOM:
+ y += (h - size);
+ break;
+ }
+ }
+
+ curchild = cell->child;
+ while(curchild)
+ {
+ if (curchild->layer)
+ {
+ rowLayerProc(curchild, cell);
+ rowPositioning(curchild, dummy);
+ }
+ else
+ {
+ curchild->r.top = y;
+ y += curchild->r.bottom;
+
+ curchild->r.left = cell->r.left;
+ curchild->r.right = dist;
+
+ rowPositioning(curchild, size);
+
+ }
+
+ curchild = curchild->next;
+ }
+ }
+
+ rowPlacing(cell);
+
+}
+
+// void rowSizeWithReposition(ROWCELL* &root, int width)
+//
+// Ïðîèçâîäèò ïðîñ÷åò è ïîçèöèîíèðîâàíèå ýëåìåíòîâ êîòàêòà
+// Ïåðåä âûçîâîì íåîáõîäèìî çàïîëíèòü ñòðóêòóðó RowTA
+//
+void rowSizeWithReposition(ROWCELL* &root, int width)
+{
+ root->h = 0;
+ root->w = 0;
+ rowCalculateMinSize(root);
+ rowEqualize(root);
+ rowPositioning(root, width);
+ root->h = root->r.bottom;
+ root->w = root->r.right;
+}
+
+#undef _CPPCODE
diff --git a/plugins/Clist_modern/src/modern_skinbutton.cpp b/plugins/Clist_modern/src/modern_skinbutton.cpp
index e0b45a2f86..a340a544e2 100644
--- a/plugins/Clist_modern/src/modern_skinbutton.cpp
+++ b/plugins/Clist_modern/src/modern_skinbutton.cpp
@@ -1,765 +1,769 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
-Copyright (c) 2000-08 Miranda ICQ/IM project,
-all portions of this codebase are copyrighted to the people
-listed in contributors.txt.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-/*
-This file contains code related to new modern free positioned skinned buttons
-*/
-
-#include "hdr/modern_commonheaders.h"
-#include "hdr/modern_skinengine.h"
-#include "hdr/modern_clcpaint.h"
-#include "m_api/m_skinbutton.h"
-
-#define MODERNSKINBUTTONCLASS "MirandaModernSkinButtonClass"
-BOOL ModernSkinButtonModuleIsLoaded = FALSE;
-static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam);
-int SkinSelector_DeleteMask(MODERNMASK *mm);
-HWND SetToolTip(HWND hwnd, TCHAR * tip);
-
-typedef struct _ModernSkinButtonCtrl
-{
- HWND hwnd;
- BYTE down; // button state
- BYTE focus; // has focus (1 or 0)
- BYTE hover;
- BYTE IsSwitcher;
- BOOL fCallOnPress;
- char * ID;
- char * CommandService;
- char * StateService;
- char * HandleService;
- char * ValueDBSection;
- char * ValueTypeDef;
- int Left, Top, Bottom, Right;
- HMENU hMenu;
- TCHAR * Hint;
-
-} ModernSkinButtonCtrl;
-typedef struct _HandleServiceParams
-{
- HWND hwnd;
- DWORD msg;
- WPARAM wParam;
- LPARAM lParam;
- BOOL handled;
-} HandleServiceParams;
-
-static CRITICAL_SECTION csTips;
-static HWND hwndToolTips = NULL;
-
-int ModernSkinButtonLoadModule()
-{
- WNDCLASSEX wc;
- ZeroMemory(&wc, sizeof(wc));
- wc.cbSize = sizeof(wc);
- wc.lpszClassName = _T(MODERNSKINBUTTONCLASS);
- wc.lpfnWndProc = ModernSkinButtonWndProc;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.cbWndExtra = sizeof(ModernSkinButtonCtrl*);
- wc.hbrBackground = 0;
- wc.style = CS_GLOBALCLASS;
- RegisterClassEx(&wc);
- InitializeCriticalSection(&csTips);
- ModernSkinButtonModuleIsLoaded = TRUE;
- return 0;
-}
-
-int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam)
-{
- DeleteCriticalSection(&csTips);
- return 0;
-}
-
-static int ModernSkinButtonPaintWorker(HWND hwnd, HDC whdc)
-{
- HDC hdc;
- HBITMAP bmp,oldbmp;
- RECT rc;
- HDC sdc = NULL;
- ModernSkinButtonCtrl* bct = (ModernSkinButtonCtrl *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (!bct) return 0;
- if (!IsWindowVisible(hwnd)) return 0;
- if (!whdc && !g_CluiData.fLayered) InvalidateRect(hwnd,NULL,FALSE);
-
- if (whdc && g_CluiData.fLayered) hdc = whdc;
- else
- {
- //sdc = GetWindowDC(GetParent(hwnd));
- hdc = CreateCompatibleDC(NULL);
- }
- GetClientRect(hwnd,&rc);
- bmp = ske_CreateDIB32(rc.right,rc.bottom);
- oldbmp = (HBITMAP)SelectObject(hdc,bmp);
- if (!g_CluiData.fLayered)
- ske_BltBackImage(bct->hwnd,hdc,NULL);
- {
- MODERNMASK Request = {0};
- // int res;
- //HBRUSH br = CreateSolidBrush(RGB(255,255,255));
- char * Value = NULL;
- DWORD val = 0;
- {
- if (bct->ValueDBSection && bct->ValueTypeDef)
- {
- char * key;
- char * section;
- DWORD defval = 0;
- char buf[20];
- key = mir_strdup(bct->ValueDBSection);
- section = key;
- if (bct->ValueTypeDef[0] != 's')
- defval = (DWORD)atol(bct->ValueTypeDef+1);
- do
- {
- if (key[0] == '/') {key[0] = '\0'; key++; break;}
- key++;
- } while (key[0] != '\0');
- switch (bct->ValueTypeDef[0])
- {
- case 's':
- {
- Value = db_get_sa(NULL,section,key);
- if (!Value)
- Value = mir_strdup(bct->ValueTypeDef+1);
- break;
- }
- case 'd':
- defval = db_get_dw(NULL,section,key,defval);
- Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
- break;
- case 'w':
- defval = db_get_w(NULL,section,key,defval);
- Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
- break;
- case 'b':
- defval = db_get_b(NULL,section,key,defval);
- Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
- break;
- }
- mir_free(section);
- }
-
- }
- g_clcPainter.AddParam(&Request,mod_CalcHash("Module"),"MButton",0);
- g_clcPainter.AddParam(&Request,mod_CalcHash("ID"),bct->ID,0);
- g_clcPainter.AddParam(&Request,mod_CalcHash("Down"),bct->down?"1":"0",0);
- g_clcPainter.AddParam(&Request,mod_CalcHash("Focused"),bct->focus?"1":"0",0);
- g_clcPainter.AddParam(&Request,mod_CalcHash("Hovered"),bct->hover?"1":"0",0);
- if (Value) {
- g_clcPainter.AddParam(&Request,mod_CalcHash("Value"),Value,0);
- mir_free(Value);
- }
- SkinDrawGlyphMask(hdc,&rc,&rc,&Request);
- SkinSelector_DeleteMask(&Request);
- // DeleteObject(br);
- }
-
- if (!whdc && g_CluiData.fLayered)
- {
- RECT r;
- SetRect(&r,bct->Left,bct->Top,bct->Right,bct->Bottom);
- ske_DrawImageAt(hdc,&r);
- //CallingService to immeadeately update window with new image.
- }
- if (whdc && !g_CluiData.fLayered)
- {
- RECT r = {0};
- GetClientRect(bct->hwnd,&r);
- BitBlt(whdc, 0, 0, r.right,r.bottom,hdc, 0, 0, SRCCOPY);
- }
- SelectObject(hdc,oldbmp);
- DeleteObject(bmp);
- if (!whdc || !g_CluiData.fLayered)
- {
- SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
- DeleteDC(hdc);
- }
- // if (sdc)
- // ReleaseDC(GetParent(hwnd),sdc);
- return 0;
-}
-
-static int ModernSkinButtonToggleDBValue(char * ValueDBSection,char *ValueTypeDef)
-{
- if (ValueDBSection && ValueTypeDef)
- {
- char * key;
- char * section;
- char * val;
- char * val2;
- char * Value;
- long l1,l2,curval;
- DWORD defval = 0;
- // char buf[20];
- key = mir_strdup(ValueDBSection);
- section = key;
- do
- {
- if (key[0] == '/') {key[0] = '\0'; key++; break;}
- key++;
- } while (key[0] != '\0');
-
- val = mir_strdup(ValueTypeDef+1);
- val2 = val;
- do
- {
- if (val2[0] == '/') {val2[0] = '\0'; val2++; break;}
- val2++;
- } while (val2[0] != '\0');
-
- if (ValueTypeDef[0] != 's')
- {
- l1 = (DWORD)atol(val);
- l2 = (DWORD)atol(val2);
- }
-
- switch (ValueTypeDef[0]) {
- case 's':
- Value = db_get_sa(NULL,section,key);
- if (!Value || (Value && mir_bool_strcmpi(Value,val2)))
- Value = mir_strdup(val);
- else
- Value = mir_strdup(val2);
- db_set_s(NULL,section,key,Value);
- mir_free(Value);
- break;
-
- case 'd':
- curval = db_get_dw(NULL,section,key,l2);
- curval = (curval == l2)?l1:l2;
- db_set_dw(NULL,section,key,(DWORD)curval);
- break;
-
- case 'w':
- curval = db_get_w(NULL,section,key,l2);
- curval = (curval == l2)?l1:l2;
- db_set_w(NULL,section,key,(WORD)curval);
- break;
-
- case 'b':
- curval = db_get_b(NULL,section,key,l2);
- curval = (curval == l2)?l1:l2;
- db_set_b(NULL,section,key,(BYTE)curval);
- break;
- }
- mir_free(section);
- mir_free(val);
- }
- return 0;
-}
-
-static char *_skipblank(char * str) //str will be modified;
-{
- char * endstr = str+strlen(str);
- while ((*str == ' ' || *str == '\t') && *str != '\0') str++;
- while ((*endstr == ' ' || *endstr == '\t') && *endstr != '\0' && endstr < str) endstr--;
- if (*endstr != '\0')
- {
- endstr++;
- *endstr = '\0';
- }
- return str;
-}
-
-static int _CallServiceStrParams(IN char * toParce, OUT int *Return)
-{
- char * pszService;
- char * param1 = NULL;
- char * param2 = NULL;
- int paramCount = 0;
- int result = 0;
- pszService = mir_strdup(toParce);
- param2 = strrchr(pszService, '%');
- if (param2)
- {
- paramCount++;
- *param2 = '\0'; param2++;
- _skipblank(param2);
- if (strlen(param2) == 0) param2 = NULL;
- }
- param1 = strrchr(pszService, '%');
- if (param1)
- {
- paramCount++;
- *param1 = '\0'; param1++;
- _skipblank(param1);
- if (strlen(param1) == 0) param1 = NULL;
- }
- if (!pszService) return 0;
- if (strlen(pszService) == 0) {
- mir_free(pszService);
- return 0;
- }
- if (param1 && *param1 == '\"')
- {
- param1++;
- *(param1+strlen(param1)) = '\0';
- }
- else if (param1)
- {
- param1 = (char*)atoi(param1);
- }
- if (param2 && *param2 == '\"')
- {
- param2++;
- *(param2+strlen(param2)) = '\0';
- }
- else if (param2)
- param2 = (char*)atoi(param2);
-
- if (paramCount == 1)
- {
- param1 = param2;
- param2 = NULL;
- }
- if (!ServiceExists(pszService))
- {
- result = 0;
- }
- else
- {
- int ret = 0;
- result = 1;
- ret = CallService(pszService, (WPARAM)param1, (WPARAM)param2);
- if (Return) *Return = ret;
- }
- mir_free(pszService);
- return result;
-}
-
-
-static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- ModernSkinButtonCtrl* bct = (msg != WM_NCCREATE)?(ModernSkinButtonCtrl *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA):0;
- if (bct && bct->HandleService && IsBadStringPtrA(bct->HandleService,255))
- bct->HandleService = NULL;
-
- if (bct)
- if (bct->HandleService && ServiceExists(bct->HandleService)) {
- HandleServiceParams MSG = {0};
- MSG.hwnd = hwndDlg;
- MSG.msg = msg;
- MSG.wParam = wParam;
- MSG.lParam = lParam;
- int t = CallService(bct->HandleService,(WPARAM)&MSG,0);
- if (MSG.handled) return t;
- }
-
- switch(msg) {
- case WM_NCCREATE:
- SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE)|BS_OWNERDRAW);
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
- if (((CREATESTRUCT *)lParam)->lpszName) SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName);
- return TRUE;
-
- case WM_DESTROY:
- if (bct) {
- EnterCriticalSection(&csTips);
- if (hwndToolTips) {
- TOOLINFO ti;
- ZeroMemory(&ti, sizeof(ti));
- ti.cbSize = sizeof(ti);
- ti.uFlags = TTF_IDISHWND;
- ti.hwnd = bct->hwnd;
- ti.uId = (UINT_PTR)bct->hwnd;
- if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
- SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
- }
- if (SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti) == 0) {
- DestroyWindow(hwndToolTips);
- hwndToolTips = NULL;
- }
- }
- LeaveCriticalSection(&csTips);
- mir_free(bct->ID);
- mir_free(bct->CommandService);
- mir_free(bct->StateService);
- mir_free(bct->HandleService);
- mir_free(bct->Hint);
- mir_free(bct->ValueDBSection);
- mir_free(bct->ValueTypeDef);
- mir_free(bct);
- }
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
- break; // DONT! fall thru
-
- case WM_SETCURSOR:
- {
- HCURSOR hCurs1 = LoadCursor(NULL, IDC_ARROW);
- if (hCurs1) SetCursor(hCurs1);
- if (bct) SetToolTip(hwndDlg, bct->Hint);
- }
- return 1;
-
- case WM_PRINT:
- if (IsWindowVisible(hwndDlg))
- ModernSkinButtonPaintWorker(hwndDlg,(HDC)wParam);
- break;
-
- case WM_PAINT:
- if (IsWindowVisible(hwndDlg) && !g_CluiData.fLayered) {
- PAINTSTRUCT ps = {0};
- BeginPaint(hwndDlg,&ps);
- ModernSkinButtonPaintWorker(hwndDlg,(HDC)ps.hdc);
- EndPaint(hwndDlg,&ps);
- }
- return DefWindowProc(hwndDlg, msg, wParam, lParam);
-
- case WM_CAPTURECHANGED:
- bct->hover = 0;
- bct->down = 0;
- ModernSkinButtonPaintWorker(bct->hwnd,0);
- break;
-
- case WM_MOUSEMOVE:
- if (!bct->hover) {
- SetCapture(bct->hwnd);
- bct->hover = 1;
- ModernSkinButtonPaintWorker(bct->hwnd,0);
- }
- else {
- POINT t = UNPACK_POINT(lParam);
- ClientToScreen(bct->hwnd,&t);
- if (WindowFromPoint(t) != bct->hwnd)
- ReleaseCapture();
- }
- return 0;
-
- case WM_LBUTTONDOWN:
- bct->down = 1;
- SetForegroundWindow(GetParent(bct->hwnd));
- ModernSkinButtonPaintWorker(bct->hwnd,0);
- if (bct && bct->CommandService && IsBadStringPtrA(bct->CommandService,255))
- bct->CommandService = NULL;
- if (bct->fCallOnPress) {
- if (bct->CommandService) {
- if (!_CallServiceStrParams(bct->CommandService, NULL) && (bct->ValueDBSection && bct->ValueTypeDef))
- ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef);
- }
- bct->down = 0;
-
- ModernSkinButtonPaintWorker(bct->hwnd,0);
- }
- return 0;
-
- case WM_LBUTTONUP:
- if (bct->down) {
- ReleaseCapture();
- bct->hover = 0;
- bct->down = 0;
- ModernSkinButtonPaintWorker(bct->hwnd,0);
- if (bct && bct->CommandService && IsBadStringPtrA(bct->CommandService,255))
- bct->CommandService = NULL;
- if (bct->CommandService)
- if (_CallServiceStrParams(bct->CommandService, NULL))
- {}
- else if (bct->ValueDBSection && bct->ValueTypeDef)
- ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef);
- }
- }
- return DefWindowProc(hwndDlg, msg, wParam, lParam);
-}
-
-HWND SetToolTip(HWND hwnd, TCHAR * tip)
-{
- TOOLINFO ti;
- if (!tip) return 0;
- EnterCriticalSection(&csTips);
- if (!hwndToolTips) {
- // hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
-
- hwndToolTips = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
- WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
- CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT,
- hwnd, NULL, GetModuleHandle(NULL),
- NULL);
-
- SetWindowPos(hwndToolTips, HWND_TOPMOST, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
- }
-
- ZeroMemory(&ti, sizeof(ti));
- ti.cbSize = sizeof(ti);
- ti.uFlags = TTF_IDISHWND;
- ti.hwnd = hwnd;
- ti.uId = (UINT_PTR)hwnd;
- if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
- SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
- }
- ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
- ti.uId = (UINT_PTR)hwnd;
- ti.lpszText = (TCHAR*)tip;
- SendMessage(hwndToolTips,TTM_ADDTOOL, 0, (LPARAM)&ti);
-
- LeaveCriticalSection(&csTips);
- return hwndToolTips;
-}
-
-
-
-typedef struct _MButton
-{
- HWND hwnd;
- BYTE ConstrainPositionFrom; //(BBRRTTLL) L = 0 - from left, L = 1 from right, L = 2 from center
- int OrL,OrR,OrT,OrB;
- int minW,minH;
- ModernSkinButtonCtrl * bct;
-
-} MButton;
-MButton * Buttons = NULL;
-DWORD ButtonsCount = 0;
-
-#define _center_h( rc ) (((rc)->right + (rc)->left ) >> 1)
-#define _center_v( rc ) (((rc)->bottom + (rc)->top ) >> 1)
-
-int ModernSkinButton_AddButton(HWND parent,
- char * ID,
- char * CommandService,
- char * StateDefService,
- char * HandeService,
- int Left,
- int Top,
- int Right,
- int Bottom,
- DWORD sbFlags,
- TCHAR * Hint,
- char * DBkey,
- char * TypeDef,
- int MinWidth, int MinHeight)
-{
- // if (!parent) return 0;
- if (!ModernSkinButtonModuleIsLoaded) return 0;
- if (!Buttons)
- Buttons = (MButton*)mir_alloc(sizeof(MButton));
- else
- Buttons = (MButton*)mir_realloc(Buttons,sizeof(MButton)*(ButtonsCount+1));
- {
- //HWND hwnd;
- RECT rc = {0};
- ModernSkinButtonCtrl* bct;
- int l,r,b,t;
- if (parent) GetClientRect(parent,&rc);
- l = ( sbFlags & SBF_ALIGN_TL_RIGHT ) ? ( rc.right + Left ) :
- ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Left ) :
- ( rc.left + Left );
-
- t = ( sbFlags & SBF_ALIGN_TL_BOTTOM ) ? ( rc.bottom + Top ) :
- ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Top ) :
- ( rc.top+Top );
-
- r = ( sbFlags & SBF_ALIGN_BR_RIGHT ) ? ( rc.right + Right ) :
- ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Right ) :
- ( rc.left + Right );
-
- b = ( sbFlags & SBF_ALIGN_BR_BOTTOM ) ? ( rc.bottom + Bottom ) :
- ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Bottom ) :
- ( rc.top + Bottom );
- bct = (ModernSkinButtonCtrl *)mir_alloc(sizeof(ModernSkinButtonCtrl));
- memset(bct, 0, sizeof(ModernSkinButtonCtrl));
- bct->Left = l;
- bct->Right = r;
- bct->Top = t;
- bct->Bottom = b;
- bct->fCallOnPress = ( sbFlags & SBF_CALL_ON_PRESS ) != 0;
- bct->HandleService = mir_strdup(HandeService);
- bct->CommandService = mir_strdup(CommandService);
- bct->StateService = mir_strdup(StateDefService);
- if (DBkey && &DBkey != '\0') bct->ValueDBSection = mir_strdup(DBkey); else bct->ValueDBSection = NULL;
- if (TypeDef && &TypeDef != '\0') bct->ValueTypeDef = mir_strdup(TypeDef); else bct->ValueTypeDef = mir_strdup("sDefault");
- bct->ID=mir_strdup(ID);
- bct->Hint = mir_tstrdup(Hint);
- Buttons[ButtonsCount].bct = bct;
- Buttons[ButtonsCount].hwnd = NULL;
- Buttons[ButtonsCount].OrL = Left;
- Buttons[ButtonsCount].OrT = Top;
- Buttons[ButtonsCount].OrR = Right;
- Buttons[ButtonsCount].OrB = Bottom;
- Buttons[ButtonsCount].ConstrainPositionFrom = (BYTE)sbFlags;
- Buttons[ButtonsCount].minH = MinHeight;
- Buttons[ButtonsCount].minW = MinWidth;
- ButtonsCount++;
- // CLUI_ShowWindowMod(hwnd,SW_SHOW);
- }
- return 0;
-}
-
-
-
-static int ModernSkinButtonErase(int l,int t,int r, int b)
-{
- DWORD i;
- if (!ModernSkinButtonModuleIsLoaded) return 0;
- if (!g_CluiData.fLayered) return 0;
- if (!g_pCachedWindow) return 0;
- if (!g_pCachedWindow->hImageDC || !g_pCachedWindow->hBackDC) return 0;
- if (!(l || r || t || b))
- {
- for (i=0; i < ButtonsCount; i++)
- {
- if (pcli->hwndContactList && Buttons[i].hwnd != NULL)
- {
- //TODO: Erase button
- BitBlt(g_pCachedWindow->hImageDC,Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right-Buttons[i].bct->Left,Buttons[i].bct->Bottom-Buttons[i].bct->Top,
- g_pCachedWindow->hBackDC,Buttons[i].bct->Left,Buttons[i].bct->Top,SRCCOPY);
- }
- }
- }
- else
- {
- BitBlt(g_pCachedWindow->hImageDC,l,t,r-l,b-t, g_pCachedWindow->hBackDC,l,t,SRCCOPY);
- }
- return 0;
-}
-
-static HWND ModernSkinButtonCreateWindow(ModernSkinButtonCtrl * bct, HWND parent)
-{
- HWND hwnd;
-
- if (bct == NULL) return FALSE;
- {
- TCHAR *UnicodeID;
- UnicodeID = mir_a2u(bct->ID);
- hwnd = CreateWindow(_T(MODERNSKINBUTTONCLASS),UnicodeID,WS_VISIBLE|WS_CHILD,bct->Left,bct->Top,bct->Right-bct->Left,bct->Bottom-bct->Top,parent,NULL,g_hInst,NULL);
- mir_free(UnicodeID);
- }
-
- bct->hwnd = hwnd;
- bct->focus = 0;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)bct);
- return hwnd;
-}
-
-int ModernSkinButtonRedrawAll(HDC hdc)
-{
- DWORD i;
- if (!ModernSkinButtonModuleIsLoaded) return 0;
- g_mutex_bLockUpdating++;
- for (i=0; i < ButtonsCount; i++)
- {
- if (pcli->hwndContactList && Buttons[i].hwnd == NULL)
- Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,pcli->hwndContactList);
- ModernSkinButtonPaintWorker(Buttons[i].hwnd,0);
- }
- g_mutex_bLockUpdating--;
- return 0;
-}
-
-int ModernSkinButtonDeleteAll()
-{
- if (!ModernSkinButtonModuleIsLoaded)
- return 0;
-
- for (size_t i=0; i < ButtonsCount; i++)
- if (Buttons[i].hwnd)
- DestroyWindow(Buttons[i].hwnd);
-
- mir_free_and_nil(Buttons);
- ButtonsCount = 0;
- return 0;
-}
-
-int ModernSkinButton_ReposButtons(HWND parent, BYTE draw, RECT *r)
-{
- DWORD i;
- RECT rc;
- RECT clr;
- RECT rd;
- BOOL altDraw = FALSE;
- static SIZE oldWndSize = {0};
- if (!ModernSkinButtonModuleIsLoaded) return 0;
- GetWindowRect(parent,&rd);
- GetClientRect(parent,&clr);
- if (!r)
- GetWindowRect(parent,&rc);
- else
- rc = *r;
- if (g_CluiData.fLayered && ( draw & SBRF_DO_ALT_DRAW ))
- {
- int sx,sy;
- sx = rd.right-rd.left;
- sy = rd.bottom-rd.top;
- if (sx != oldWndSize.cx || sy != oldWndSize.cy)
- altDraw = TRUE;//EraseButtons();
- oldWndSize.cx = sx;
- oldWndSize.cy = sy;
- }
-
- OffsetRect(&rc,-rc.left,-rc.top);
- rc.right = rc.left+(clr.right-clr.left);
- rc.bottom = rc.top+(clr.bottom-clr.top);
- for (i=0; i < ButtonsCount; i++)
- {
- int l,r,b,t;
- RECT oldRect = {0};
- int sbFlags = Buttons[i].ConstrainPositionFrom;
- if (parent && Buttons[i].hwnd == NULL)
- {
- Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,parent);
- altDraw = FALSE;
- }
-
- l = ( sbFlags & SBF_ALIGN_TL_RIGHT ) ? ( rc.right + Buttons[i].OrL ) :
- ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Buttons[i].OrL ) :
- ( rc.left + Buttons[i].OrL );
-
- t = ( sbFlags & SBF_ALIGN_TL_BOTTOM ) ? ( rc.bottom + Buttons[i].OrT ) :
- ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrT ) :
- ( rc.top + Buttons[i].OrT );
-
- r = ( sbFlags & SBF_ALIGN_BR_RIGHT ) ? ( rc.right + Buttons[i].OrR ) :
- ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Buttons[i].OrR ) :
- ( rc.left + Buttons[i].OrR );
-
- b = ( sbFlags & SBF_ALIGN_BR_BOTTOM ) ? ( rc.bottom + Buttons[i].OrB ) :
- ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrB ) :
- ( rc.top + Buttons[i].OrB );
-
- SetWindowPos(Buttons[i].hwnd,HWND_TOP,l,t,r-l,b-t,0);
- if ( (rc.right-rc.left < Buttons[i].minW /* && Buttons[i].minW != 0*/)
- || (rc.bottom-rc.top < Buttons[i].minH /* && Buttons[i].minH != 0*/))
- CLUI_ShowWindowMod(Buttons[i].hwnd,SW_HIDE);
- else
- CLUI_ShowWindowMod(Buttons[i].hwnd,SW_SHOW);
- if ((1 || altDraw) &&
- (Buttons[i].bct->Left != l ||
- Buttons[i].bct->Top != t ||
- Buttons[i].bct->Right != r ||
- Buttons[i].bct->Bottom != b))
- {
- //Need to erase in old location
- ModernSkinButtonErase(Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right,Buttons[i].bct->Bottom);
- }
-
- Buttons[i].bct->Left = l;
- Buttons[i].bct->Top = t;
- Buttons[i].bct->Right = r;
- Buttons[i].bct->Bottom = b;
-
-
- }
- if ( draw & SBRF_DO_REDRAW_ALL ) ModernSkinButtonRedrawAll(0);
- return 0;
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
+Copyright (c) 2000-08 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+This file contains code related to new modern free positioned skinned buttons
+*/
+
+#include "hdr/modern_commonheaders.h"
+#include "hdr/modern_skinengine.h"
+#include "hdr/modern_clcpaint.h"
+#include "m_api/m_skinbutton.h"
+
+#define MODERNSKINBUTTONCLASS "MirandaModernSkinButtonClass"
+BOOL ModernSkinButtonModuleIsLoaded = FALSE;
+static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam);
+int SkinSelector_DeleteMask(MODERNMASK *mm);
+HWND SetToolTip(HWND hwnd, TCHAR * tip);
+
+typedef struct _ModernSkinButtonCtrl
+{
+ HWND hwnd;
+ BYTE down; // button state
+ BYTE focus; // has focus (1 or 0)
+ BYTE hover;
+ BYTE IsSwitcher;
+ BOOL fCallOnPress;
+ char * ID;
+ char * CommandService;
+ char * StateService;
+ char * HandleService;
+ char * ValueDBSection;
+ char * ValueTypeDef;
+ int Left, Top, Bottom, Right;
+ HMENU hMenu;
+ TCHAR * Hint;
+
+} ModernSkinButtonCtrl;
+typedef struct _HandleServiceParams
+{
+ HWND hwnd;
+ DWORD msg;
+ WPARAM wParam;
+ LPARAM lParam;
+ BOOL handled;
+} HandleServiceParams;
+
+static CRITICAL_SECTION csTips;
+static HWND hwndToolTips = NULL;
+
+int ModernSkinButtonLoadModule()
+{
+ WNDCLASSEX wc;
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = _T(MODERNSKINBUTTONCLASS);
+ wc.lpfnWndProc = ModernSkinButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(ModernSkinButtonCtrl*);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS;
+ RegisterClassEx(&wc);
+ InitializeCriticalSection(&csTips);
+ ModernSkinButtonModuleIsLoaded = TRUE;
+ return 0;
+}
+
+int ModernSkinButtonUnloadModule(WPARAM wParam, LPARAM lParam)
+{
+ DeleteCriticalSection(&csTips);
+ return 0;
+}
+
+static int ModernSkinButtonPaintWorker(HWND hwnd, HDC whdc)
+{
+ HDC hdc;
+ HBITMAP bmp,oldbmp;
+ RECT rc;
+ HDC sdc = NULL;
+ ModernSkinButtonCtrl* bct = (ModernSkinButtonCtrl *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (!bct) return 0;
+ if (!IsWindowVisible(hwnd)) return 0;
+ if (!whdc && !g_CluiData.fLayered) InvalidateRect(hwnd,NULL,FALSE);
+
+ if (whdc && g_CluiData.fLayered) hdc = whdc;
+ else
+ {
+ //sdc = GetWindowDC(GetParent(hwnd));
+ hdc = CreateCompatibleDC(NULL);
+ }
+ GetClientRect(hwnd,&rc);
+ bmp = ske_CreateDIB32(rc.right,rc.bottom);
+ oldbmp = (HBITMAP)SelectObject(hdc,bmp);
+ if (!g_CluiData.fLayered)
+ ske_BltBackImage(bct->hwnd,hdc,NULL);
+ {
+ MODERNMASK Request = {0};
+ // int res;
+ //HBRUSH br = CreateSolidBrush(RGB(255,255,255));
+ char * Value = NULL;
+ DWORD val = 0;
+ {
+ if (bct->ValueDBSection && bct->ValueTypeDef)
+ {
+ char * key;
+ char * section;
+ DWORD defval = 0;
+ char buf[20];
+ key = mir_strdup(bct->ValueDBSection);
+ section = key;
+ if (bct->ValueTypeDef[0] != 's')
+ defval = (DWORD)atol(bct->ValueTypeDef+1);
+ do
+ {
+ if (key[0] == '/') {key[0] = '\0'; key++; break;}
+ key++;
+ } while (key[0] != '\0');
+ switch (bct->ValueTypeDef[0])
+ {
+ case 's':
+ {
+ Value = db_get_sa(NULL,section,key);
+ if (!Value)
+ Value = mir_strdup(bct->ValueTypeDef+1);
+ break;
+ }
+ case 'd':
+ defval = db_get_dw(NULL,section,key,defval);
+ Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
+ break;
+ case 'w':
+ defval = db_get_w(NULL,section,key,defval);
+ Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
+ break;
+ case 'b':
+ defval = db_get_b(NULL,section,key,defval);
+ Value = mir_strdup(_ltoa(defval,buf,SIZEOF(buf)));
+ break;
+ }
+ mir_free(section);
+ }
+
+ }
+ g_clcPainter.AddParam(&Request,mod_CalcHash("Module"),"MButton",0);
+ g_clcPainter.AddParam(&Request,mod_CalcHash("ID"),bct->ID,0);
+ g_clcPainter.AddParam(&Request,mod_CalcHash("Down"),bct->down?"1":"0",0);
+ g_clcPainter.AddParam(&Request,mod_CalcHash("Focused"),bct->focus?"1":"0",0);
+ g_clcPainter.AddParam(&Request,mod_CalcHash("Hovered"),bct->hover?"1":"0",0);
+ if (Value) {
+ g_clcPainter.AddParam(&Request,mod_CalcHash("Value"),Value,0);
+ mir_free(Value);
+ }
+ SkinDrawGlyphMask(hdc,&rc,&rc,&Request);
+ SkinSelector_DeleteMask(&Request);
+ // DeleteObject(br);
+ }
+
+ if (!whdc && g_CluiData.fLayered)
+ {
+ RECT r;
+ SetRect(&r,bct->Left,bct->Top,bct->Right,bct->Bottom);
+ ske_DrawImageAt(hdc,&r);
+ //CallingService to immeadeately update window with new image.
+ }
+ if (whdc && !g_CluiData.fLayered)
+ {
+ RECT r = {0};
+ GetClientRect(bct->hwnd,&r);
+ BitBlt(whdc, 0, 0, r.right,r.bottom,hdc, 0, 0, SRCCOPY);
+ }
+ SelectObject(hdc,oldbmp);
+ DeleteObject(bmp);
+ if (!whdc || !g_CluiData.fLayered)
+ {
+ SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
+ DeleteDC(hdc);
+ }
+ // if (sdc)
+ // ReleaseDC(GetParent(hwnd),sdc);
+ return 0;
+}
+
+static int ModernSkinButtonToggleDBValue(char * ValueDBSection,char *ValueTypeDef)
+{
+ if (ValueDBSection && ValueTypeDef)
+ {
+ char * key;
+ char * section;
+ char * val;
+ char * val2;
+ char * Value;
+ long l1,l2,curval;
+ DWORD defval = 0;
+ // char buf[20];
+ key = mir_strdup(ValueDBSection);
+ section = key;
+ do
+ {
+ if (key[0] == '/') {key[0] = '\0'; key++; break;}
+ key++;
+ } while (key[0] != '\0');
+
+ val = mir_strdup(ValueTypeDef+1);
+ val2 = val;
+ do
+ {
+ if (val2[0] == '/') {val2[0] = '\0'; val2++; break;}
+ val2++;
+ } while (val2[0] != '\0');
+
+ if (ValueTypeDef[0] != 's')
+ {
+ l1 = (DWORD)atol(val);
+ l2 = (DWORD)atol(val2);
+ }
+
+ switch (ValueTypeDef[0]) {
+ case 's':
+ Value = db_get_sa(NULL,section,key);
+ if (!Value || (Value && mir_bool_strcmpi(Value,val2)))
+ Value = mir_strdup(val);
+ else
+ Value = mir_strdup(val2);
+ db_set_s(NULL,section,key,Value);
+ mir_free(Value);
+ break;
+
+ case 'd':
+ curval = db_get_dw(NULL,section,key,l2);
+ curval = (curval == l2)?l1:l2;
+ db_set_dw(NULL,section,key,(DWORD)curval);
+ break;
+
+ case 'w':
+ curval = db_get_w(NULL,section,key,l2);
+ curval = (curval == l2)?l1:l2;
+ db_set_w(NULL,section,key,(WORD)curval);
+ break;
+
+ case 'b':
+ curval = db_get_b(NULL,section,key,l2);
+ curval = (curval == l2)?l1:l2;
+ db_set_b(NULL,section,key,(BYTE)curval);
+ break;
+ }
+ mir_free(section);
+ mir_free(val);
+ }
+ return 0;
+}
+
+static char *_skipblank(char * str) //str will be modified;
+{
+ char * endstr = str+strlen(str);
+ while ((*str == ' ' || *str == '\t') && *str != '\0') str++;
+ while ((*endstr == ' ' || *endstr == '\t') && *endstr != '\0' && endstr < str) endstr--;
+ if (*endstr != '\0')
+ {
+ endstr++;
+ *endstr = '\0';
+ }
+ return str;
+}
+
+static int _CallServiceStrParams(IN char * toParce, OUT int *Return)
+{
+ char * pszService;
+ char * param1 = NULL;
+ char * param2 = NULL;
+ int paramCount = 0;
+ int result = 0;
+
+ pszService = mir_strdup(toParce);
+ if (!pszService)
+ return 0;
+ if (strlen(pszService) == 0) {
+ mir_free(pszService);
+ return 0;
+ }
+ param2 = strrchr(pszService, '%');
+ if (param2)
+ {
+ paramCount++;
+ *param2 = '\0'; param2++;
+ _skipblank(param2);
+ if (strlen(param2) == 0)
+ param2 = NULL;
+ }
+ param1 = strrchr(pszService, '%');
+ if (param1)
+ {
+ paramCount++;
+ *param1 = '\0'; param1++;
+ _skipblank(param1);
+ if (strlen(param1) == 0)
+ param1 = NULL;
+ }
+ if (param1 && *param1 == '\"')
+ {
+ param1++;
+ *(param1+strlen(param1)) = '\0';
+ }
+ else if (param1)
+ {
+ param1 = (char*)atoi(param1);
+ }
+ if (param2 && *param2 == '\"')
+ {
+ param2++;
+ *(param2+strlen(param2)) = '\0';
+ }
+ else if (param2)
+ param2 = (char*)atoi(param2);
+
+ if (paramCount == 1)
+ {
+ param1 = param2;
+ param2 = NULL;
+ }
+ if (!ServiceExists(pszService))
+ {
+ result = 0;
+ }
+ else
+ {
+ int ret = 0;
+ result = 1;
+ ret = CallService(pszService, (WPARAM)param1, (WPARAM)param2);
+ if (Return) *Return = ret;
+ }
+ mir_free(pszService);
+ return result;
+}
+
+
+static LRESULT CALLBACK ModernSkinButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ModernSkinButtonCtrl* bct = (msg != WM_NCCREATE)?(ModernSkinButtonCtrl *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA):0;
+ if (bct && bct->HandleService && IsBadStringPtrA(bct->HandleService,255))
+ bct->HandleService = NULL;
+
+ if (bct)
+ if (bct->HandleService && ServiceExists(bct->HandleService)) {
+ HandleServiceParams MSG = {0};
+ MSG.hwnd = hwndDlg;
+ MSG.msg = msg;
+ MSG.wParam = wParam;
+ MSG.lParam = lParam;
+ int t = CallService(bct->HandleService,(WPARAM)&MSG,0);
+ if (MSG.handled) return t;
+ }
+
+ switch(msg) {
+ case WM_NCCREATE:
+ SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE)|BS_OWNERDRAW);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ if (((CREATESTRUCT *)lParam)->lpszName) SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName);
+ return TRUE;
+
+ case WM_DESTROY:
+ if (bct == NULL)
+ break;
+ EnterCriticalSection(&csTips);
+ if (hwndToolTips) {
+ TOOLINFO ti;
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT_PTR)bct->hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ if (SendMessage(hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti) == 0) {
+ DestroyWindow(hwndToolTips);
+ hwndToolTips = NULL;
+ }
+ }
+ LeaveCriticalSection(&csTips);
+ mir_free(bct->ID);
+ mir_free(bct->CommandService);
+ mir_free(bct->StateService);
+ mir_free(bct->HandleService);
+ mir_free(bct->Hint);
+ mir_free(bct->ValueDBSection);
+ mir_free(bct->ValueTypeDef);
+ mir_free(bct);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ break; // DONT! fall thru
+
+ case WM_SETCURSOR:
+ {
+ HCURSOR hCurs1 = LoadCursor(NULL, IDC_ARROW);
+ if (hCurs1) SetCursor(hCurs1);
+ if (bct) SetToolTip(hwndDlg, bct->Hint);
+ }
+ return 1;
+
+ case WM_PRINT:
+ if (IsWindowVisible(hwndDlg))
+ ModernSkinButtonPaintWorker(hwndDlg,(HDC)wParam);
+ break;
+
+ case WM_PAINT:
+ if (IsWindowVisible(hwndDlg) && !g_CluiData.fLayered) {
+ PAINTSTRUCT ps = {0};
+ BeginPaint(hwndDlg,&ps);
+ ModernSkinButtonPaintWorker(hwndDlg,(HDC)ps.hdc);
+ EndPaint(hwndDlg,&ps);
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+
+ case WM_CAPTURECHANGED:
+ bct->hover = 0;
+ bct->down = 0;
+ ModernSkinButtonPaintWorker(bct->hwnd,0);
+ break;
+
+ case WM_MOUSEMOVE:
+ if (!bct->hover) {
+ SetCapture(bct->hwnd);
+ bct->hover = 1;
+ ModernSkinButtonPaintWorker(bct->hwnd,0);
+ }
+ else {
+ POINT t = UNPACK_POINT(lParam);
+ ClientToScreen(bct->hwnd,&t);
+ if (WindowFromPoint(t) != bct->hwnd)
+ ReleaseCapture();
+ }
+ return 0;
+
+ case WM_LBUTTONDOWN:
+ bct->down = 1;
+ SetForegroundWindow(GetParent(bct->hwnd));
+ ModernSkinButtonPaintWorker(bct->hwnd,0);
+ if (bct->CommandService && IsBadStringPtrA(bct->CommandService,255))
+ bct->CommandService = NULL;
+ if (bct->fCallOnPress) {
+ if (bct->CommandService) {
+ if (!_CallServiceStrParams(bct->CommandService, NULL) && (bct->ValueDBSection && bct->ValueTypeDef))
+ ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef);
+ }
+ bct->down = 0;
+
+ ModernSkinButtonPaintWorker(bct->hwnd,0);
+ }
+ return 0;
+
+ case WM_LBUTTONUP:
+ if (bct->down) {
+ ReleaseCapture();
+ bct->hover = 0;
+ bct->down = 0;
+ ModernSkinButtonPaintWorker(bct->hwnd,0);
+ if (bct->CommandService && IsBadStringPtrA(bct->CommandService,255))
+ bct->CommandService = NULL;
+ if (bct->CommandService)
+ if (_CallServiceStrParams(bct->CommandService, NULL))
+ {}
+ else if (bct->ValueDBSection && bct->ValueTypeDef)
+ ModernSkinButtonToggleDBValue(bct->ValueDBSection,bct->ValueTypeDef);
+ }
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
+
+HWND SetToolTip(HWND hwnd, TCHAR * tip)
+{
+ TOOLINFO ti;
+ if (!tip) return 0;
+ EnterCriticalSection(&csTips);
+ if (!hwndToolTips) {
+ // hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
+
+ hwndToolTips = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
+ WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ hwnd, NULL, GetModuleHandle(NULL),
+ NULL);
+
+ SetWindowPos(hwndToolTips, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+
+ ZeroMemory(&ti, sizeof(ti));
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = hwnd;
+ ti.uId = (UINT_PTR)hwnd;
+ if (SendMessage(hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
+ ti.uId = (UINT_PTR)hwnd;
+ ti.lpszText = (TCHAR*)tip;
+ SendMessage(hwndToolTips,TTM_ADDTOOL, 0, (LPARAM)&ti);
+
+ LeaveCriticalSection(&csTips);
+ return hwndToolTips;
+}
+
+
+
+typedef struct _MButton
+{
+ HWND hwnd;
+ BYTE ConstrainPositionFrom; //(BBRRTTLL) L = 0 - from left, L = 1 from right, L = 2 from center
+ int OrL,OrR,OrT,OrB;
+ int minW,minH;
+ ModernSkinButtonCtrl * bct;
+
+} MButton;
+MButton * Buttons = NULL;
+DWORD ButtonsCount = 0;
+
+#define _center_h( rc ) (((rc)->right + (rc)->left ) >> 1)
+#define _center_v( rc ) (((rc)->bottom + (rc)->top ) >> 1)
+
+int ModernSkinButton_AddButton(HWND parent,
+ char * ID,
+ char * CommandService,
+ char * StateDefService,
+ char * HandeService,
+ int Left,
+ int Top,
+ int Right,
+ int Bottom,
+ DWORD sbFlags,
+ TCHAR * Hint,
+ char * DBkey,
+ char * TypeDef,
+ int MinWidth, int MinHeight)
+{
+ // if (!parent) return 0;
+ if (!ModernSkinButtonModuleIsLoaded) return 0;
+ if (!Buttons)
+ Buttons = (MButton*)mir_alloc(sizeof(MButton));
+ else
+ Buttons = (MButton*)mir_realloc(Buttons,sizeof(MButton)*(ButtonsCount+1));
+ {
+ //HWND hwnd;
+ RECT rc = {0};
+ ModernSkinButtonCtrl* bct;
+ int l,r,b,t;
+ if (parent) GetClientRect(parent,&rc);
+ l = ( sbFlags & SBF_ALIGN_TL_RIGHT ) ? ( rc.right + Left ) :
+ ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Left ) :
+ ( rc.left + Left );
+
+ t = ( sbFlags & SBF_ALIGN_TL_BOTTOM ) ? ( rc.bottom + Top ) :
+ ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Top ) :
+ ( rc.top+Top );
+
+ r = ( sbFlags & SBF_ALIGN_BR_RIGHT ) ? ( rc.right + Right ) :
+ ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Right ) :
+ ( rc.left + Right );
+
+ b = ( sbFlags & SBF_ALIGN_BR_BOTTOM ) ? ( rc.bottom + Bottom ) :
+ ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Bottom ) :
+ ( rc.top + Bottom );
+ bct = (ModernSkinButtonCtrl *)mir_alloc(sizeof(ModernSkinButtonCtrl));
+ memset(bct, 0, sizeof(ModernSkinButtonCtrl));
+ bct->Left = l;
+ bct->Right = r;
+ bct->Top = t;
+ bct->Bottom = b;
+ bct->fCallOnPress = ( sbFlags & SBF_CALL_ON_PRESS ) != 0;
+ bct->HandleService = mir_strdup(HandeService);
+ bct->CommandService = mir_strdup(CommandService);
+ bct->StateService = mir_strdup(StateDefService);
+ if (DBkey && &DBkey != '\0') bct->ValueDBSection = mir_strdup(DBkey); else bct->ValueDBSection = NULL;
+ if (TypeDef && &TypeDef != '\0') bct->ValueTypeDef = mir_strdup(TypeDef); else bct->ValueTypeDef = mir_strdup("sDefault");
+ bct->ID=mir_strdup(ID);
+ bct->Hint = mir_tstrdup(Hint);
+ Buttons[ButtonsCount].bct = bct;
+ Buttons[ButtonsCount].hwnd = NULL;
+ Buttons[ButtonsCount].OrL = Left;
+ Buttons[ButtonsCount].OrT = Top;
+ Buttons[ButtonsCount].OrR = Right;
+ Buttons[ButtonsCount].OrB = Bottom;
+ Buttons[ButtonsCount].ConstrainPositionFrom = (BYTE)sbFlags;
+ Buttons[ButtonsCount].minH = MinHeight;
+ Buttons[ButtonsCount].minW = MinWidth;
+ ButtonsCount++;
+ // CLUI_ShowWindowMod(hwnd,SW_SHOW);
+ }
+ return 0;
+}
+
+
+
+static int ModernSkinButtonErase(int l,int t,int r, int b)
+{
+ DWORD i;
+ if (!ModernSkinButtonModuleIsLoaded) return 0;
+ if (!g_CluiData.fLayered) return 0;
+ if (!g_pCachedWindow) return 0;
+ if (!g_pCachedWindow->hImageDC || !g_pCachedWindow->hBackDC) return 0;
+ if (!(l || r || t || b))
+ {
+ for (i=0; i < ButtonsCount; i++)
+ {
+ if (pcli->hwndContactList && Buttons[i].hwnd != NULL)
+ {
+ //TODO: Erase button
+ BitBlt(g_pCachedWindow->hImageDC,Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right-Buttons[i].bct->Left,Buttons[i].bct->Bottom-Buttons[i].bct->Top,
+ g_pCachedWindow->hBackDC,Buttons[i].bct->Left,Buttons[i].bct->Top,SRCCOPY);
+ }
+ }
+ }
+ else
+ {
+ BitBlt(g_pCachedWindow->hImageDC,l,t,r-l,b-t, g_pCachedWindow->hBackDC,l,t,SRCCOPY);
+ }
+ return 0;
+}
+
+static HWND ModernSkinButtonCreateWindow(ModernSkinButtonCtrl * bct, HWND parent)
+{
+ HWND hwnd;
+
+ if (bct == NULL) return FALSE;
+ {
+ TCHAR *UnicodeID;
+ UnicodeID = mir_a2u(bct->ID);
+ hwnd = CreateWindow(_T(MODERNSKINBUTTONCLASS),UnicodeID,WS_VISIBLE|WS_CHILD,bct->Left,bct->Top,bct->Right-bct->Left,bct->Bottom-bct->Top,parent,NULL,g_hInst,NULL);
+ mir_free(UnicodeID);
+ }
+
+ bct->hwnd = hwnd;
+ bct->focus = 0;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)bct);
+ return hwnd;
+}
+
+int ModernSkinButtonRedrawAll(HDC hdc)
+{
+ DWORD i;
+ if (!ModernSkinButtonModuleIsLoaded) return 0;
+ g_mutex_bLockUpdating++;
+ for (i=0; i < ButtonsCount; i++)
+ {
+ if (pcli->hwndContactList && Buttons[i].hwnd == NULL)
+ Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,pcli->hwndContactList);
+ ModernSkinButtonPaintWorker(Buttons[i].hwnd,0);
+ }
+ g_mutex_bLockUpdating--;
+ return 0;
+}
+
+int ModernSkinButtonDeleteAll()
+{
+ if (!ModernSkinButtonModuleIsLoaded)
+ return 0;
+
+ for (size_t i=0; i < ButtonsCount; i++)
+ if (Buttons[i].hwnd)
+ DestroyWindow(Buttons[i].hwnd);
+
+ mir_free_and_nil(Buttons);
+ ButtonsCount = 0;
+ return 0;
+}
+
+int ModernSkinButton_ReposButtons(HWND parent, BYTE draw, RECT *r)
+{
+ DWORD i;
+ RECT rc;
+ RECT clr;
+ RECT rd;
+ BOOL altDraw = FALSE;
+ static SIZE oldWndSize = {0};
+ if (!ModernSkinButtonModuleIsLoaded) return 0;
+ GetWindowRect(parent,&rd);
+ GetClientRect(parent,&clr);
+ if (!r)
+ GetWindowRect(parent,&rc);
+ else
+ rc = *r;
+ if (g_CluiData.fLayered && ( draw & SBRF_DO_ALT_DRAW ))
+ {
+ int sx,sy;
+ sx = rd.right-rd.left;
+ sy = rd.bottom-rd.top;
+ if (sx != oldWndSize.cx || sy != oldWndSize.cy)
+ altDraw = TRUE;//EraseButtons();
+ oldWndSize.cx = sx;
+ oldWndSize.cy = sy;
+ }
+
+ OffsetRect(&rc,-rc.left,-rc.top);
+ rc.right = rc.left+(clr.right-clr.left);
+ rc.bottom = rc.top+(clr.bottom-clr.top);
+ for (i=0; i < ButtonsCount; i++)
+ {
+ int l,r,b,t;
+ RECT oldRect = {0};
+ int sbFlags = Buttons[i].ConstrainPositionFrom;
+ if (parent && Buttons[i].hwnd == NULL)
+ {
+ Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct,parent);
+ altDraw = FALSE;
+ }
+
+ l = ( sbFlags & SBF_ALIGN_TL_RIGHT ) ? ( rc.right + Buttons[i].OrL ) :
+ ( sbFlags & SBF_ALIGN_TL_HCENTER ) ? ( _center_h( &rc ) + Buttons[i].OrL ) :
+ ( rc.left + Buttons[i].OrL );
+
+ t = ( sbFlags & SBF_ALIGN_TL_BOTTOM ) ? ( rc.bottom + Buttons[i].OrT ) :
+ ( sbFlags & SBF_ALIGN_TL_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrT ) :
+ ( rc.top + Buttons[i].OrT );
+
+ r = ( sbFlags & SBF_ALIGN_BR_RIGHT ) ? ( rc.right + Buttons[i].OrR ) :
+ ( sbFlags & SBF_ALIGN_BR_HCENTER ) ? ( _center_h( &rc) + Buttons[i].OrR ) :
+ ( rc.left + Buttons[i].OrR );
+
+ b = ( sbFlags & SBF_ALIGN_BR_BOTTOM ) ? ( rc.bottom + Buttons[i].OrB ) :
+ ( sbFlags & SBF_ALIGN_BR_VCENTER ) ? ( _center_v( &rc ) + Buttons[i].OrB ) :
+ ( rc.top + Buttons[i].OrB );
+
+ SetWindowPos(Buttons[i].hwnd,HWND_TOP,l,t,r-l,b-t,0);
+ if ( (rc.right-rc.left < Buttons[i].minW /* && Buttons[i].minW != 0*/)
+ || (rc.bottom-rc.top < Buttons[i].minH /* && Buttons[i].minH != 0*/))
+ CLUI_ShowWindowMod(Buttons[i].hwnd,SW_HIDE);
+ else
+ CLUI_ShowWindowMod(Buttons[i].hwnd,SW_SHOW);
+ if ((1 || altDraw) &&
+ (Buttons[i].bct->Left != l ||
+ Buttons[i].bct->Top != t ||
+ Buttons[i].bct->Right != r ||
+ Buttons[i].bct->Bottom != b))
+ {
+ //Need to erase in old location
+ ModernSkinButtonErase(Buttons[i].bct->Left,Buttons[i].bct->Top,Buttons[i].bct->Right,Buttons[i].bct->Bottom);
+ }
+
+ Buttons[i].bct->Left = l;
+ Buttons[i].bct->Top = t;
+ Buttons[i].bct->Right = r;
+ Buttons[i].bct->Bottom = b;
+
+
+ }
+ if ( draw & SBRF_DO_REDRAW_ALL ) ModernSkinButtonRedrawAll(0);
+ return 0;
} \ No newline at end of file
diff --git a/plugins/Clist_modern/src/modern_skinengine.cpp b/plugins/Clist_modern/src/modern_skinengine.cpp
index 48965be1f0..ba02bcb6df 100644
--- a/plugins/Clist_modern/src/modern_skinengine.cpp
+++ b/plugins/Clist_modern/src/modern_skinengine.cpp
@@ -1,4145 +1,4140 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
-Copyright (c) 2000-08 Miranda ICQ/IM project,
-all portions of this codebase are copyrighted to the people
-listed in contributors.txt.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-//Include
-#include "hdr/modern_commonheaders.h"
-#include <m_png.h>
-#include "m_api/m_skin_eng.h"
-#include "hdr/modern_skinselector.h"
-#include "CLUIFrames/cluiframes.h"
-
-#define _EFFECTENUM_FULL_H
-#include "hdr/modern_effectenum.h"
-#undef _EFFECTENUM_FULL_H
-
-#include "hdr/modern_skinengine.h"
-#include "hdr/modern_commonprototypes.h"
-#include "hdr/modern_sync.h"
-//Implementation
-
-/* Global variables */
-
-SKINOBJECTSLIST g_SkinObjectList = {0};
-CURRWNDIMAGEDATA *g_pCachedWindow = NULL;
-
-BOOL g_flag_bPostWasCanceled = FALSE;
-BOOL g_flag_bFullRepaint = FALSE;
-BOOL g_mutex_bLockUpdating = FALSE;
-
-SortedList *gl_plGlyphTexts = NULL;
-SortedList *gl_plSkinFonts = NULL;
-
-/* Private module variables */
-
-static HANDLE hSkinLoadedEvent;
-
-static GLYPHIMAGE *pLoadedImages = NULL;
-static DWORD dwLoadedImagesCount = 0;
-static DWORD dwLoadedImagesAlocated = 0;
-
-static BOOL flag_bUpdateQueued = FALSE;
-static BOOL flag_bJustDrawNonFramedObjects = FALSE;
-static BOOL mutex_bLockUpdate = FALSE;
-
-static LIST<EFFECTSSTACKITEM> arEffectStack(10, HandleKeySortT);
-static SKINOBJECTSLIST *pCurrentSkin = NULL;
-static char **pszSettingName = NULL;
-static int nArrayLen = 0;
-
-static BYTE pbGammaWeight[256] = {0};
-static BYTE pbGammaWeightAdv[256] = {0};
-static BOOL bGammaWeightFilled = FALSE;
-
-static CRITICAL_SECTION cs_SkinChanging = {0};
-
-static LISTMODERNMASK *MainModernMaskList = NULL;
-
-/* Private module procedures */
-static BOOL ske_GetMaskBit(BYTE *line, int x);
-static INT_PTR ske_Service_AlphaTextOut(WPARAM wParam, LPARAM lParam);
-static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, LPARAM lParam);
-
-static int ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor);
-static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin);
-static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin);
-static int ske_DeleteAllSettingInSection(char * SectionName);
-static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin);
-static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType,SKINOBJECTSLIST* Skin);
-static int ske_LoadSkinFromResource(BOOL bOnlyObjects);
-static void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult);
-static int ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting);
-static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam);
-static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam);
-static INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam);
-
-static MODERNEFFECT meCurrentEffect = {-1,{0}, 0, 0};
-
-
-//////////////////////////////////////////////////////////////////////////
-// Ini file parser
-//////////////////////////////////////////////////////////////////////////
-IniParser::IniParser(TCHAR * tcsFileName, BYTE flags) : _Flags(flags)
-{
- _DoInit();
- if (!tcsFileName) return;
-
- if (tcsFileName[0] == _T('%'))
- {
- //TODO: Add parser of resource filename here
- _LoadResourceIni(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF");
- return;
- }
-
- _hFile = _tfopen(tcsFileName, _T("r"));
-
- if (_hFile != NULL)
- {
- _eType = IT_FILE;
- _isValid = true;
- }
-}
-
-IniParser::IniParser(HINSTANCE hInst, const char * resourceName, const char * resourceType, BYTE flags) : _Flags(flags)
-{
- _DoInit();
- _LoadResourceIni(hInst, resourceName, resourceType);
-}
-
-IniParser::~IniParser()
-{
- mir_free(_szSection);
- if (_hFile) fclose(_hFile);
- if (_hGlobalRes) {
- UnlockResource(_hGlobalRes);
- FreeResource(_hGlobalRes);
- }
-
- _szSection = NULL;
- _hGlobalRes = NULL;
- _hFile = NULL;
- _isValid = false;
- _eType = IT_UNKNOWN;
-}
-
-HRESULT IniParser::Parse(ParserCallback_t pLineCallBackProc, LPARAM SecCheck)
-{
- if (_isValid && pLineCallBackProc)
- {
- _pLineCallBackProc = pLineCallBackProc;
- _SecCheck = SecCheck;
- switch (_eType) {
- case IT_FILE:
- return _DoParseFile();
- case IT_RESOURCE:
- return _DoParseResource();
- }
- }
- return E_FAIL;
-}
-
-HRESULT IniParser::WriteStrToDb( const char * szSection, const char * szName, const char * szValue, IniParser * This )
-{
- if ( This->_SecCheck) {
- //TODO check security here
- if ( wildcmp( szSection,"Skin_Description_Section"))
- return S_OK;
- }
- if (( This->_Flags == IniParser::FLAG_ONLY_OBJECTS ) && !wildcmp( szSection, DEFAULTSKINSECTION))
- return S_OK; // skip not objects
-
- switch (szValue[0]) {
- case 'b':
- db_set_b(NULL, szSection, szName, (BYTE)atoi(szValue + 1));
- break;
-
- case 'w':
- db_set_w(NULL, szSection, szName, (WORD)atoi(szValue + 1));
- break;
-
- case 'd':
- db_set_dw(NULL, szSection, szName, (DWORD)atoi(szValue + 1));
- break;
-
- case 's':
- db_set_s(NULL, szSection, szName, szValue + 1);
- break;
- }
- return S_OK;
-}
-
-int IniParser::GetSkinFolder( IN const TCHAR * szFileName, OUT TCHAR * pszFolderName )
-{
- TCHAR *szBuff = mir_tstrdup(szFileName);
- TCHAR *pszPos = szBuff + _tcslen(szBuff);
- while ( pszPos > szBuff && *pszPos != _T('.')) { pszPos--; }
- *pszPos = _T('\0');
- _tcscpy( pszFolderName, szBuff );
-
- TCHAR custom_folder[MAX_PATH];
- TCHAR cus[MAX_PATH];
- TCHAR *b3;
- _tcscpy( custom_folder, pszFolderName );
- b3 = custom_folder + _tcslen( custom_folder );
- while ( b3 > custom_folder && *b3 != _T('\\')) { b3--; }
- *b3 = _T('\0');
-
- GetPrivateProfileString(_T("Skin_Description_Section"),_T("SkinFolder"),_T(""),cus,SIZEOF(custom_folder),szFileName);
- if (cus[0] != 0)
- mir_sntprintf(pszFolderName, MAX_PATH, _T("%s\\%s"), custom_folder, cus);
-
- mir_free(szBuff);
- PathToRelativeT(pszFolderName, pszFolderName);
- return 0;
-}
-
-void IniParser::_DoInit()
-{
- _isValid = false;
- _eType = IT_UNKNOWN;
- _szSection = NULL;
- _hFile = NULL;
- _hGlobalRes = NULL;
- _dwSizeOfRes = 0;
- _pPosition = NULL;
- _pLineCallBackProc = NULL;
- _SecCheck = 0;
-}
-
-void IniParser::_LoadResourceIni( HINSTANCE hInst, const char * resourceName, const char * resourceType )
-{
- if (_eType != IT_UNKNOWN)
- return;
-
- HRSRC hRSrc = FindResourceA(hInst, resourceName, resourceType);
- if (!hRSrc)
- return;
-
- _hGlobalRes = LoadResource(hInst, hRSrc);
- if (!_hGlobalRes)
- return;
-
- _dwSizeOfRes = SizeofResource(hInst, hRSrc);
- _pPosition = (char*)LockResource(_hGlobalRes);
-
- _isValid = true;
- _eType = IT_RESOURCE;
-}
-
-HRESULT IniParser::_DoParseFile()
-{
- char szLine[MAX_LINE_LEN];
- _nLine = 0;
- while (fgets(szLine, SIZEOF(szLine), _hFile) != NULL) {
- size_t len = 0;
- char * pLine = (char*)_RemoveTailings(szLine, len);
- if (len > 0) {
- pLine[len] = '\0';
- if (!_DoParseLine(pLine)) return E_FAIL;
- }
- else _nLine++;
- };
-
- return S_OK;
-}
-
-HRESULT IniParser::_DoParseResource()
-{
- _nLine = 0;
- char szLine[MAX_LINE_LEN];
- char * pos = (char*)_pPosition;
-
- while (pos < _pPosition + _dwSizeOfRes) {
- int i = 0;
- while (pos < _pPosition + _dwSizeOfRes && *pos != '\n' && *pos != '\0' && i < MAX_LINE_LEN - 1) {
- if ((*pos) != '\r')
- szLine[i++] = *pos;
- pos++;
- }
- szLine[i] = '\0';
- pos++;
-
- size_t len = 0;
- char * pLine = (char*)_RemoveTailings(szLine, len);
- if (len > 0) {
- pLine[len] = '\0';
- if (!_DoParseLine(pLine)) return E_FAIL;
- }
- else _nLine++;
- }
- return S_OK;
-}
-
-const char * IniParser::_RemoveTailings( const char * szLine, size_t& len )
-{
- const char * pStart = szLine;
- while (*pStart == ' ' || *pStart == '\t')
- pStart++; //skip spaces at begin
- const char * pEnd = pStart + strlen(pStart);
- while (pEnd > pStart && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n' || *pEnd == '\r'))
- pEnd--;
-
- len = pEnd - pStart;
- return pStart;
-}
-
-BOOL IniParser::_DoParseLine( char * szLine )
-{
- _nLine++;
- DWORD len = strlen( szLine );
-
- if (len == 0) return TRUE;
-
- switch( szLine[0] ) {
- case ';':
- return TRUE; // start of comment is found
-
- case '[':
- //New section start here
- mir_free(_szSection);
- _szSection = NULL;
- {
- char *tbuf = szLine + 1; // skip [
-
- char *ebuf = tbuf;
-
- while (*ebuf != ']' && *ebuf != '\0') ebuf++;
- if (*ebuf == '\0')
- return FALSE; // no close bracket
-
- DWORD sectionLen = ebuf - tbuf;
- _szSection = (char*)mir_alloc(sectionLen + 1);
- strncpy(_szSection, tbuf, sectionLen);
- _szSection[sectionLen] = '\0';
- }
- return TRUE;
-
- default:
- if (!_szSection )
- return TRUE; //param found out of section
-
- char *keyName = szLine;
- char *keyValue = szLine;
-
- DWORD eqPlace = 0;
- DWORD len2 = strlen(keyName);
-
- while ( eqPlace < len2 && keyName[ eqPlace ] != '=' )
- eqPlace++; //find '='
-
- if (eqPlace == 0 || eqPlace == len2)
- return TRUE; // = not found or no key name //say false
-
- keyName[eqPlace] = '\0';
-
- keyValue = keyName + eqPlace + 1;
-
- //remove tail spaces in Name
- {
- DWORD len3 = strlen(keyName);
- int j = len3-1;
- while (j>0 && (keyName[j] == ' ' || keyName[j] == '\t')) j--;
- if (j >= 0) keyName[j+1] = '\0';
- }
- //remove start spaces in Value
- {
- DWORD len3 = strlen(keyValue);
- DWORD j = 0;
- while (j < len3 && (keyValue[j] == ' ' || keyValue[j] == '\t')) j++;
- if (j < len3) keyValue += j;
- }
- //remove tail spaces in Value
- {
- DWORD len3 = strlen(keyValue);
- int j = len3-1;
- while (j>0 && (keyValue[j] == ' ' || keyValue[j] == '\t' || keyValue[j] == '\n')) j--;
- if (j >= 0) keyValue[j+1] = '\0';
- }
- _pLineCallBackProc( _szSection, keyName, keyValue, this );
- }
- return TRUE;
-}
-//////////////////////////////////////////////////////////////////////////
-// End of IniParser
-//////////////////////////////////////////////////////////////////////////
-
-HRESULT SkinEngineLoadModule()
-{
- ModernSkinButtonLoadModule();
- InitializeCriticalSection(&cs_SkinChanging);
- MainModernMaskList = (LISTMODERNMASK*)mir_calloc(sizeof(LISTMODERNMASK));
- //init variables
- g_SkinObjectList.dwObjLPAlocated = 0;
- g_SkinObjectList.dwObjLPReserved = 0;
- g_SkinObjectList.pObjects = NULL;
- // Initialize GDI+
- InitGdiPlus();
- AniAva_InitModule();
- //create services
- CreateServiceFunction(MS_SKIN_DRAWGLYPH,ske_Service_DrawGlyph);
- CreateServiceFunction(MS_SKINENG_UPTATEFRAMEIMAGE,ske_Service_UpdateFrameImage);
- CreateServiceFunction(MS_SKINENG_INVALIDATEFRAMEIMAGE,ske_Service_InvalidateFrameImage);
- CreateServiceFunction(MS_SKINENG_ALPHATEXTOUT,ske_Service_AlphaTextOut);
- CreateServiceFunction(MS_SKINENG_DRAWICONEXFIX,ske_Service_DrawIconEx);
-
- CreateServiceFunction(MS_DRAW_TEXT_WITH_EFFECT,ske_Service_DrawTextWithEffect);
-
- //create event handle
- hSkinLoadedEvent = HookEvent(ME_SKIN_SERVICESCREATED,CLUI_OnSkinLoad);
- NotifyEventHooks(g_CluiData.hEventSkinServicesCreated, 0, 0);
- return S_OK;
-}
-
-int SkinEngineUnloadModule()
-{
- //unload services
- ModernSkinButtonUnloadModule(0, 0);
- ske_UnloadSkin(&g_SkinObjectList);
-
- mir_free_and_nil(g_SkinObjectList.pObjects);
- mir_free_and_nil(g_SkinObjectList.pMaskList);
- mir_free_and_nil(MainModernMaskList);
-
- for (int i=0; i < arEffectStack.getCount(); i++)
- mir_free(arEffectStack[i]);
- arEffectStack.destroy();
-
- if (g_pCachedWindow) {
- SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld);
- SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld);
- DeleteObject(g_pCachedWindow->hBackDIB);
- DeleteObject(g_pCachedWindow->hImageDIB);
- DeleteDC(g_pCachedWindow->hBackDC);
- DeleteDC(g_pCachedWindow->hImageDC);
- ReleaseDC(NULL,g_pCachedWindow->hScreenDC);
- mir_free_and_nil(g_pCachedWindow);
- }
- DeleteCriticalSection(&cs_SkinChanging);
- GdiFlush();
- DestroyHookableEvent(g_CluiData.hEventSkinServicesCreated);
- AniAva_UnloadModule();
- ShutdownGdiPlus();
- //free variables
- return 1;
-}
-
-BOOL ske_AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int nHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction)
-{
- if (g_CluiData.fDisableSkinEngine && !(blendFunction.BlendFlags&128))
- {
- if (nWidthDest != nWidthSrc || nHeightDest != nHeightSrc)
- return StretchBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc, SRCCOPY);
- else
- return BitBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc, SRCCOPY);
- }
-
- if (blendFunction.BlendFlags&128) //Use gdi+ engine
- {
- return GDIPlus_AlphaBlend( hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,
- hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,
- &blendFunction);
- }
- blendFunction.BlendFlags &= ~128;
- return AlphaBlend(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,blendFunction);
-}
-
-static int ske_LockSkin()
-{
- EnterCriticalSection(&cs_SkinChanging);
- return 0;
-}
-
-static int ske_UnlockSkin()
-{
- LeaveCriticalSection(&cs_SkinChanging);
- return 0;
-}
-
-struct DCBUFFER
-{
- HDC hdcOwnedBy;
- int nUsageID;
- int width;
- int height;
- void* pImage;
- HDC hDC;
- HBITMAP oldBitmap;
- HBITMAP hBitmap;
- DWORD dwDestroyAfterTime;
-};
-
-static int SortBufferList(const DCBUFFER *buf1, const DCBUFFER *buf2)
-{
- if (buf1->hdcOwnedBy != buf2->hdcOwnedBy) return (int)(buf1->hdcOwnedBy < buf2->hdcOwnedBy);
- else if (buf1->nUsageID != buf2->nUsageID) return (int)(buf1->nUsageID < buf2->nUsageID);
- else return (int)(buf1->hDC < buf2->hDC);
-}
-
-LIST<DCBUFFER> BufferList(2, SortBufferList);
-CRITICAL_SECTION BufferListCS = {0};
-
-enum
-{
- BUFFER_DRAWICON = 0,
- BUFFER_DRAWIMAGE
-};
-
-HDC ske_RequestBufferDC(HDC hdcOwner, int dcID, int width, int height, BOOL fClear)
-{
- mir_cslock lck(BufferListCS);
- //Try to find DC in buffer list
- DCBUFFER buf;
- buf.hdcOwnedBy = hdcOwner;
- buf.nUsageID = dcID;
- buf.hDC = NULL;
- DCBUFFER *pBuf = BufferList.find(&buf);
- if (!pBuf) {
- //if not found - allocate it
- pBuf = (DCBUFFER *)mir_alloc(sizeof(DCBUFFER));
- *pBuf = buf;
- pBuf->width = width;
- pBuf->height = height;
- pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage));
- pBuf->hDC = CreateCompatibleDC(hdcOwner);
- pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap);
- pBuf->dwDestroyAfterTime = 0;
- BufferList.insert(pBuf);
- }
- else
- {
- if (pBuf->width != width || pBuf->height != height)
- {
- //resize
- SelectObject(pBuf->hDC,pBuf->oldBitmap);
- DeleteObject(pBuf->hBitmap);
- pBuf->width = width;
- pBuf->height = height;
- pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage));
- pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap);
- } else if (fClear)
- memset(pBuf->pImage, 0, width*height*sizeof(DWORD));
- }
- pBuf->dwDestroyAfterTime = 0;
- return pBuf->hDC;
-}
-
-int ske_ReleaseBufferDC(HDC hDC, int keepTime)
-{
- DWORD dwCurrentTime = GetTickCount();
-
- //Try to find DC in buffer list - set flag to be release after time;
- mir_cslock lck(BufferListCS);
- for (int i=0; i < BufferList.getCount(); i++) {
- DCBUFFER *pBuf = BufferList[i];
- if (pBuf) {
- if (hDC != NULL && pBuf->hDC == hDC) {
- pBuf->dwDestroyAfterTime = dwCurrentTime+keepTime;
- break;
- }
-
- if ((pBuf->dwDestroyAfterTime && pBuf->dwDestroyAfterTime < dwCurrentTime) || keepTime == -1) {
- SelectObject(pBuf->hDC,pBuf->oldBitmap);
- DeleteObject(pBuf->hBitmap);
- DeleteDC(pBuf->hDC);
- mir_free(pBuf);
- BufferList.remove(i);
- i--;
- }
- }
- }
- return 0;
-}
-
-BOOL ske_SetRgnOpaque(HDC memdc,HRGN hrgn, BOOL force)
-{
- RGNDATA * rdata;
- DWORD rgnsz;
- DWORD d;
- RECT *rect;
- if (g_CluiData.fDisableSkinEngine && !force) return TRUE;
- rgnsz = GetRegionData(hrgn, 0, NULL);
- rdata = (RGNDATA *) mir_alloc(rgnsz);
- GetRegionData(hrgn,rgnsz,rdata);
- rect = (RECT *)rdata->Buffer;
- for (d = 0; d < rdata->rdh.nCount; d++)
- {
- ske_SetRectOpaque(memdc,&rect[d], force);
- }
- mir_free(rdata);
- return TRUE;
-}
-
-
-BOOL ske_SetRectOpaque(HDC memdc,RECT *fr, BOOL force)
-{
- int f = 0;
- BYTE * bits;
- BITMAP bmp;
- HBITMAP hbmp;
-
- if ( g_CluiData.fDisableSkinEngine && !force )
- return TRUE;
-
- hbmp = (HBITMAP)GetCurrentObject( memdc,OBJ_BITMAP );
- GetObject( hbmp, sizeof(bmp), &bmp );
-
- if ( bmp.bmPlanes != 1 )
- return FALSE;
-
- if (!bmp.bmBits)
- {
- f = 1;
- bits = (BYTE*)malloc(bmp.bmWidthBytes*bmp.bmHeight);
- GetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits);
- }
- else
- bits = (BYTE*)bmp.bmBits;
-
- int sx = ( fr->left > 0 ) ? fr->left : 0;
- int sy = ( fr->top > 0 ) ? fr->top : 0;
- int ex = ( fr->right < bmp.bmWidth ) ? fr->right : bmp.bmWidth;
- int ey = ( fr->bottom < bmp.bmHeight) ? fr->bottom : bmp.bmHeight;
-
- int width = ex-sx;
-
- BYTE* pLine = ((BYTE*)bits) + (bmp.bmHeight-sy-1)*bmp.bmWidthBytes + (sx << 2) + 3;
- for ( int y = 0; y < (ey - sy); y++ )
- {
- BYTE * pColumn = pLine;
- for ( int x = 0; x < width; x++ )
- {
- *pColumn = 255;
- pColumn += 4;
- }
- pLine -= bmp.bmWidthBytes;
- }
- if (f)
- {
- SetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits);
- free(bits);
- }
- // DeleteObject(hbmp);
- return 1;
-}
-
-static BOOL ske_SkinFillRectByGlyph(HDC hDest, HDC hSource, RECT *rFill, RECT *rGlyph, RECT *rClip, BYTE mode, BYTE drawMode, int depth)
-{
- int destw = 0, desth = 0;
- int xstart = 0, xmax = 0;
- int ystart = 0, ymax = 0;
- BLENDFUNCTION bfa = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
- BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
-
- //initializations
- if (mode == FM_STRETCH)
- {
- HDC mem2dc;
- HBITMAP mem2bmp, oldbmp;
- RECT wr;
- IntersectRect(&wr,rClip,rFill);
- if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
- if (drawMode != 2)
- {
- mem2dc = CreateCompatibleDC(hDest);
- mem2bmp = ske_CreateDIB32(wr.right-wr.left,wr.bottom-wr.top);
- oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
-
- }
-
- if (drawMode == 0 || drawMode == 2)
- {
- if (drawMode == 0)
- {
- ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top,
- hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
- ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf);
- }
- else
- {
- ske_AlphaBlend(hDest,rFill->left,rFill->top,rFill->right-rFill->left,rFill->bottom-rFill->top,
- hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
-
- }
- }
- else
- {
- // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
- ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top,
- hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
- ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf);
- }
- if (drawMode != 2)
- {
- SelectObject(mem2dc,oldbmp);
- DeleteObject(mem2bmp);
- DeleteDC(mem2dc);
- }
- return 1;
- }
- else if (mode == FM_TILE_VERT && (rGlyph->bottom-rGlyph->top>0) && (rGlyph->right-rGlyph->left>0))
- {
- HDC mem2dc;
- HBITMAP mem2bmp,oldbmp;
- RECT wr;
- IntersectRect(&wr,rClip,rFill);
- if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
- mem2dc = CreateCompatibleDC(hDest);
- //SetStretchBltMode(mem2dc, HALFTONE);
- mem2bmp = ske_CreateDIB32(wr.right-wr.left, rGlyph->bottom-rGlyph->top);
- oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
- if (!oldbmp)
- return 0;
-
- /// draw here
- {
- int y = 0, sy = 0, maxy = 0;
- int w = rFill->right-rFill->left;
- int h = rGlyph->bottom-rGlyph->top;
- if (h>0 && (wr.bottom-wr.top)*(wr.right-wr.left) != 0)
- {
- w = wr.right-wr.left;
- {
- // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
- ske_AlphaBlend(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,bf);
- //StretchBlt(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,SRCCOPY);
- }
- if (drawMode == 0 || drawMode == 2)
- {
- if (drawMode == 0 )
- {
-
- int dy;
- dy = (wr.top-rFill->top)%h;
- if (dy >= 0)
- {
- int ht;
- y = wr.top;
- ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top);
- BitBlt(hDest,wr.left,y,w,ht,mem2dc, 0, dy,SRCCOPY);
- }
-
- y = wr.top+h-dy;
- while (y < wr.bottom-h){
- BitBlt(hDest,wr.left,y,w,h,mem2dc, 0, 0, SRCCOPY);
- y += h;
- }
- if (y <= wr.bottom)
- BitBlt(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, SRCCOPY);
-
- }
- else
- {
- y = wr.top;
- while (y < wr.bottom-h)
- {
- // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
- ske_AlphaBlend(hDest,wr.left,y,w,h, mem2dc, 0, 0, w,h,bf);
- y += h;
- }
- if (y <= wr.bottom)
- {
- // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
- ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf);
- }
- }
-
- }
- else
- {
- int dy;
-
- BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
-
- dy = (wr.top-rFill->top)%h;
-
- if (dy >= 0)
- {
- int ht;
- y = wr.top;
- ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top);
- ske_AlphaBlend(hDest,wr.left,y,w,ht,mem2dc, 0, dy,w,ht,bf);
- }
-
- y = wr.top+h-dy;
- while (y < wr.bottom-h)
- {
- ske_AlphaBlend(hDest,wr.left,y,w,h,mem2dc, 0, 0, w,h,bf);
- y += h;
- }
- if (y <= wr.bottom)
- ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf);
- }
- }
- }
- SelectObject(mem2dc,oldbmp);
- DeleteObject(mem2bmp);
- DeleteDC(mem2dc);
- }
- else if (mode == FM_TILE_HORZ && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0) && (rFill->bottom-rFill->top)>0 && (rFill->right-rFill->left)>0)
- {
- HDC mem2dc;
- RECT wr;
- HBITMAP mem2bmp,oldbmp;
- int w = rGlyph->right-rGlyph->left;
- int h = rFill->bottom-rFill->top;
- IntersectRect(&wr,rClip,rFill);
- if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
- h = wr.bottom-wr.top;
- mem2dc = CreateCompatibleDC(hDest);
-
- mem2bmp = ske_CreateDIB32(w,h);
- oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
-
- if (!oldbmp)
- return 0;
- /// draw here
- {
- int x = 0, sy = 0, maxy = 0;
- {
- //SetStretchBltMode(mem2dc, HALFTONE);
- //StretchBlt(mem2dc, 0, 0, w,h,hSource,rGlyph->left+(wr.left-rFill->left),rGlyph->top,w,h,SRCCOPY);
-
- // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
- ske_AlphaBlend(mem2dc, 0, -(wr.top-rFill->top),w,rFill->bottom-rFill->top,hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf);
- if (drawMode == 0 || drawMode == 2)
- {
- if (drawMode == 0)
- {
-
- int dx;
- dx = (wr.left-rFill->left)%w;
- if (dx >= 0)
- {
- int wt;
- x = wr.left;
- wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
- BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY);
- }
- x = wr.left+w-dx;
- while (x < wr.right-w){
- BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY);
- x += w;
- }
- if (x <= wr.right)
- BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY);
- }
- else
- {
- int dx;
- dx = (wr.left-rFill->left)%w;
- x = wr.left-dx;
- while (x < wr.right-w){
- ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
- x += w;
- }
- if (x <= wr.right)
- ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
- }
-
- }
- else
- {
- BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
- int dx;
- dx = (wr.left-rFill->left)%w;
- if (dx >= 0)
- {
- int wt;
- x = wr.left;
- wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
- ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf);
- }
- x = wr.left+w-dx;
- while (x < wr.right-w){
- ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
- x += w;
- }
- if (x <= wr.right)
- ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
-
- }
- }
- }
- SelectObject(mem2dc,oldbmp);
- DeleteObject(mem2bmp);
- DeleteDC(mem2dc);
- }
- else if (mode == FM_TILE_BOTH && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0))
- {
- HDC mem2dc;
- int w = rGlyph->right-rGlyph->left;
- int x = 0, sy = 0, maxy = 0;
- int h = rFill->bottom-rFill->top;
- HBITMAP mem2bmp,oldbmp;
- RECT wr;
- IntersectRect(&wr,rClip,rFill);
- if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
- mem2dc = CreateCompatibleDC(hDest);
- mem2bmp = ske_CreateDIB32(w,wr.bottom-wr.top);
- h = wr.bottom-wr.top;
- oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
-#ifdef _DEBUG
- if (!oldbmp)
- (NULL,"Tile bitmap not selected","ERROR", MB_OK);
-#endif
- /// draw here
- {
-
- //fill temp bitmap
- {
- int y;
- int dy;
- dy = (wr.top-rFill->top)%(rGlyph->bottom-rGlyph->top);
- y = -dy;
- while (y < wr.bottom-wr.top)
- {
-
- ske_AlphaBlend(mem2dc, 0, y,w,rGlyph->bottom-rGlyph->top, hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf);
- y += rGlyph->bottom-rGlyph->top;
- }
-
- //--
- //end temp bitmap
- if (drawMode == 0 || drawMode == 2)
- {
- if (drawMode == 0)
- {
-
- int dx;
- dx = (wr.left-rFill->left)%w;
- if (dx >= 0)
- {
- int wt;
- x = wr.left;
- wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
- BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY);
- }
- x = wr.left+w-dx;
- while (x < wr.right-w){
- BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY);
- x += w;
- }
- if (x <= wr.right)
- BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY);
- }
- else
- {
- int dx;
- dx = (wr.left-rFill->left)%w;
- x = wr.left-dx;
- while (x < wr.right-w){
- ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
- x += w;
- }
- if (x <= wr.right)
- ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
- }
-
- }
- else
- {
- BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
-
- int dx;
- dx = (wr.left-rFill->left)%w;
- if (dx >= 0)
- {
- int wt;
- x = wr.left;
- wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
- ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf);
- }
- x = wr.left+w-dx;
- while (x < wr.right-w){
- ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
- x += w;
- }
- if (x <= wr.right)
- ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
-
- }
- }
-
- }
- SelectObject(mem2dc,oldbmp);
- DeleteObject(mem2bmp);
- DeleteDC(mem2dc);
- }
- return 1;
-
-}
-
-HBITMAP ske_CreateDIB32(int cx, int cy)
-{
- return ske_CreateDIB32Point(cx,cy,NULL);
-}
-
-HBITMAP ske_CreateDIB32Point(int cx, int cy, void ** bits)
-{
- if (cx < 0 || cy < 0)
- return NULL;
-
- BITMAPINFO RGB32BitsBITMAPINFO = { 0 };
- RGB32BitsBITMAPINFO.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- RGB32BitsBITMAPINFO.bmiHeader.biWidth = cx;//bm.bmWidth;
- RGB32BitsBITMAPINFO.bmiHeader.biHeight = cy;//bm.bmHeight;
- RGB32BitsBITMAPINFO.bmiHeader.biPlanes = 1;
- RGB32BitsBITMAPINFO.bmiHeader.biBitCount = 32;
- // pointer used for direct Bitmap pixels access
-
- UINT *ptPixels;
- HBITMAP DirectBitmap = CreateDIBSection(NULL,
- (BITMAPINFO *)&RGB32BitsBITMAPINFO,
- DIB_RGB_COLORS,
- (void **)&ptPixels,
- NULL, 0);
- if ((DirectBitmap == NULL || ptPixels == NULL) && cx != 0 && cy != 0)
- {
-#ifdef _DEBUG
- MessageBoxA(NULL,"Object not allocated. Check GDI object count","ERROR",MB_OK|MB_ICONERROR);
- DebugBreak();
-#endif
- ;
- }
- else memset(ptPixels, 0, cx*cy*4);
- if (bits != NULL) *bits = ptPixels;
- return DirectBitmap;
-}
-
-HRGN ske_CreateOpaqueRgn(BYTE Level, bool Opaque)
-{
- if (!g_pCachedWindow)
- return NULL;
-
- RGBQUAD *buf = (RGBQUAD *) g_pCachedWindow->hImageDIBByte;
- if (buf == NULL)
- return NULL;
-
- unsigned int cRect = 64;
- PRGNDATA pRgnData = (PRGNDATA)malloc(sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
- memset(pRgnData, 0, sizeof(RGNDATAHEADER));
- pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
- pRgnData->rdh.iType = RDH_RECTANGLES;
-
- for (int y = 0; y < g_pCachedWindow->Height; ++y) {
- bool inside = false;
- bool lastin = false;
- unsigned int entry = 0;
-
- for (int x = 0; x < g_pCachedWindow->Width; ++x) {
- inside = Opaque ? (buf->rgbReserved > Level) : (buf->rgbReserved < Level);
- ++buf;
-
- if (inside != lastin) {
- if (inside) {
- lastin = true;
- entry = x;
- }
- else {
- if (pRgnData->rdh.nCount == cRect) {
- cRect = cRect + 64;
- pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
- }
- SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, x, g_pCachedWindow->Height - y + 1);
-
- pRgnData->rdh.nCount++;
- lastin = false;
- }
- }
- }
-
- if (lastin) {
- if (pRgnData->rdh.nCount == cRect) {
- cRect = cRect + 64;
- pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
- }
- SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, g_pCachedWindow->Width, g_pCachedWindow->Height - y + 1);
-
- pRgnData->rdh.nCount++;
- }
- }
-
- HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData);
- free(pRgnData);
- return hRgn;
-}
-
-static int ske_DrawSkinObject(SKINDRAWREQUEST * preq, GLYPHOBJECT * pobj)
-{
- HDC memdc = NULL, glyphdc = NULL;
- int k = 0;
- //BITMAP bmp = {0};
- HBITMAP membmp = 0, oldbmp = 0, oldglyph = 0;
- BYTE Is32Bit = 0;
- RECT PRect;
- POINT mode2offset = {0};
- int depth = 0;
- int mode = 0; //0-FastDraw, 1-DirectAlphaDraw, 2-BufferedAlphaDraw
-
- if (!(preq && pobj)) return -1;
- if ((!pobj->hGlyph || pobj->hGlyph == (HBITMAP)-1) && ((pobj->Style&7) == ST_IMAGE || (pobj->Style&7) == ST_FRAGMENT || (pobj->Style&7) == ST_SOLARIZE)) return 0;
- // Determine painting mode
- depth = GetDeviceCaps(preq->hDC,BITSPIXEL);
- depth = depth < 16?16:depth;
- Is32Bit = pobj->bmBitsPixel == 32;
- if ((!Is32Bit && pobj->dwAlpha == 255) && pobj->Style != ST_BRUSH) mode = 0;
- else if (pobj->dwAlpha == 255 && pobj->Style != ST_BRUSH) mode = 1;
- else mode = 2;
- // End painting mode
-
- //force mode
-
- if (preq->rcClipRect.bottom-preq->rcClipRect.top*preq->rcClipRect.right-preq->rcClipRect.left == 0)
- preq->rcClipRect = preq->rcDestRect;
- IntersectRect(&PRect,&preq->rcDestRect,&preq->rcClipRect);
- if (IsRectEmpty(&PRect))
- {
- return 0;
- }
- if (mode == 2)
- {
- memdc = CreateCompatibleDC(preq->hDC);
- membmp = ske_CreateDIB32(PRect.right-PRect.left,PRect.bottom-PRect.top);
- oldbmp = (HBITMAP)SelectObject(memdc,membmp);
- if (oldbmp == NULL)
- {
- if (mode == 2)
- {
- SelectObject(memdc,oldbmp);
- DeleteDC(memdc);
- DeleteObject(membmp);
- }
- return 0;
- }
- }
-
- if (mode != 2) memdc = preq->hDC;
- {
- if (pobj->hGlyph && pobj->hGlyph != (HBITMAP)-1)
- {
- glyphdc = CreateCompatibleDC(preq->hDC);
- if (!oldglyph)
- oldglyph = (HBITMAP)SelectObject(glyphdc,pobj->hGlyph);
- else
- SelectObject(glyphdc,pobj->hGlyph);
- }
- // Drawing
- {
- RECT rFill, rGlyph, rClip;
- if ((pobj->Style&7) == ST_BRUSH)
- {
- HBRUSH br = CreateSolidBrush(pobj->dwColor);
- RECT fr;
- if (mode == 2)
- {
- SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top);
- FillRect(memdc,&fr,br);
- ske_SetRectOpaque(memdc,&fr);
- // FillRectAlpha(memdc,&fr,pobj->dwColor|0xFF000000);
- }
- else
- {
- fr = PRect;
- // SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top);
- FillRect(preq->hDC,&fr,br);
- }
- DeleteObject(br);
- k = -1;
- }
- else
- {
- if (mode == 2)
- {
- mode2offset.x = PRect.left;
- mode2offset.y = PRect.top;
- OffsetRect(&PRect,-mode2offset.x,-mode2offset.y);
- }
- rClip = (preq->rcClipRect);
-
- {
- int lft = 0;
- int top = 0;
- int rgh = pobj->bmWidth;
- int btm = pobj->bmHeight;
- if ((pobj->Style&7) == ST_FRAGMENT)
- {
- lft = pobj->clipArea.x;
- top = pobj->clipArea.y;
- rgh = min(rgh,lft+pobj->szclipArea.cx);
- btm = min(btm,top+pobj->szclipArea.cy);
- }
-
- // Draw center...
- if (1)
- {
- rFill.top = preq->rcDestRect.top+pobj->dwTop;
- rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
- rFill.left = preq->rcDestRect.left+pobj->dwLeft;
- rFill.right = preq->rcDestRect.right-pobj->dwRight;
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
- rGlyph.top = top+pobj->dwTop;
- rGlyph.left = lft+pobj->dwLeft;
- rGlyph.right = rgh-pobj->dwRight;
- rGlyph.bottom = btm-pobj->dwBottom;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode,mode,depth);
- }
-
- // Draw top side...
- if (1)
- {
- rFill.top = preq->rcDestRect.top;
- rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
- rFill.left = preq->rcDestRect.left+pobj->dwLeft;
- rFill.right = preq->rcDestRect.right-pobj->dwRight;
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
- rGlyph.top = top+0;
- rGlyph.left = lft+pobj->dwLeft;
- rGlyph.right = rgh-pobj->dwRight;
- rGlyph.bottom = top+pobj->dwTop;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth);
- }
- // Draw bottom side...
- if (1)
- {
- rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
- rFill.bottom = preq->rcDestRect.bottom;
- rFill.left = preq->rcDestRect.left+pobj->dwLeft;
- rFill.right = preq->rcDestRect.right-pobj->dwRight;
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
-
- rGlyph.top = btm-pobj->dwBottom;
- rGlyph.left = lft+pobj->dwLeft;
- rGlyph.right = rgh-pobj->dwRight;
- rGlyph.bottom = btm;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth);
- }
- // Draw left side...
- if (1)
- {
- rFill.top = preq->rcDestRect.top+pobj->dwTop;
- rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
- rFill.left = preq->rcDestRect.left;
- rFill.right = preq->rcDestRect.left+pobj->dwLeft;
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
-
- rGlyph.top = top+pobj->dwTop;
- rGlyph.left = lft;
- rGlyph.right = lft+pobj->dwLeft;
- rGlyph.bottom = btm-pobj->dwBottom;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth);
- }
-
- // Draw right side...
- if (1)
- {
- rFill.top = preq->rcDestRect.top+pobj->dwTop;
- rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
- rFill.left = preq->rcDestRect.right-pobj->dwRight;
- rFill.right = preq->rcDestRect.right;
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
-
- rGlyph.top = top+pobj->dwTop;
- rGlyph.left = rgh-pobj->dwRight;
- rGlyph.right = rgh;
- rGlyph.bottom = btm-pobj->dwBottom;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth);
- }
-
-
- // Draw Top-Left corner...
- if (1)
- {
- rFill.top = preq->rcDestRect.top;
- rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
- rFill.left = preq->rcDestRect.left;
- rFill.right = preq->rcDestRect.left+pobj->dwLeft;
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
-
- rGlyph.top = top;
- rGlyph.left = lft;
- rGlyph.right = lft+pobj->dwLeft;
- rGlyph.bottom = top+pobj->dwTop;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
- }
- // Draw Top-Right corner...
- if (1)
- {
- rFill.top = preq->rcDestRect.top;
- rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
- rFill.left = preq->rcDestRect.right-pobj->dwRight;
- rFill.right = preq->rcDestRect.right;
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
-
- rGlyph.top = top;
- rGlyph.left = rgh-pobj->dwRight;
- rGlyph.right = rgh;
- rGlyph.bottom = top+pobj->dwTop;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
- }
-
- // Draw Bottom-Left corner...
- if (1)
- {
- rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
- rFill.bottom = preq->rcDestRect.bottom;
- rFill.left = preq->rcDestRect.left;
- rFill.right = preq->rcDestRect.left+pobj->dwLeft;
-
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
-
- rGlyph.left = lft;
- rGlyph.right = lft+pobj->dwLeft;
- rGlyph.top = btm-pobj->dwBottom;
- rGlyph.bottom = btm;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
- }
- // Draw Bottom-Right corner...
- if (1)
- {
- rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
- rFill.bottom = preq->rcDestRect.bottom;
- rFill.left = preq->rcDestRect.right-pobj->dwRight;
- rFill.right = preq->rcDestRect.right;
-
-
- if (mode == 2)
- OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
-
- rGlyph.left = rgh-pobj->dwRight;
- rGlyph.right = rgh;
- rGlyph.top = btm-pobj->dwBottom;
- rGlyph.bottom = btm;
-
- k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
- }
- }
-
- }
-
- if ((k>0 || k == -1) && mode == 2)
- {
- {
- BLENDFUNCTION bf = {AC_SRC_OVER, 0, /*(bm.bmBitsPixel == 32)?255:*/pobj->dwAlpha, (pobj->bmBitsPixel == 32 && pobj->Style != ST_BRUSH)?AC_SRC_ALPHA:0};
- if (mode == 2)
- OffsetRect(&PRect,mode2offset.x,mode2offset.y);
- ske_AlphaBlend( preq->hDC,PRect.left,PRect.top,PRect.right-PRect.left,PRect.bottom-PRect.top,
- memdc, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top,bf);
- }
- }
- }
- //free GDI resources
- //--++--
-
- //free GDI resources
- {
-
- if (oldglyph) SelectObject(glyphdc,oldglyph);
- if (glyphdc) DeleteDC(glyphdc);
- }
- if (mode == 2)
- {
- SelectObject(memdc,oldbmp);
- DeleteDC(memdc);
- DeleteObject(membmp);
- }
-
- }
- if (pobj->plTextList && pobj->plTextList->realCount>0)
- {
- int i;
- HFONT hOldFont;
- for (i=0; i < pobj->plTextList->realCount; i++)
- {
- GLYPHTEXT * gt = (GLYPHTEXT *)pobj->plTextList->items[i];
- if (!gt->hFont)
- {
- if (gl_plSkinFonts && gl_plSkinFonts->realCount>0)
- {
- int j = 0;
- for (j = 0; j < gl_plSkinFonts->realCount; j++)
- {
- SKINFONT * sf;
- sf = (SKINFONT*)gl_plSkinFonts->items[j];
- if (sf->szFontID && !strcmp(sf->szFontID,gt->szFontID))
- {
- gt->hFont = sf->hFont;
- break;
- }
- }
- }
- if (!gt->hFont) gt->hFont = (HFONT)-1;
- }
- if (gt->hFont != (HFONT)-1)
- {
- RECT rc = {0};
- hOldFont = (HFONT)SelectObject(preq->hDC,gt->hFont);
-
-
-
- if (gt->RelativeFlags&2) rc.left = preq->rcDestRect.right+gt->iLeft;
- else if (gt->RelativeFlags&1) rc.left = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iLeft;
- else rc.left = preq->rcDestRect.left+gt->iLeft;
-
- if (gt->RelativeFlags&8) rc.top = preq->rcDestRect.bottom+gt->iTop;
- else if (gt->RelativeFlags&4) rc.top = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iTop;
- else rc.top = preq->rcDestRect.top+gt->iTop;
-
- if (gt->RelativeFlags&32) rc.right = preq->rcDestRect.right+gt->iRight;
- else if (gt->RelativeFlags&16) rc.right = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iRight;
- else rc.right = preq->rcDestRect.left+gt->iRight;
-
- if (gt->RelativeFlags&128) rc.bottom = preq->rcDestRect.bottom+gt->iBottom;
- else if (gt->RelativeFlags&64) rc.bottom = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iBottom;
- else rc.bottom = preq->rcDestRect.top+gt->iBottom;
-
- ske_AlphaTextOut(preq->hDC, gt->stText, -1, &rc,gt->dwFlags, gt->dwColor);
- SelectObject(preq->hDC,hOldFont);
- }
- }
- }
-
- return 0;
-}
-
-
-
-int ske_AddDescriptorToSkinObjectList (LPSKINOBJECTDESCRIPTOR lpDescr, SKINOBJECTSLIST* Skin)
-{
- SKINOBJECTSLIST *sk;
- if (Skin) sk = Skin; else sk = &g_SkinObjectList;
- if (!sk) return 0;
- if (mir_bool_strcmpi(lpDescr->szObjectID,"_HEADER_")) return 0;
- {//check if new object allready presents.
- DWORD i=0;
- for (i=0; i < sk->dwObjLPAlocated; i++)
- if (!mir_strcmp(sk->pObjects[i].szObjectID,lpDescr->szObjectID)) return 0;
- }
- if (sk->dwObjLPAlocated+1>sk->dwObjLPReserved)
- { // Realocated list to add space for new object
-
- sk->pObjects = (SKINOBJECTDESCRIPTOR*)mir_realloc(sk->pObjects,sizeof(SKINOBJECTDESCRIPTOR)*(sk->dwObjLPReserved+1)/*alloc step*/);
- sk->dwObjLPReserved++;
- }
- { //filling new objects field
- sk->pObjects[sk->dwObjLPAlocated].bType = lpDescr->bType;
- sk->pObjects[sk->dwObjLPAlocated].Data = NULL;
- sk->pObjects[sk->dwObjLPAlocated].szObjectID = mir_strdup(lpDescr->szObjectID);
- // sk->Objects[sk->dwObjLPAlocated].szObjectName = mir_strdup(lpDescr->szObjectName);
- if (lpDescr->Data != NULL)
- { //Copy defaults values
- switch (lpDescr->bType)
- {
- case OT_GLYPHOBJECT:
- {
- GLYPHOBJECT * obdat;
- GLYPHOBJECT * gl = (GLYPHOBJECT*)lpDescr->Data;
- sk->pObjects[sk->dwObjLPAlocated].Data = mir_alloc(sizeof(GLYPHOBJECT));
- obdat = (GLYPHOBJECT*)sk->pObjects[sk->dwObjLPAlocated].Data;
- memcpy(obdat,gl,sizeof(GLYPHOBJECT));
- if (gl->szFileName != NULL)
- {
- obdat->szFileName = mir_strdup(gl->szFileName);
- mir_free_and_nil(gl->szFileName);
- }
- else obdat->szFileName = NULL;
-
- obdat->hGlyph = NULL;
- break;
- }
- }
-
- }
- }
- sk->dwObjLPAlocated++;
- return 1;
-}
-
-static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin)
-{
- // DWORD i;
- SKINOBJECTSLIST* sk;
- sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
- return skin_FindObjectByRequest((char *)szName,sk->pMaskList);
-}
-
-static LPSKINOBJECTDESCRIPTOR ske_FindObjectByMask(MODERNMASK *pModernMask, BYTE objType, SKINOBJECTSLIST* Skin)
-{
- // DWORD i;
- SKINOBJECTSLIST* sk;
- sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
- if (!sk->pMaskList) return NULL;
- return skin_FindObjectByMask(pModernMask,sk->pMaskList);
-}
-
-LPSKINOBJECTDESCRIPTOR ske_FindObjectByName(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin)
-{
- DWORD i;
- SKINOBJECTSLIST* sk;
- sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
- for (i=0; i < sk->dwObjLPAlocated; i++)
- {
- if (sk->pObjects[i].bType == objType || objType == OT_ANY)
- {
- if (!mir_strcmp(sk->pObjects[i].szObjectID,szName))
- return &(sk->pObjects[i]);
- }
- }
- return NULL;
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Paint glyph
-// wParam - LPSKINDRAWREQUEST
-// lParam - possible direct pointer to modern mask
-//////////////////////////////////////////////////////////////////////////
-
-INT_PTR ske_Service_DrawGlyph(WPARAM wParam, LPARAM lParam)
-{
- LPSKINDRAWREQUEST preq;
- LPSKINOBJECTDESCRIPTOR pgl;
- LPGLYPHOBJECT gl;
- if (!wParam) return -1;
- ske_LockSkin();
- __try
- {
- preq = (LPSKINDRAWREQUEST)wParam;
- if (lParam)
- pgl = ske_FindObjectByMask((MODERNMASK*)lParam, OT_GLYPHOBJECT,NULL);
- else
- pgl = ske_FindObject(preq->szObjectID, OT_GLYPHOBJECT,NULL);
- if (pgl == NULL) return -1;
- if (pgl->Data == NULL) return -1;
-
- gl = (LPGLYPHOBJECT)pgl->Data;
- int iStyle = gl->Style & 7;
- if (iStyle == ST_SKIP)
- return ST_SKIP;
-
- if (gl->hGlyph == NULL && gl->hGlyph != (HBITMAP)-1 && (iStyle == ST_IMAGE || iStyle == ST_FRAGMENT || iStyle == ST_SOLARIZE))
- if (gl->szFileName) {
- gl->hGlyph = ske_LoadGlyphImage( _A2T(gl->szFileName));
- if (gl->hGlyph) {
- BITMAP bmp = {0};
- GetObject(gl->hGlyph,sizeof(BITMAP),&bmp);
- gl->bmBitsPixel = (BYTE)bmp.bmBitsPixel;
- gl->bmHeight = bmp.bmHeight;
- gl->bmWidth = bmp.bmWidth;
- }
- else gl->hGlyph = (HBITMAP)-1; //invalid
- }
- return ske_DrawSkinObject(preq,gl);
- }
- __finally
- {
- ske_UnlockSkin();
- }
- return -1;
-}
-
-
-void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult)
-{
- BITMAP bmp;
- BOOL flag = FALSE;
- BYTE * pBitmapBits;
- DWORD Len;
- int bh,bw,y,x;
-
- GetObject(hbmp, sizeof(BITMAP), (LPSTR)&bmp);
- bh = bmp.bmHeight;
- bw = bmp.bmWidth;
- Len = bh*bw*4;
- flag = (bmp.bmBits == NULL);
- if (flag)
- {
- pBitmapBits = (LPBYTE)malloc(Len);
- GetBitmapBits(hbmp,Len,pBitmapBits);
- }
- else
- pBitmapBits = (BYTE*)bmp.bmBits;
- for (y = 0; y < bh; ++y)
- {
- BYTE *pPixel = pBitmapBits + bw * 4 * y;
-
- for (x = 0; x < bw ; ++x)
- {
- if (Mult)
- {
- pPixel[0] = pPixel[0]*pPixel[3]/255;
- pPixel[1] = pPixel[1]*pPixel[3]/255;
- pPixel[2] = pPixel[2]*pPixel[3]/255;
- }
- else
- {
- pPixel[3] = 255;
- }
- pPixel += 4;
- }
- }
- if (flag)
- {
- Len = SetBitmapBits(hbmp,Len,pBitmapBits);
- free (pBitmapBits);
- }
- return;
-}
-
-int ske_GetFullFilename(TCHAR *buf, const TCHAR *file, TCHAR *skinfolder, BOOL madeAbsolute)
-{
- TCHAR *SkinPlace = db_get_tsa(NULL,SKIN,"SkinFolder");
- if (SkinPlace == NULL)
- SkinPlace = mir_tstrdup( _T("\\Skin\\default"));
-
- TCHAR b2[MAX_PATH];
- if (file[0] != '\\' && file[1] != ':')
- mir_sntprintf(b2, MAX_PATH, _T("%s\\%s"), (skinfolder == NULL) ? SkinPlace : ((INT_PTR)skinfolder != -1) ? skinfolder : _T(""), file);
- else
- _tcsncpy(b2, file, SIZEOF(b2));
-
- if (madeAbsolute) {
- if (b2[0] == '\\' && b2[1] != '\\')
- PathToAbsoluteT(b2+1, buf);
- else
- PathToAbsoluteT(b2, buf);
- }
- else _tcsncpy(buf, b2, MAX_PATH);
-
- mir_free(SkinPlace);
- return 0;
-}
-
-/*
-This function is required to load TGA to dib buffer myself
-Major part of routines is from http://tfcduke.developpez.com/tutoriel/format/tga/fichiers/tga.c
-*/
-
-static BOOL ske_ReadTGAImageData(void * From, DWORD fromSize, BYTE * destBuf, DWORD bufSize, BOOL RLE)
-{
- BYTE * pos = destBuf;
- BYTE * from = fromSize?(BYTE*)From:NULL;
- FILE * fp = !fromSize?(FILE*)From:NULL;
- DWORD destCount = 0;
- DWORD fromCount = 0;
- if (!RLE)
- {
- while (((from && fromCount < fromSize) || (fp && fromCount < bufSize))
- && (destCount < bufSize))
- {
- BYTE r = from?from[fromCount++]:(BYTE)fgetc(fp);
- BYTE g = from?from[fromCount++]:(BYTE)fgetc(fp);
- BYTE b = from?from[fromCount++]:(BYTE)fgetc(fp);
- BYTE a = from?from[fromCount++]:(BYTE)fgetc(fp);
- pos[destCount++] = r;
- pos[destCount++] = g;
- pos[destCount++] = b;
- pos[destCount++] = a;
-
- if (destCount>bufSize) break;
- if (from) if (fromCount < fromSize) break;
- }
- }
- else
- {
- BYTE rgba[4];
- BYTE packet_header;
- BYTE *ptr = pos;
- BYTE size;
- int i;
- while (ptr < pos + bufSize)
- {
- /* read first byte */
- packet_header = from?from[fromCount]:(BYTE)fgetc(fp);
- if (from) from++;
- size = 1 + (packet_header & 0x7f);
- if (packet_header & 0x80)
- {
- /* run-length packet */
- if (from)
- {
- *((DWORD*)rgba) = *((DWORD*)(from+fromCount));
- fromCount += 4;
- }
- else fread (rgba, sizeof (BYTE), 4, fp);
- for (i=0; i < size; ++i, ptr += 4)
- {
- ptr[2] = rgba[2];
- ptr[1] = rgba[1];
- ptr[0] = rgba[0];
- ptr[3] = rgba[3];
- }
- }
- else
- { /* not run-length packet */
- for (i=0; i < size; ++i, ptr += 4)
- {
- ptr[0] = from? from[fromCount++]:(BYTE)fgetc (fp);
- ptr[1] = from? from[fromCount++]:(BYTE)fgetc (fp);
- ptr[2] = from? from[fromCount++]:(BYTE)fgetc (fp);
- ptr[3] = from? from[fromCount++]:(BYTE)fgetc (fp);
- }
- }
- }
- }
- return TRUE;
-}
-
-static HBITMAP ske_LoadGlyphImage_TGA(const TCHAR *szFilename)
-{
- BYTE *colormap = NULL;
- int cx = 0, cy = 0;
- BOOL err = FALSE;
- tga_header_t header;
- if (!szFilename) return NULL;
- if (!wildcmpit(szFilename, _T("*\\*%.tga"))) {
- //Loading TGA image from file
- FILE *fp = _tfopen (szFilename, _T("rb"));
- if (!fp) {
- TRACEVAR("error: couldn't open \"%s\"!\n", szFilename);
- return NULL;
- }
- /* read header */
- fread (&header, sizeof (tga_header_t), 1, fp);
- if ((header.pixel_depth != 32) || ((header.image_type != 10) && (header.image_type != 2))) {
- fclose(fp);
- return NULL;
- }
-
- /*memory allocation */
- colormap = (BYTE*)malloc(header.width*header.height*4);
- cx = header.width;
- cy = header.height;
- fseek (fp, header.id_lenght, SEEK_CUR);
- fseek (fp, header.cm_length, SEEK_CUR);
- err = !ske_ReadTGAImageData((void*)fp, 0, colormap, header.width*header.height*4,header.image_type == 10);
- fclose(fp);
- }
- else {
- /* reading from resources IDR_TGA_DEFAULT_SKIN */
- DWORD size = 0;
- BYTE * mem;
- HGLOBAL hRes;
- HRSRC hRSrc = FindResourceA(g_hInst,MAKEINTRESOURCEA(IDR_TGA_DEFAULT_SKIN),"TGA");
- if (!hRSrc) return NULL;
- hRes = LoadResource(g_hInst,hRSrc);
- if (!hRes) return NULL;
- size = SizeofResource(g_hInst,hRSrc);
- mem = (BYTE*) LockResource(hRes);
- if (size>sizeof(header))
- {
- tga_header_t * header = (tga_header_t *)mem;
- if (header->pixel_depth == 32 && (header->image_type == 2 || header->image_type == 10))
- {
- colormap = (BYTE*)malloc(header->width*header->height*4);
- cx = header->width;
- cy = header->height;
- ske_ReadTGAImageData((void*)(mem+sizeof(tga_header_t)+header->id_lenght+header->cm_length), size-(sizeof(tga_header_t)+header->id_lenght+header->cm_length), colormap, cx*cy*4,header->image_type == 10);
- }
- }
- FreeResource(hRes);
- }
-
- if (colormap) { //create dib section
- BYTE * pt;
- HBITMAP hbmp = ske_CreateDIB32Point(cx,cy,(void**)&pt);
- if (hbmp)
- memcpy(pt,colormap,cx*cy*4);
- free(colormap);
- return hbmp;
- }
- return NULL;
-}
-
-
-//this function is required to load PNG to dib buffer myself
-static HBITMAP ske_LoadGlyphImage_Png2Dib(const TCHAR *tszFilename)
-{
- HANDLE hFile, hMap = NULL;
- BYTE* ppMap = NULL;
- long cbFileSize = 0;
- BITMAPINFOHEADER* pDib;
- BYTE* pDibBits;
-
- if (!ServiceExists( MS_PNG2DIB )) {
- MessageBox( NULL, TranslateT("You need an image services plugin to process PNG images."), TranslateT("Error"), MB_OK );
- return (HBITMAP)NULL;
- }
-
- if ((hFile = CreateFile(tszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
- if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL)
- if ((ppMap = ( BYTE* )MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL)
- cbFileSize = GetFileSize(hFile, NULL);
-
- if (cbFileSize != 0) {
- PNG2DIB param;
- param.pSource = ppMap;
- param.cbSourceSize = cbFileSize;
- param.pResult = &pDib;
- if ( CallService(MS_PNG2DIB, 0, (LPARAM)&param ))
- pDibBits = ( BYTE* )( pDib+1 );
- else
- cbFileSize = 0;
- }
-
- if ( ppMap != NULL ) UnmapViewOfFile( ppMap );
- if ( hMap != NULL ) CloseHandle( hMap );
- if ( hFile != NULL ) CloseHandle( hFile );
-
- if ( cbFileSize == 0 )
- return (HBITMAP)NULL;
-
- HBITMAP hBitmap;
- BITMAPINFO* bi = ( BITMAPINFO* )pDib;
- BYTE *pt = (BYTE*)bi;
- pt += bi->bmiHeader.biSize;
- if (bi->bmiHeader.biBitCount != 32) {
- HDC sDC = GetDC( NULL );
- hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS );
- SelectObject( sDC, hBitmap );
- DeleteDC( sDC );
- }
- else {
- BYTE *ptPixels = pt;
- hBitmap = CreateDIBSection(NULL,bi, DIB_RGB_COLORS, (void **)&ptPixels, NULL, 0);
- memcpy(ptPixels,pt,bi->bmiHeader.biSizeImage);
- }
- GlobalFree( pDib );
- return hBitmap;
-}
-
-static HBITMAP ske_LoadGlyphImageByDecoders(const TCHAR *tszFileName)
-{
- // Loading image from file by imgdecoder...
- HBITMAP hBitmap = NULL;
- TCHAR ext[5];
- BYTE f = 0;
- LPVOID pImg = NULL;
-
- BITMAP bmpInfo;
- {
- int l = lstrlen(tszFileName);
- lstrcpyn(ext, tszFileName+(l-4),5);
- }
- if (!_tcschr(tszFileName,'%') && !PathFileExists(tszFileName))
- return NULL;
-
- if (mir_bool_tstrcmpi(ext, _T(".tga"))) {
- hBitmap = ske_LoadGlyphImage_TGA(tszFileName);
- f = 1;
- }
- else if ( ServiceExists("Image/Png2Dib") && mir_bool_tstrcmpi(ext, _T(".png"))) {
- hBitmap = ske_LoadGlyphImage_Png2Dib(tszFileName);
- GetObject(hBitmap, sizeof(BITMAP), &bmpInfo);
- f = (bmpInfo.bmBits != NULL);
- }
- else if (!mir_bool_tstrcmpi(ext, _T(".png"))) {
- hBitmap = (HBITMAP)CallService(MS_UTILS_LOADBITMAPT, 0, (LPARAM)tszFileName);
- }
-
- if (hBitmap) {
- GetObject(hBitmap, sizeof(BITMAP), &bmpInfo);
- if (bmpInfo.bmBitsPixel == 32)
- ske_PreMultiplyChanells(hBitmap,f);
- else {
- HDC dc24,dc32;
- HBITMAP hBitmap32,obmp24,obmp32;
- dc32 = CreateCompatibleDC(NULL);
- dc24 = CreateCompatibleDC(NULL);
- hBitmap32 = ske_CreateDIB32(bmpInfo.bmWidth,bmpInfo.bmHeight);
- obmp24 = (HBITMAP)SelectObject(dc24,hBitmap);
- obmp32 = (HBITMAP)SelectObject(dc32,hBitmap32);
- BitBlt(dc32, 0, 0, bmpInfo.bmWidth,bmpInfo.bmHeight,dc24, 0, 0, SRCCOPY);
- SelectObject(dc24,obmp24);
- SelectObject(dc32,obmp32);
- DeleteDC(dc24);
- DeleteDC(dc32);
- DeleteObject(hBitmap);
- hBitmap = hBitmap32;
- ske_PreMultiplyChanells(hBitmap,0);
- }
- }
- return hBitmap;
-}
-
-static HBITMAP ske_skinLoadGlyphImage(const TCHAR *tszFileName)
-{
- if (!wildcmpit(tszFileName, _T("*.tga")))
- return GDIPlus_LoadGlyphImage(tszFileName);
-
- return ske_LoadGlyphImageByDecoders(tszFileName);
-}
-
-HBITMAP ske_LoadGlyphImage(const TCHAR *tszFileName)
-{
- // try to find image in loaded
- DWORD i;
- HBITMAP hbmp;
- TCHAR szFile [MAX_PATH] = {0};
- ske_GetFullFilename(szFile, tszFileName, g_SkinObjectList.szSkinPlace, TRUE);
- ske_LockSkin();
- if (pLoadedImages) {
- for (i=0; i < dwLoadedImagesCount; i++) {
- if (mir_bool_tstrcmpi(pLoadedImages[i].szFileName, szFile)) {
- pLoadedImages[i].dwLoadedTimes++;
- ske_UnlockSkin();
- return pLoadedImages[i].hGlyph;
- }
- }
- }
- // load new image
- hbmp = ske_skinLoadGlyphImage(szFile);
- if (hbmp == NULL)
- {
- ske_UnlockSkin();
- return NULL;
- }
- // add to loaded list
- if (dwLoadedImagesCount+1>dwLoadedImagesAlocated)
- {
- pLoadedImages = (GLYPHIMAGE*)mir_realloc(pLoadedImages,sizeof(GLYPHIMAGE)*(dwLoadedImagesCount+1));
- if (pLoadedImages) dwLoadedImagesAlocated++;
- else
- {
- ske_UnlockSkin();
- return NULL;
- }
- }
- pLoadedImages[dwLoadedImagesCount].dwLoadedTimes = 1;
- pLoadedImages[dwLoadedImagesCount].hGlyph = hbmp;
- pLoadedImages[dwLoadedImagesCount].szFileName = mir_tstrdup(szFile);
- dwLoadedImagesCount++;
- ske_UnlockSkin();
- return hbmp;
-}
-
-int ske_UnloadGlyphImage(HBITMAP hbmp)
-{
- DWORD i;
- for (i=0; i < dwLoadedImagesCount; i++)
- {
- if (hbmp == pLoadedImages[i].hGlyph)
- {
- pLoadedImages[i].dwLoadedTimes--;
- if (pLoadedImages[i].dwLoadedTimes == 0)
- {
- LPGLYPHIMAGE gl = &(pLoadedImages[i]);
- mir_free_and_nil(gl->szFileName);
- memmove(&(pLoadedImages[i]),&(pLoadedImages[i+1]),sizeof(GLYPHIMAGE)*(dwLoadedImagesCount-i-1));
- dwLoadedImagesCount--;
- DeleteObject(hbmp);
- if (pLoadedImages && dwLoadedImagesCount == 0)
- {
- dwLoadedImagesAlocated = 0;
- mir_free_and_nil(pLoadedImages);
- }
- }
- return 0;
- }
-
- }
- DeleteObject(hbmp);
- return 0;
-}
-
-int ske_UnloadSkin(SKINOBJECTSLIST * Skin)
-{
- DWORD i;
- ske_LockSkin();
- ClearMaskList(Skin->pMaskList);
-
- //clear font list
- if (gl_plSkinFonts && gl_plSkinFonts->realCount > 0) {
- for (int i=0; i < gl_plSkinFonts->realCount; i++) {
- SKINFONT * sf = (SKINFONT *)gl_plSkinFonts->items[i];
- if (sf) {
- mir_free(sf->szFontID);
- DeleteObject(sf->hFont);
- mir_free(sf);
- }
- }
- List_Destroy(gl_plSkinFonts);
- mir_free_and_nil(gl_plSkinFonts);
- }
-
- mir_free_and_nil(Skin->szSkinPlace);
- if (Skin->pTextList) List_Destroy(Skin->pTextList);
- mir_free_and_nil(Skin->pTextList);
- ModernSkinButtonDeleteAll();
- if (Skin->dwObjLPAlocated == 0) { ske_UnlockSkin(); return 0;}
- for (i=0; i < Skin->dwObjLPAlocated; i++)
- {
- switch(Skin->pObjects[i].bType)
- {
- case OT_GLYPHOBJECT:
- {
- GLYPHOBJECT * dt;
- dt = (GLYPHOBJECT*)Skin->pObjects[i].Data;
- if (dt->hGlyph && dt->hGlyph != (HBITMAP)-1)
- ske_UnloadGlyphImage(dt->hGlyph);
- dt->hGlyph = NULL;
- mir_free_and_nil(dt->szFileName);
- {// delete texts
- int i;
- if (dt->plTextList && dt->plTextList->realCount>0)
- {
- for (i=0; i < dt->plTextList->realCount; i++)
- {
- GLYPHTEXT * gt = (GLYPHTEXT *)dt->plTextList->items[i];
- if (gt) {
- mir_free(gt->stText);
- mir_free(gt->stValueText);
- mir_free(gt->szFontID);
- mir_free(gt->szGlyphTextID);
- mir_free(gt);
- }
- }
- List_Destroy(dt->plTextList);
- mir_free(dt->plTextList);
- }
- }
- mir_free(dt);
- }
- break;
- }
- mir_free_and_nil(Skin->pObjects[i].szObjectID);
-
- }
- mir_free_and_nil(Skin->pObjects);
- Skin->pTextList = NULL;
- Skin->dwObjLPAlocated = 0;
- Skin->dwObjLPReserved = 0;
- ske_UnlockSkin();
- return 0;
-}
-
-static void RegisterMaskByParce(const char * szSetting, char * szValue, SKINOBJECTSLIST * pSkin)
-{
- int i;
- DWORD ID=atoi(szSetting+1);
- for (i=0; i < mir_strlen(szValue); i++) if (szValue[i] == ':') break;
- if (i < mir_strlen(szValue))
- {
- char * Obj, *Mask;
- int res;
- Mask = szValue+i+1;
- Obj = (char*)mir_alloc(i+1);
- strncpy(Obj,szValue,i);
- Obj[i] = '\0';
- res = AddStrModernMaskToList(ID,Mask,Obj,pSkin->pMaskList,pSkin);
- mir_free(Obj);
- }
-}
-
-static int ske_ProcessLoadindString(const char * szSetting, char *szValue)
-{
- if (!pCurrentSkin) return 0;
- if (szSetting[0] == '$')
- RegisterObjectByParce((char *)szSetting, szValue);
- else if (szSetting[0] == '#')
- RegisterButtonByParce((char *)szSetting,szValue);
- else if (szSetting[0] == '@')
- RegisterMaskByParce((char *)szSetting, szValue, pCurrentSkin); ///
- else if (szSetting[0] == 't')
- ske_AddParseTextGlyphObject((char*)szSetting,szValue,pCurrentSkin);
- else if (szSetting[0] == 'f')
- ske_AddParseSkinFont((char*)szSetting,szValue,pCurrentSkin);
- else return 0;
- return 1;
-}
-static int ske_enumdb_SkinObjectsProc (const char *szSetting,LPARAM lParam)
-{
- char *value;
- value = db_get_sa(NULL,SKIN,szSetting);
- ske_ProcessLoadindString(szSetting,value);
- mir_free_and_nil(value);
-
- return 0;
-}
-
-static int ske_SortTextGlyphObjectFunc(void * first, void * second)
-{
- return strcmp(((GLYPHTEXT*)(((int*)first)[0]))->szGlyphTextID,((GLYPHTEXT*)(((int*)second)[0]))->szGlyphTextID);
-}
-
-static void ske_LinkSkinObjects(SKINOBJECTSLIST * pObjectList)
-{
- DWORD i;
- // LINK Mask with objects
- for (i=0; i < pObjectList->pMaskList->dwMaskCnt; i++)
- {
- MODERNMASK *mm = &(pObjectList->pMaskList->pl_Masks[i]);
- void * pObject = (void*) ske_FindObjectByName(mm->szObjectName, OT_ANY, (SKINOBJECTSLIST*) pObjectList);
- mir_free_and_nil(mm->szObjectName);
- mm->bObjectFound = TRUE;
- mm->pObject = pObject;
- }
-
- if (pObjectList->pTextList)
- {
- int i;
- // LINK Text with objects
- for (i=0; i < pObjectList->pTextList->realCount; i++)
- {
- GLYPHTEXT * glText;
- GLYPHOBJECT *globj = NULL;
- SKINOBJECTDESCRIPTOR * lpobj;
- glText = (GLYPHTEXT *)pObjectList->pTextList->items[i];
- lpobj = ske_FindObjectByName(glText->szObjectName,OT_GLYPHOBJECT, pObjectList);
- mir_free_and_nil(glText->szObjectName);
- if (lpobj)
- globj = (GLYPHOBJECT*)lpobj->Data;
- if (globj)
- {
- if (!globj->plTextList)
- {
- globj->plTextList = List_Create(0, 1);
- globj->plTextList->sortFunc = ske_SortTextGlyphObjectFunc;
- }
- List_Insert(globj->plTextList,(void*)glText,globj->plTextList->realCount);
- qsort(globj->plTextList->items,globj->plTextList->realCount,sizeof(void*),(int(*)(const void*, const void*))globj->plTextList->sortFunc);
- pObjectList->pTextList->items[i] = NULL;
- }
- else
- {
- GLYPHTEXT *gt = glText;
- if (gt) {
- mir_free(gt->stText);
- mir_free(gt->stValueText);
- mir_free(gt->szFontID);
- mir_free(gt->szGlyphTextID);
- mir_free(gt);
- }
- }
- }
- List_Destroy(pObjectList->pTextList);
- mir_free_and_nil(pObjectList->pTextList);
- }
-}
-// Getting skin objects and masks from DB
-static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin)
-{
- if (Skin == NULL) return 0;
- ske_UnloadSkin(Skin);
- g_CluiData.fDisableSkinEngine = db_get_b(NULL,"ModernData","DisableEngine", SETTING_DISABLESKIN_DEFAULT);
- //window borders
- if (g_CluiData.fDisableSkinEngine) {
- g_CluiData.LeftClientMargin = 0;
- g_CluiData.RightClientMargin = 0;
- g_CluiData.TopClientMargin = 0;
- g_CluiData.BottomClientMargin = 0;
- } else {
- //window borders
- g_CluiData.LeftClientMargin = (int)db_get_b(NULL,"CLUI","LeftClientMargin",SETTING_LEFTCLIENTMARIGN_DEFAULT);
- g_CluiData.RightClientMargin = (int)db_get_b(NULL,"CLUI","RightClientMargin",SETTING_RIGHTCLIENTMARIGN_DEFAULT);
- g_CluiData.TopClientMargin = (int)db_get_b(NULL,"CLUI","TopClientMargin",SETTING_TOPCLIENTMARIGN_DEFAULT);
- g_CluiData.BottomClientMargin = (int)db_get_b(NULL,"CLUI","BottomClientMargin",SETTING_BOTTOMCLIENTMARIGN_DEFAULT);
- }
-
- if (g_CluiData.fDisableSkinEngine) return 0;
-
- Skin->pMaskList = (LISTMODERNMASK*)mir_alloc(sizeof(LISTMODERNMASK));
- memset(Skin->pMaskList, 0, sizeof(LISTMODERNMASK));
- Skin->szSkinPlace = db_get_tsa(NULL, SKIN, "SkinFolder");
- if (!Skin->szSkinPlace || (_tcschr(Skin->szSkinPlace, '%') && !db_get_b(NULL,SKIN,"Modified",0)))
- {
- BOOL bOnlyObjects = FALSE;
- if (Skin->szSkinPlace && _tcschr(Skin->szSkinPlace, '%'))
- bOnlyObjects = TRUE;
- mir_free(Skin->szSkinPlace);
- Skin->szSkinPlace = mir_tstrdup( _T("%Default%"));
- ske_LoadSkinFromResource( bOnlyObjects );
- }
- //Load objects
- {
- DBCONTACTENUMSETTINGS dbces;
- pCurrentSkin = Skin;
- dbces.pfnEnumProc = ske_enumdb_SkinObjectsProc;
- dbces.szModule = SKIN;
- dbces.ofsSettings = 0;
- CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces);
-
- SortMaskList(pCurrentSkin->pMaskList);
- ske_LinkSkinObjects(pCurrentSkin);
- }
- //Load Masks
- return 0;
-}
-
-//surrogate to be called from outside
-void ske_LoadSkinFromDB(void)
-{
- ske_GetSkinFromDB(SKIN,&g_SkinObjectList);
- g_CluiData.dwKeyColor = db_get_dw(NULL,"ModernSettings","KeyColor",(DWORD)SETTING_KEYCOLOR_DEFAULT);
-}
-
-//
-
-static int ske_LoadSkinFromResource(BOOL bOnlyObjects)
-{
- IniParser parser(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF", bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
- if (parser.CheckOK()) {
- ske_DeleteAllSettingInSection("ModernSkin");
- db_set_s(NULL, SKIN, "SkinFolder", "%Default%");
- db_set_s(NULL, SKIN, "SkinFile", "%Default%");
- parser.Parse(IniParser::WriteStrToDb, 0);
- }
- return 0;
-}
-
-//Load data from ini file
-int ske_LoadSkinFromIniFile(TCHAR *szFileName, BOOL bOnlyObjects)
-{
- if (_tcschr(szFileName,_T('%')))
- return ske_LoadSkinFromResource( bOnlyObjects );
-
- IniParser parser(szFileName, bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
- if (!parser.CheckOK())
- return 0;
-
- ske_DeleteAllSettingInSection("ModernSkin");
-
- TCHAR skinFolder[MAX_PATH], skinFile[MAX_PATH];
- IniParser::GetSkinFolder(szFileName, skinFolder);
- PathToRelativeT(szFileName, skinFile);
-
- db_set_ts(NULL,SKIN,"SkinFolder", skinFolder);
- db_set_ts(NULL,SKIN,"SkinFile", skinFile);
-
- parser.Parse(IniParser::WriteStrToDb, 1);
- return 0;
-}
-
-static int ske_enumdb_SkinSectionDeletionProc (const char *szSetting,LPARAM lParam)
-{
- if (szSetting == NULL)
- return 0;
-
- nArrayLen++;
- pszSettingName = (char **)realloc(pszSettingName, nArrayLen*sizeof(char *));
- pszSettingName[nArrayLen-1] = _strdup(szSetting);
- return 0;
-}
-
-static int ske_DeleteAllSettingInSection(char * SectionName)
-{
- DBCONTACTENUMSETTINGS dbces;
- nArrayLen = 0;
- pszSettingName = NULL;
- dbces.pfnEnumProc = ske_enumdb_SkinSectionDeletionProc;
- dbces.szModule = SectionName;
- dbces.ofsSettings = 0;
-
- CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces);
-
- //delete all settings
- if (nArrayLen == 0)
- return 0;
-
- for (int i=0; i < nArrayLen; i++) {
- db_unset(0, SectionName,pszSettingName[i]);
- free(pszSettingName[i]);
- }
- free(pszSettingName);
- pszSettingName = NULL;
- nArrayLen = 0;
- return 0;
-}
-
-BOOL ske_TextOut(HDC hdc, int x, int y, LPCTSTR lpString, int nCount)
-{
- SIZE sz;
- GetTextExtentPoint32(hdc, lpString, nCount, &sz);
- int ta = GetTextAlign(hdc);
-
- RECT rc = { 0 };
- SetRect(&rc, x, y, x + sz.cx, y + sz.cy);
- ske_DrawText(hdc, lpString, nCount, &rc, DT_NOCLIP | DT_SINGLELINE | DT_LEFT);
- return 1;
-}
-
-static INT_PTR ske_Service_AlphaTextOut(WPARAM wParam, LPARAM lParam)
-{
- if (!wParam) return 0;
-
- AlphaTextOutParams ap = *(AlphaTextOutParams*)wParam;
- return ske_AlphaTextOut(ap.hDC,ap.lpString,ap.nCount,ap.lpRect,ap.format,ap.ARGBcolor);
-}
-
-static __inline void ske_SetMatrix( sbyte * matrix,
- sbyte a, sbyte b, sbyte c,
- sbyte d, sbyte e, sbyte f,
- sbyte g, sbyte h, sbyte i)
-{
- matrix[0] = a; matrix[1] = b; matrix[2] = c;
- matrix[3] = d; matrix[4] = e; matrix[5] = f;
- matrix[6] = g; matrix[7] = h; matrix[8] = i;
-}
-
-static void ske_SetTextEffect(BYTE EffectID, DWORD FirstColor, DWORD SecondColor)
-{
- if (EffectID > MAXPREDEFINEDEFFECTS) return;
- if (EffectID == -1) meCurrentEffect.EffectID = -1;
- else {
- meCurrentEffect.EffectID = EffectID;
- meCurrentEffect.EffectMatrix = ModernEffectsEnum[EffectID];
- meCurrentEffect.EffectColor1 = FirstColor;
- meCurrentEffect.EffectColor2 = SecondColor;
- }
-}
-
-bool ske_ResetTextEffect(HDC hdc)
-{
- int idx = arEffectStack.getIndex((EFFECTSSTACKITEM*)&hdc);
- if (idx == -1)
- return false;
-
- mir_free(arEffectStack[idx]);
- arEffectStack.remove(idx);
- return true;
-}
-
-bool ske_SelectTextEffect(HDC hdc, BYTE EffectID, DWORD FirstColor, DWORD SecondColor)
-{
- if (EffectID > MAXPREDEFINEDEFFECTS)
- return false;
-
- if (EffectID == -1)
- return ske_ResetTextEffect(hdc);
-
- EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc);
- if (effect == NULL) {
- effect = (EFFECTSSTACKITEM *)mir_alloc(sizeof(EFFECTSSTACKITEM));
- effect->hdc = hdc;
- arEffectStack.insert(effect);
- }
-
- effect->EffectID = EffectID;
- effect->FirstColor = FirstColor;
- effect->SecondColor = SecondColor;
- return true;
-}
-
-static bool ske_GetTextEffect(HDC hdc, MODERNEFFECT *modernEffect)
-{
- if (!modernEffect)
- return false;
-
- EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc);
- if (effect == NULL)
- return false;
-
- modernEffect->EffectID = effect->EffectID;
- modernEffect->EffectColor1 = effect->FirstColor;
- modernEffect->EffectColor2 = effect->SecondColor;
- modernEffect->EffectMatrix = ModernEffectsEnum[effect->EffectID];
- return true;
-}
-
-static bool ske_DrawTextEffect(BYTE* destPt, BYTE* maskPt, DWORD width, DWORD height, MODERNEFFECT *effect)
-{
- sbyte *buf;
- sbyte *outbuf;
- sbyte *bufline, *buflineTop, *buflineMid;
- int sign = 0;
- BYTE *maskline,*destline;
- BYTE al,rl,gl,bl,ad,rd,gd,bd;
- int k = 0;
- DWORD x,y;
- sbyte *matrix;
- BYTE mcTopStart;
- BYTE mcBottomEnd;
- BYTE mcLeftStart;
- BYTE mcRightEnd;
- BYTE effectCount;
- int minX = width;
- int maxX = 0;
- int minY = height;
- int maxY = 0;
- if (effect->EffectID == 0xFF) return false;
- if (!width || !height) return false;
- if (!destPt) return false;
- buf = (sbyte*)malloc(width*height*sizeof(BYTE));
- {
- matrix = effect->EffectMatrix.matrix;
- mcTopStart = 2-effect->EffectMatrix.topEffect;
- mcBottomEnd = 3+effect->EffectMatrix.bottomEffect;
- mcLeftStart = 2-effect->EffectMatrix.leftEffect;
- mcRightEnd = 3+effect->EffectMatrix.rightEffect;
- effectCount = effect->EffectMatrix.cycleCount;
- }
- al = 255-((BYTE)(effect->EffectColor1>>24));
- rl = GetRValue(effect->EffectColor1);
- gl = GetGValue(effect->EffectColor1);
- bl = GetBValue(effect->EffectColor1);
- ad = 255-((BYTE)(effect->EffectColor2>>24));
- rd = GetRValue(effect->EffectColor2);
- gd = GetGValue(effect->EffectColor2);
- bd = GetBValue(effect->EffectColor2);
-
- //Fill buffer by mid values of image
- for (y = 0; y < height; y++)
- {
- bufline = buf+y*width;
- maskline = maskPt+((y*width) << 2);
- for (x = 0; x < width; x++)
- {
- BYTE a = (sbyte)(DWORD)((maskline[0]+maskline[2]+maskline[1]+maskline[1])>>4);
- *bufline = a;
- if (a != 0)
- {
- minX = min((int)x,minX);
- minY = min((int)y,minY);
- maxX = max((int)x,maxX);
- maxY = max((int)y,maxY);
- }
- bufline++;
- maskline += 4;
- }
- }
- //Here perform effect on buffer and place results to outbuf
- for (k = 0; k < (effectCount&0x7F); k++)
- {
- minX = max( 0, minX + mcLeftStart - 2 );
- minY = max( 0, minY + mcTopStart - 2 );
- maxX = min((int)width, maxX + mcRightEnd - 1 );
- maxY = min((int)height, maxY + mcBottomEnd - 1 );
-
- outbuf = (sbyte*)malloc(width*height*sizeof(sbyte));
- memset(outbuf, 0, width*height*sizeof(sbyte));
- for (y = (DWORD)minY; y < (DWORD)maxY; y++)
- {
- int val;
- bufline = outbuf+y*width+minX;
- buflineMid = buf+y*width+minX;
- for (x = (DWORD)minX; x < (DWORD)maxX; x++)
- {
- int matrixHor,matrixVer;
- val = 0;
- for (matrixVer = mcTopStart; matrixVer < mcBottomEnd; matrixVer++)
- {
- int buflineStep = width*(matrixVer-2);
- int as = y+matrixVer-2;
- sbyte * buflineTopS = NULL;
- if (as >= 0 && (DWORD)as < height) buflineTopS = buflineMid+buflineStep;
-
- for (matrixHor = mcLeftStart; matrixHor < mcRightEnd;matrixHor++)
- {
- buflineTop = buflineTopS;
- int a = x+matrixHor-2;
- if (buflineTop && a >= 0 && (DWORD)a < width) buflineTop += matrixHor-2;
- else buflineTop = NULL;
- if (buflineTop)
- val += ((*buflineTop)*matrix[matrixVer*5+matrixHor]);
- }
- }
- val = (val+1)>>5;
- *bufline = (sbyte)((val>127)?127:(val < -125)?-125:val);
- bufline++;
- buflineMid++;
- }
- }
- free(buf);
- buf = outbuf;
- }
- {
- BYTE r1,b1,g1,a1;
- b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1;
- //perform out to dest
- for (y = 0; y < height; y++)
- {
- bufline = buf+y*width;
- destline = destPt+((y*width) << 2);
- for (x = 0; x < width; x++)
- {
- sbyte val = *bufline;
- BYTE absVal = ((val < 0)?-val:val);
-
- if (val != 0)
- {
- if (val>0 && sign < 0)
- { b1 = bl; r1 = rl; g1 = gl; a1 = al; sign = 1;}
- else if (val < 0 && sign>0)
- { b1 = bd; r1 = rd; g1 = gd; a1 = ad; sign = -1;}
-
- absVal = absVal*a1/255;
-
- destline[0] = ((destline[0]*(128-absVal))+absVal*b1)>>7;
- destline[1] = ((destline[1]*(128-absVal))+absVal*g1)>>7;
- destline[2] = ((destline[2]*(128-absVal))+absVal*r1)>>7;
- destline[3] += ((255-destline[3])*(a1*absVal))/32640;
- }
- bufline++;
- destline += 4;
- }
- }
- free(buf);
- }
- return false;
-}
-
-static int ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor)
-{
- if (!(lpString && lpRect))
- return 0;
-
- // Step first fill fast calc correction tables:
- static bool _tables_empty = true;
- static BYTE gammaTbl[256]; // Gamma correction table
- static WORD blueMulTbl[256]; // blue coefficient multiplication table
- static WORD greenMulTbl[256]; // green coefficient multiplication table
- static WORD redMulTbl[256]; // red coefficient multiplication table
- if ( _tables_empty )
- {
- // fill tables
- double gammaCfPw = 1000 / (double)DBGetContactSettingRangedWord(NULL,"ModernData","AlphaTextOutGamma", 700, 1, 5000 );
- BYTE blueCf = db_get_b(NULL,"ModernData","AlphaTextOutBlueCorrection", 28 );
- BYTE redCf = db_get_b(NULL,"ModernData","AlphaTextOutRed Correction", 77 );
- BYTE greenCf = db_get_b(NULL,"ModernData","AlphaTextOutGreen Correction", 151 );
-
- for ( int i=0; i < 256; i++ ) {
- gammaTbl[i] = (BYTE)( 255 * pow((double)i / 255, gammaCfPw ));
- blueMulTbl[i] = i * blueCf;
- redMulTbl[i] = i * redCf;
- greenMulTbl[i] = i * greenCf;
- }
- }
-
- // Calc len of input string
- if (nCount == -1)
- nCount = lstrlen(lpString);
-
- // retrieve destination bitmap bits
- HBITMAP hDestBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
- BITMAP bmpDest;
- GetObject(hDestBitmap, sizeof(BITMAP), &bmpDest);
-
- BOOL destHasNotDIB = FALSE;
- BYTE *pDestBits = NULL;
- if (bmpDest.bmBits == NULL) {
- destHasNotDIB = TRUE;
- pDestBits = (BYTE*) malloc ( bmpDest.bmHeight * bmpDest.bmWidthBytes );
- GetBitmapBits( hDestBitmap, bmpDest.bmHeight*bmpDest.bmWidthBytes, pDestBits );
- }
- else pDestBits = (BYTE*)bmpDest.bmBits;
-
- BOOL isDest16bit = (bmpDest.bmBitsPixel) != 32;
-
- // Creating offscreen buffer
- HDC hOffscreenDC = CreateCompatibleDC(hDC);
-
- // Font to be used to draw text
- HFONT hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT);
- HFONT hOldOffscreenFont = (HFONT)SelectObject(hOffscreenDC, hFont);
-
- // Calculating text geometric size
- RECT workRect = *lpRect;
- int workRectWidth = workRect.right - workRect.left;
- int workRectHeight = workRect.bottom - workRect.top;
- if (workRectWidth <= 0 || workRectHeight <= 0)
- return 0;
-
- SIZE textSize;
- GetTextExtentPoint32( hOffscreenDC, lpString, nCount, &textSize );
-
- LPCTSTR lpWorkString = lpString;
- BOOL bNeedFreeWorkString = FALSE;
-
- // if we need to cut the text with ellipsis
- if ((format & DT_END_ELLIPSIS) && textSize.cx > workRectWidth) {
- // Calc geometric width of ellipsis
- SIZE szEllipsis;
- GetTextExtentPoint32A(hOffscreenDC,"...",3,&szEllipsis);
- szEllipsis.cx++; // CORRECTION: some width correction
-
- // Calc count of visible chars
- int visibleCharCount = nCount;
- if (workRectWidth > szEllipsis.cx)
- GetTextExtentExPoint(hOffscreenDC, lpString, nCount, workRectWidth - szEllipsis.cx, &visibleCharCount, NULL, &textSize);
- else
- GetTextExtentExPoint(hOffscreenDC, lpString, nCount, 0, &visibleCharCount, NULL, &textSize);
-
- // replace end of string by elipsis
- bNeedFreeWorkString = TRUE;
- lpWorkString = (TCHAR*) malloc(( visibleCharCount + 4) * sizeof(TCHAR));
-
- memcpy((void*) lpWorkString, lpString, visibleCharCount * sizeof(TCHAR));
- memcpy((void*) ( lpWorkString + visibleCharCount ), _T("..."), 4 * sizeof(TCHAR)); // 3 + 1
-
- nCount = visibleCharCount + 3;
- }
-
- // Calc sizes and offsets
-
- textSize.cx += 2; // CORRECTION: for italic
-
- int drx = 0; // x-axis offset of draw point
-
- if (workRectWidth > textSize.cx) {
- if ( format & ( DT_RIGHT | DT_RTLREADING ))
- drx = workRectWidth - textSize.cx;
- else if ( format & DT_CENTER )
- drx = ( workRectWidth - textSize.cx ) >> 1;
- }
- else textSize.cx = workRectWidth;
-
- int dry = 0; // y-axis offset of draw point
-
- if (workRectHeight > textSize.cy) {
- if (format & DT_BOTTOM)
- dry = workRectHeight - textSize.cy;
- else if (format & DT_VCENTER)
- dry = (workRectHeight - textSize.cy) >> 1;
- }
- else textSize.cy = workRectHeight;
-
- textSize.cx += 4; // CORRECTION: for effects ???
- textSize.cy += 4; // CORRECTION: for effects ???
-
- if (textSize.cx > 0 && textSize.cy > 0) { // Ok we need to paint
- // probably here are mess ofscreen and temp buff dc
-
- //Create bitmap image for offscreen
- BYTE *bits = NULL;
- HBITMAP hbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bits);
- if (bits != NULL) {
- HBITMAP holdbmp = (HBITMAP)SelectObject( hOffscreenDC, hbmp );
-
- //Create buffer bitmap image for temp text
- BYTE *bufbits = NULL;
- HBITMAP bufbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bufbits);
- if ( bufbits != NULL ) {
- HDC bufDC = CreateCompatibleDC(hDC);
- HBITMAP bufoldbmp = (HBITMAP)SelectObject(bufDC, bufbmp);
- HFONT hOldBufFont = (HFONT)SelectObject(bufDC, hFont);
- SetBkColor(bufDC, RGB(0, 0, 0));
- SetTextColor(bufDC, RGB(255, 255, 255));
-
- // Copy from destination to temp buffer
- BitBlt(hOffscreenDC, 0, 0, textSize.cx, textSize.cy, hDC, workRect.left + drx - 2, workRect.top + dry - 2, SRCCOPY);
-
- //Draw text on offscreen bitmap
- TextOut(bufDC, 2, 2, lpWorkString, nCount);
-
- MODERNEFFECT effect;
- if (ske_GetTextEffect(hDC, &effect))
- ske_DrawTextEffect(bits, bufbits, textSize.cx, textSize.cy, &effect);
-
- // RenderText
- RECT drawRect;
- drawRect.left = 0; drawRect.top = 0;
- drawRect.right = textSize.cx;
- drawRect.bottom = textSize.cy;
-
- DWORD width = textSize.cx;
- DWORD heigh = textSize.cy;
-
- BYTE *pDestScanLine;
- BYTE *pBufScanLine;
- BYTE *pix;
- BYTE *bufpix;
-
- BYTE al = 255 - ((BYTE)( ARGBcolor >> 24 ));
- BYTE r = GetRValue( ARGBcolor );
- BYTE g = GetGValue( ARGBcolor );
- BYTE b = GetBValue( ARGBcolor );
-
- for (DWORD y = 2; y < heigh - 2; y++) {
- int lineBytes = y * (width << 2);
-
- pDestScanLine = bits + lineBytes;
- pBufScanLine = bufbits + lineBytes;
-
- for (DWORD x = 2; x < width - 2; x++) {
- pix = pDestScanLine + ( x << 2 );
- bufpix = pBufScanLine + ( x << 2 );
-
- // Monochromatic
- BYTE bx = gammaTbl[ bufpix[0] ];
- BYTE gx = gammaTbl[ bufpix[1] ];
- BYTE rx = gammaTbl[ bufpix[2] ];
-
- if ( al != 255 ) {
- bx *= al/255;
- gx *= al/255;
- rx *= al/255;
- }
-
- BYTE ax = (BYTE)(( (DWORD)rx*77 + (DWORD)gx * 151 + (DWORD)bx *28 + 128 ) / 256 );
- if (ax) {
- //Normalize components to gray
- BYTE axx = 255 - (( r + g + b ) >> 2 ) ; // Coefficient of grayance, more white font - more gray edges
- WORD atx = ax * (255 - axx);
- bx = ( atx + bx * axx )/255;
- gx = ( atx + gx * axx )/255;
- rx = ( atx + rx * axx )/255;
-
- short brx = (short)((b - pix[0])*bx / 255);
- short grx = (short)((g - pix[1])*gx / 255);
- short rrx = (short)((r - pix[2])*rx / 255);
-
- pix[0] += brx;
- pix[1] += grx;
- pix[2] += rrx;
- pix[3] = (BYTE)(ax+(BYTE)(255-ax)*pix[3]/255);
- }
- }
- }
-
- // Blit to destination
- BitBlt(hDC, workRect.left + drx - 2, workRect.top + dry - 2, textSize.cx, textSize.cy, hOffscreenDC, 0, 0, SRCCOPY);
-
- //free resources
- SelectObject(bufDC, bufoldbmp);
- DeleteObject(bufbmp);
- SelectObject(bufDC, hOldBufFont);
- DeleteDC(bufDC);
- }
- SelectObject(hOffscreenDC, holdbmp);
- DeleteObject(hbmp);
- }
- }
-
- // Final cleanup
- SelectObject(hOffscreenDC, hOldOffscreenFont);
- DeleteDC(hOffscreenDC);
-
- if (destHasNotDIB)
- free(pDestBits);
-
- if (bNeedFreeWorkString)
- free((void*)lpWorkString);
-
- return 0;
-}
-
-static int ske_DrawTextWithEffectWorker( HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, MODERNFONTEFFECT * effect )
-{
- if (format & DT_CALCRECT)
- return DrawText(hdc, lpString, nCount, lpRect, format);
-
- if (format & DT_RTLREADING)
- SetTextAlign(hdc, TA_RTLREADING);
-
- DWORD color = GetTextColor(hdc);
- RECT r = *lpRect;
- OffsetRect(&r, 1, 1);
- DWORD form = format;
- if (effect && effect->effectIndex)
- ske_SelectTextEffect(hdc, effect->effectIndex - 1, effect->baseColour, effect->secondaryColour);
-
- int res = ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color);
-
- if (effect && effect->effectIndex)
- ske_ResetTextEffect(hdc);
-
- return res;
-}
-
-INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam)
-{
- DrawTextWithEffectParam *p = (DrawTextWithEffectParam *)wParam;
- if (p->cbSize != sizeof(DrawTextWithEffectParam))
- return FALSE;
- return ske_DrawTextWithEffectWorker(p->hdc, p->lpchText, p->cchText, p->lprc, p->dwDTFormat, p->pEffect);
-}
-
-BOOL ske_DrawText(HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format)
-{
- DWORD form = 0, color = 0;
- RECT r = *lpRect;
- OffsetRect(&r, 1, 1);
- if (format & DT_RTLREADING) SetTextAlign(hdc, TA_RTLREADING);
- if (format & DT_CALCRECT) return DrawText(hdc, lpString, nCount, lpRect, format);
- if (format & DT_FORCENATIVERENDER || g_CluiData.fDisableSkinEngine)
- return DrawText(hdc, lpString, nCount, lpRect, format&~DT_FORCENATIVERENDER);
-
- form = format;
- color = GetTextColor(hdc);
- return ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color);
-}
-
-HICON ske_ImageList_GetIcon(HIMAGELIST himl, int i, UINT fStyle)
-{
- IMAGEINFO imi = {0};
- BITMAP bm = {0};
- if (i != -1) {
- ImageList_GetImageInfo(himl,i,&imi);
- GetObject(imi.hbmImage,sizeof(bm),&bm);
- if (bm.bmBitsPixel == 32) //stupid bug of Microsoft
- // Icons bitmaps are not premultiplied
- // So Imagelist_AddIcon - premultiply alpha
- // But incorrect - it is possible that alpha will
- // be less than color and
- // ImageList_GetIcon will return overflowed colors
- // TODO: Direct draw Icon from imagelist without
- // extracting of icon
- {
- BYTE *bits = (BYTE*)bm.bmBits;
- if (!bits) {
- bits = (BYTE*)malloc(bm.bmWidthBytes*bm.bmHeight);
- GetBitmapBits(imi.hbmImage,bm.bmWidthBytes*bm.bmHeight,bits);
- }
-
- int wb = ((imi.rcImage.right - imi.rcImage.left)*bm.bmBitsPixel >> 3);
- BYTE *bcbits = bits + (bm.bmHeight - imi.rcImage.bottom)*bm.bmWidthBytes + (imi.rcImage.left*bm.bmBitsPixel >> 3);
- for (int iy = 0; iy < imi.rcImage.bottom - imi.rcImage.top; iy++) {
- int x;
- // Dummy microsoft fix - alpha can be less than r,g or b
- // Looks like color channels in icons should be non-premultiplied with alpha
- // But AddIcon store it premultiplied (incorrectly cause can be Alpha == 7F, but R,G or B == 80
- // So i check that alpha is 0x7F and set it to 0x80
- DWORD *c = ((DWORD*)bcbits);
- for (x = 0; x < imi.rcImage.right - imi.rcImage.left; x++) {
- DWORD val = *c;
- BYTE a = (BYTE)((val) >> 24);
- if (a != 0) {
- BYTE r = (BYTE)((val & 0xFF0000) >> 16);
- BYTE g = (BYTE)((val & 0xFF00) >> 8);
- BYTE b = (BYTE)(val & 0xFF);
- if (a < r || a < g || a < b)
- {
- a = max(max(r, g), b);
- val = a << 24 | r << 16 | g << 8 | b;
- *c = val;
- }
- }
- c++;
- }
- bcbits += bm.bmWidthBytes;
- }
-
- if (!bm.bmBits) {
- SetBitmapBits(imi.hbmImage, bm.bmWidthBytes*bm.bmHeight, bits);
- free(bits);
- }
- }
- }
- return ImageList_GetIcon(himl,i,ILD_NORMAL);
-}
-
-////////////////////////////////////////////////////////////////////////////
-// This creates new dib image from Imagelist icon ready to alphablend it
-
-HBITMAP ske_ExtractDIBFromImagelistIcon( HIMAGELIST himl,int index, int * outWidth, int * outHeight)
-{
- return NULL;
-}
-
-BOOL ske_ImageList_DrawEx( HIMAGELIST himl,int i,HDC hdcDst,int x,int y,int dx,int dy,COLORREF rgbBk,COLORREF rgbFg,UINT fStyle)
-{
- //the routine to directly draw icon from image list without creating icon from there - should be some faster
- if (i < 0)
- return FALSE;
-
- if (g_CluiData.fDisableSkinEngine)
- return ImageList_DrawEx(himl, i, hdcDst, x, y, dx, dy, rgbBk, rgbFg, fStyle);
-
- BYTE alpha;
- if (fStyle&ILD_BLEND25) alpha = 64;
- else if (fStyle&ILD_BLEND50) alpha = 128;
- else alpha = 255;
-
- HICON hIcon = ske_ImageList_GetIcon(himl, i, ILD_NORMAL);
- if (hIcon == NULL)
- return FALSE;
-
- ske_DrawIconEx(hdcDst, x, y, hIcon, dx ? dx : GetSystemMetrics(SM_CXSMICON), dy ? dy : GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL | (alpha << 24));
- DestroyIcon(hIcon);
- return TRUE;
-}
-
-static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, LPARAM lParam)
-{
- DrawIconFixParam *p = (DrawIconFixParam*)wParam;
- if (!p)
- return 0;
-
- return ske_DrawIconEx(p->hdc,p->xLeft,p->yTop,p->hIcon,p->cxWidth,p->cyWidth,p->istepIfAniCur,p->hbrFlickerFreeDraw,p->diFlags);
-}
-
-
-BOOL ske_DrawIconEx(HDC hdcDst,int xLeft,int yTop,HICON hIcon,int cxWidth,int cyWidth, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags)
-{
- ICONINFO ici;
- BYTE alpha = (BYTE)((diFlags&0xFF000000)>>24);
-
-
- HDC imDC;
- HBITMAP oldBmp, imBmp,tBmp;
- BITMAP imbt,immaskbt;
- BYTE * imbits;
- BYTE * imimagbits;
- BYTE * immaskbits;
- DWORD cx,cy,icy;
- BYTE *t1, *t2, *t3;
-
- BOOL NoDIBImage = FALSE;
- //lockimagelist
- BYTE hasmask = FALSE;
- BYTE no32bit = FALSE;
- BYTE noMirrorMask = FALSE;
- BYTE hasalpha = FALSE;
- alpha = alpha?alpha:255;
-
- if ( g_CluiData.fDisableSkinEngine && !(diFlags&0x80))
- return DrawIconEx(hdcDst,xLeft,yTop,hIcon,cxWidth,cyWidth,istepIfAniCur,hbrFlickerFreeDraw,diFlags&0xFFFF7F);
-
- if (!GetIconInfo(hIcon, &ici))
- return 0;
-
- GetObject(ici.hbmColor,sizeof(BITMAP),&imbt);
- if (imbt.bmWidth*imbt.bmHeight == 0) {
- DeleteObject(ici.hbmColor);
- DeleteObject(ici.hbmMask);
- return 0;
- }
- GetObject(ici.hbmMask,sizeof(BITMAP),&immaskbt);
- cy = imbt.bmHeight;
-
- if (imbt.bmBitsPixel != 32) {
- HBITMAP otBmp;
- no32bit = TRUE;
- HDC tempDC1 = CreateCompatibleDC(hdcDst);
- tBmp = ske_CreateDIB32(imbt.bmWidth, imbt.bmHeight);
- if (tBmp) {
- GetObject(tBmp, sizeof(BITMAP), &imbt);
- otBmp = (HBITMAP)SelectObject(tempDC1, tBmp);
- DrawIconEx(tempDC1, 0, 0, hIcon, imbt.bmWidth, imbt.bmHeight, istepIfAniCur, hbrFlickerFreeDraw, DI_IMAGE);
- noMirrorMask = TRUE;
-
- }
- SelectObject(tempDC1, otBmp);
- DeleteDC(tempDC1);
- }
-
- if (imbt.bmBits == NULL) {
- NoDIBImage = TRUE;
- imimagbits = (BYTE*)malloc(cy*imbt.bmWidthBytes);
- GetBitmapBits(ici.hbmColor, cy*imbt.bmWidthBytes, (void*)imimagbits);
- }
- else imimagbits = (BYTE*)imbt.bmBits;
-
- if (immaskbt.bmBits == NULL) {
- immaskbits = (BYTE*)malloc(cy*immaskbt.bmWidthBytes);
- GetBitmapBits(ici.hbmMask, cy*immaskbt.bmWidthBytes, (void*)immaskbits);
- }
- else immaskbits = (BYTE*)immaskbt.bmBits;
-
- icy = imbt.bmHeight;
- cx = imbt.bmWidth;
- imDC = CreateCompatibleDC(hdcDst);
- imBmp = ske_CreateDIB32Point(cx, icy, (void**)&imbits);
- oldBmp = (HBITMAP)SelectObject(imDC, imBmp);
- if (imbits != NULL && imimagbits != NULL && immaskbits != NULL) {
- int x; int y;
- int bottom, right, top, h;
- int mwb, mwb2;
- mwb = immaskbt.bmWidthBytes;
- mwb2 = imbt.bmWidthBytes;
- bottom = icy;
- right = cx;
- top = 0;
- h = icy;
- for (y = top; (y < bottom) && !hasmask; y++) {
- t1 = immaskbits + y*mwb;
- for (x = 0; (x < mwb) && !hasmask; x++)
- hasmask |= (*(t1 + x) != 0);
- }
-
- for (y = top; (y < bottom) && !hasalpha; y++) {
- t1 = imimagbits + (cy - y - 1)*mwb2;
- for (x = 0; (x < right) && !hasalpha; x++)
- hasalpha |= (*(t1+(x << 2)+3) != 0);
- }
-
- for (y = 0; y < (int)icy; y++) {
- t1 = imimagbits+(h-y-1-top)*mwb2;
- t2 = imbits+(!no32bit?y:(icy-y-1))*mwb2;
- t3 = immaskbits+(noMirrorMask?y:(h-y-1-top))*mwb;
- for (x = 0; x < right; x++) {
- BYTE mask = 0;
- BYTE a = 0;
- DWORD *src = (DWORD*)(t1 + (x << 2));
- DWORD *dest = (DWORD*)(t2 + (x << 2));
- if (hasalpha && !hasmask)
- a = ((BYTE*)src)[3];
- else {
- mask = ((1 << (7 - x % 8))&(*(t3 + (x >> 3)))) != 0;
- if (mask) {
- if (!hasalpha) {
- *dest = 0;
- continue;
- }
-
- if (((BYTE*)src)[3]>0 )
- a = ((BYTE*)src)[3];
- else
- a = 0;
- }
- else if (hasalpha || hasmask)
- a = (((BYTE*)src)[3]>0?((BYTE*)src)[3]:255);
- else if (!hasalpha && !hasmask)
- a = 255;
- else { *dest = 0; continue; }
- }
- if (a > 0) {
- ((BYTE*)dest)[3] = a;
- ((BYTE*)dest)[0] = ((BYTE*)src)[0] * a / 255;
- ((BYTE*)dest)[1] = ((BYTE*)src)[1] * a / 255;
- ((BYTE*)dest)[2] = ((BYTE*)src)[2] * a / 255;
- }
- else *dest = 0;
- }
- }
- }
-
- BLENDFUNCTION bf = { AC_SRC_OVER, diFlags & 128, alpha, AC_SRC_ALPHA };
- ske_AlphaBlend(hdcDst, xLeft, yTop, cxWidth, cyWidth, imDC, 0, 0, cx, icy, bf);
-
- if (immaskbt.bmBits == NULL) free(immaskbits);
- if (imbt.bmBits == NULL) free(imimagbits);
- SelectObject(imDC, oldBmp);
- DeleteObject(imBmp);
- if (no32bit)DeleteObject(tBmp);
- DeleteObject(ici.hbmColor);
- DeleteObject(ici.hbmMask);
- SelectObject(imDC, GetStockObject(DEFAULT_GUI_FONT));
- DeleteDC(imDC);
- return 1;
-}
-
-int ske_PrepareImageButDontUpdateIt(RECT *r)
-{
- if (!g_CluiData.fLayered)
- return ske_ReCreateBackImage(FALSE, r);
-
- mutex_bLockUpdate = 1;
- ske_DrawNonFramedObjects(TRUE, r);
- ske_ValidateFrameImageProc(r);
- mutex_bLockUpdate = 0;
- return 0;
-}
-
-int ske_RedrawCompleteWindow()
-{
- if (g_CluiData.fLayered) {
- ske_DrawNonFramedObjects(TRUE,0);
- CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, 0, 0);
- }
- else RedrawWindow(pcli->hwndContactList,NULL,NULL,RDW_ALLCHILDREN|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME);
-
- return 0;
-}
-
-// Request to repaint frame or change/drop callback data
-// wParam = hWnd of called frame
-// lParam = pointer to sPaintRequest (or NULL to redraw all)
-// return 2 - already queued, data updated, 1-have been queued, 0 - failure
-
-static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam) // Immideately recall paint routines for frame and refresh image
-{
- if ( MirandaLoading())
- return 0;
-
- RECT wnd;
- FRAMEWND *frm;
- BOOL NoCancelPost = 0;
- BOOL IsAnyQueued = 0;
- if (!g_CluiData.mutexOnEdgeSizing)
- GetWindowRect(pcli->hwndContactList,&wnd);
- else
- wnd = g_rcEdgeSizingRect;
-
- if (!g_CluiData.fLayered) {
- RedrawWindow((HWND)wParam,NULL,NULL,RDW_UPDATENOW|RDW_ERASE|RDW_INVALIDATE|RDW_FRAME);
- return 0;
- }
-
- if (g_pCachedWindow == NULL) ske_ValidateFrameImageProc(&wnd);
- else if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) ske_ValidateFrameImageProc(&wnd);
- else if (wParam == 0) ske_ValidateFrameImageProc(&wnd);
- else { // all Ok Update Single Frame
- // TO BE LOCKED OR PROXIED
- frm = FindFrameByItsHWND((HWND)wParam);
- if (!frm)
- ske_ValidateFrameImageProc(&wnd);
- // Validate frame, update window image and remove it from queue
- else {
- if (frm->UpdateRgn) {
- DeleteObject(frm->UpdateRgn);
- frm->UpdateRgn = 0;
- }
- ske_ValidateSingleFrameImage(frm, 0);
- ske_UpdateWindowImage();
- NoCancelPost = 1;
- //-- Remove frame from queue
- if (flag_bUpdateQueued) {
- frm->bQueued = 0;
- for (int i = 0; i < g_nFramesCount; i++)
- if (IsAnyQueued |= g_pfwFrames[i].bQueued)
- break;
- }
- }
- }
-
- if ((!NoCancelPost || !IsAnyQueued) && flag_bUpdateQueued) { // no any queued updating cancel post or need to cancel post
- flag_bUpdateQueued = 0;
- g_flag_bPostWasCanceled = 1;
- }
- return 1;
-}
-static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam) // Post request for updating
-{
- if (MirandaLoading()) return 0;
-
- if (wParam) {
- FRAMEWND *frm = FindFrameByItsHWND((HWND)wParam);
- sPaintRequest *pr = (sPaintRequest*)lParam;
- if (!g_CluiData.fLayered || (frm && frm->floating))
- return InvalidateRect((HWND)wParam, pr ? (RECT*)&(pr->rcUpdate) : NULL, FALSE);
-
- if (frm) {
- if (frm->PaintCallbackProc != NULL) {
- frm->PaintData = (sPaintRequest *)pr;
- frm->bQueued = 1;
- if (pr) {
- HRGN r2;
- if (!IsRectEmpty(&pr->rcUpdate)) {
- RECT rcClient;
- RECT rcUpdate;
- GetClientRect(frm->hWnd, &rcClient);
- IntersectRect(&rcUpdate, &rcClient, &pr->rcUpdate);
- if (IsRectEmpty(&rcUpdate))
- return 0;
- r2 = CreateRectRgn(rcUpdate.left, rcUpdate.top, rcUpdate.right, rcUpdate.bottom);
- }
- else {
- RECT r;
- GetClientRect(frm->hWnd, &r);
- r2 = CreateRectRgn(r.left, r.top, r.right, r.bottom);
- }
-
- if (!frm->UpdateRgn) {
- frm->UpdateRgn = CreateRectRgn(0, 0, 1, 1);
- CombineRgn(frm->UpdateRgn, r2, 0, RGN_COPY);
- }
- else CombineRgn(frm->UpdateRgn, frm->UpdateRgn, r2, RGN_OR);
- DeleteObject(r2);
- }
- }
- }
- else Sync(QueueAllFramesUpdating, 1);
- }
- else Sync(QueueAllFramesUpdating, 1);
-
- if (!flag_bUpdateQueued || g_flag_bPostWasCanceled)
- if (PostMessage(pcli->hwndContactList, UM_UPDATE, 0, 0)) {
- flag_bUpdateQueued = 1;
- g_flag_bPostWasCanceled = 0;
- }
- return 1;
-}
-
-static int ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting) // Calling frame paint proc
-{
- if (!g_pCachedWindow) { TRACE("ske_ValidateSingleFrameImage calling without cached\n"); return 0;}
- if (Frame->hWnd == (HWND)-1 && !Frame->PaintCallbackProc) { TRACE("ske_ValidateSingleFrameImage calling without FrameProc\n"); return 0;}
-
- // if ok update image
- HDC hdc;
- HBITMAP o,n;
- RECT rcPaint,wnd;
- RECT ru = {0};
- int w,h,x,y;
- int w1,h1,x1,y1;
-
- CLUI_SizingGetWindowRect(pcli->hwndContactList,&wnd);
- rcPaint = Frame->wndSize;
- {
- int dx,dy,bx,by;
- if (g_CluiData.mutexOnEdgeSizing)
- {
- dx = rcPaint.left-wnd.left;
- dy = rcPaint.top-wnd.top;
- bx = rcPaint.right-wnd.right;
- by = rcPaint.bottom-wnd.bottom;
- wnd = g_rcEdgeSizingRect;
- rcPaint.left = wnd.left+dx;
- rcPaint.top = wnd.top+dy;
- rcPaint.right = wnd.right+bx;
- rcPaint.bottom = wnd.bottom+by;
- }
- }
- //OffsetRect(&rcPaint,-wnd.left,-wnd.top);
- w = rcPaint.right-rcPaint.left;
- h = rcPaint.bottom-rcPaint.top;
- if (w <= 0 || h <= 0)
- {
- TRACE("Frame size smaller than 0\n");
- return 0;
- }
- x = rcPaint.left;
- y = rcPaint.top;
- hdc = CreateCompatibleDC(g_pCachedWindow->hImageDC);
- n = ske_CreateDIB32(w,h);
- o = (HBITMAP)SelectObject(hdc,n);
- {
- if (Frame->UpdateRgn && !SkipBkgBlitting)
- {
- GetRgnBox(Frame->UpdateRgn,&ru);
- {
- RECT rc;
- GetClientRect(Frame->hWnd,&rc);
- if (ru.top < 0) ru.top = 0;
- if (ru.left < 0) ru.left = 0;
- if (ru.right>rc.right) ru.right = rc.right;
- if (ru.bottom>rc.bottom) ru.bottom = rc.bottom;
- }
- if (!IsRectEmpty(&ru))
- {
- x1 = ru.left;
- y1 = ru.top;
- w1 = ru.right-ru.left;
- h1 = ru.bottom-ru.top;
- }
- else
- {x1 = 0; y1 = 0; w1 = w; h1 = h;}
- // copy image at hdc
- if (SkipBkgBlitting) //image already at foreground
- {
- BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY);
- }
- else
- {
- BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY);
- }
- Frame->PaintCallbackProc(Frame->hWnd,hdc,&ru,Frame->UpdateRgn, Frame->dwFlags,Frame->PaintData);
- }
- else
- {
- HRGN rgnUpdate;
- RECT r;
- GetClientRect(Frame->hWnd,&r);
- rgnUpdate = CreateRectRgn(r.left,r.top,r.right,r.bottom);
- ru = r;
- if (!IsRectEmpty(&ru))
- {
- x1 = ru.left;
- y1 = ru.top;
- w1 = ru.right-ru.left;
- h1 = ru.bottom-ru.top;
- }
- else
- {x1 = 0; y1 = 0; w1 = w; h1 = h;}
- // copy image at hdc
- if (SkipBkgBlitting) //image already at foreground
- {
- BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hImageDC,x+x1,y+y1,SRCCOPY);
- }
- else
- {
- BitBlt(hdc,x1,y1,w1,h1,g_pCachedWindow->hBackDC,x+x1,y+y1,SRCCOPY);
- }
- Frame->PaintCallbackProc(Frame->hWnd,hdc,&r,rgnUpdate, Frame->dwFlags,Frame->PaintData);
- ru = r;
- DeleteObject(rgnUpdate);
- }
- DeleteObject(Frame->UpdateRgn);
- Frame->UpdateRgn = 0;
- }
- if (!IsRectEmpty(&ru))
- {
- x1 = ru.left;
- y1 = ru.top;
- w1 = ru.right-ru.left;
- h1 = ru.bottom-ru.top;
- }
- else {
- x1 = 0; y1 = 0; w1 = w; h1 = h;
- }
-
- BitBlt(g_pCachedWindow->hImageDC,x+x1,y+y1,w1,h1,hdc,x1,y1,SRCCOPY);
-
- if (GetWindowLongPtr(Frame->hWnd, GWL_STYLE) & WS_VSCROLL) {
- //Draw vertical scroll bar
- //
- SCROLLBARINFO si = {0};
- si.cbSize = sizeof(SCROLLBARINFO);
- GetScrollBarInfo(Frame->hWnd, OBJID_VSCROLL, &si);
-
- RECT rLine = (si.rcScrollBar);
- RECT rUpBtn = rLine;
- RECT rDnBtn = rLine;
- RECT rThumb = rLine;
-
- rUpBtn.bottom = rUpBtn.top+si.dxyLineButton;
- rDnBtn.top = rDnBtn.bottom-si.dxyLineButton;
- rThumb.top = rLine.top+si.xyThumbTop;
- rThumb.bottom = rLine.top+si.xyThumbBottom;
-
- int dx = Frame->wndSize.right-rLine.right;
- int dy = -rLine.top + Frame->wndSize.top;
-
- OffsetRect(&rLine, dx, dy);
- OffsetRect(&rUpBtn, dx, dy);
- OffsetRect(&rDnBtn, dx, dy);
- OffsetRect(&rThumb, dx, dy);
- BitBlt(g_pCachedWindow->hImageDC, rLine.left, rLine.top, rLine.right - rLine.left, rLine.bottom - rLine.top, g_pCachedWindow->hBackDC, rLine.left, rLine.top, SRCCOPY);
-
- char req[255];
- mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Back", Frame->szName);
- SkinDrawGlyph(g_pCachedWindow->hImageDC,&rLine,&rLine,req);
- mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=Thumb", Frame->szName);
- SkinDrawGlyph(g_pCachedWindow->hImageDC,&rThumb,&rThumb,req);
- mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar, Frame=%s,Part=UpLineButton", Frame->szName);
- SkinDrawGlyph(g_pCachedWindow->hImageDC,&rUpBtn,&rUpBtn,req);
- mir_snprintf(req, sizeof(req), "Main,ID=ScrollBar,Frame=%s,Part=DownLineButton", Frame->szName);
- SkinDrawGlyph(g_pCachedWindow->hImageDC,&rDnBtn,&rDnBtn,req);
- }
-
- SelectObject(hdc, o);
- DeleteObject(n);
- DeleteDC(hdc);
- return 1;
-}
-
-int ske_BltBackImage (HWND destHWND, HDC destDC, RECT *BltClientRect)
-{
- POINT ptMainWnd = {0};
- POINT ptChildWnd = {0};
- RECT from = {0};
- RECT w = {0};
- if (g_CluiData.fDisableSkinEngine) {
- FillRect(destDC,BltClientRect,GetSysColorBrush(COLOR_3DFACE));
- return 0;
- }
- ske_ReCreateBackImage(FALSE,NULL);
- if (BltClientRect) w = *BltClientRect;
- else GetClientRect(destHWND,&w);
- ptChildWnd.x = w.left;
- ptChildWnd.y = w.top;
- ClientToScreen(destHWND,&ptChildWnd);
- ClientToScreen(pcli->hwndContactList,&ptMainWnd);
- //TODO if main not relative to client area
- return BitBlt(destDC,w.left,w.top,(w.right-w.left),(w.bottom-w.top),g_pCachedWindow->hBackDC,(ptChildWnd.x-ptMainWnd.x),(ptChildWnd.y-ptMainWnd.y),SRCCOPY);
-
-}
-int ske_ReCreateBackImage(BOOL Erase,RECT *w)
-{
- HBITMAP hb2;
- RECT wnd = {0};
- BOOL IsNewCache = 0;
- if (g_CluiData.fDisableSkinEngine) return 0;
- GetClientRect(pcli->hwndContactList,&wnd);
- if (w) wnd = *w;
- //-- Check cached.
- if (g_pCachedWindow == NULL) {
- //-- Create New Cache
- g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
- g_pCachedWindow->hScreenDC = GetDC(NULL);
- g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
- g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
- g_pCachedWindow->Width = wnd.right-wnd.left;
- g_pCachedWindow->Height = wnd.bottom-wnd.top;
- if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) {
- g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
- g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
- g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB);
- g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB);
- }
- IsNewCache = 1;
- }
-
- if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) {
- HBITMAP hb1 = NULL,hb2 = NULL;
- g_pCachedWindow->Width = wnd.right-wnd.left;
- g_pCachedWindow->Height = wnd.bottom-wnd.top;
- if (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0) {
- hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
- hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
- SelectObject(g_pCachedWindow->hImageDC,hb1);
- SelectObject(g_pCachedWindow->hBackDC,hb2);
- }
- else {
- SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld);
- SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld);
- }
- if (g_pCachedWindow->hImageDIB) DeleteObject(g_pCachedWindow->hImageDIB);
- if (g_pCachedWindow->hBackDIB) DeleteObject(g_pCachedWindow->hBackDIB);
- g_pCachedWindow->hImageDIB = hb1;
- g_pCachedWindow->hBackDIB = hb2;
- IsNewCache = 1;
- }
-
- if ((Erase || IsNewCache ) && (g_pCachedWindow->Width != 0 && g_pCachedWindow->Height != 0)) {
- hb2 = ske_CreateDIB32(g_pCachedWindow->Width,g_pCachedWindow->Height);
- SelectObject(g_pCachedWindow->hBackDC,hb2);
- DeleteObject(g_pCachedWindow->hBackDIB);
- g_pCachedWindow->hBackDIB = hb2;
- FillRect(g_pCachedWindow->hBackDC,&wnd,GetSysColorBrush(COLOR_BTNFACE));
- SkinDrawGlyph(g_pCachedWindow->hBackDC,&wnd,&wnd,"Main,ID=Background,Opt=Non-Layered");
- ske_SetRectOpaque(g_pCachedWindow->hBackDC,&wnd);
- }
- return 1;
-}
-
-int ske_DrawNonFramedObjects(BOOL Erase,RECT *r)
-{
- RECT w, wnd;
- if (r) w = *r;
- else CLUI_SizingGetWindowRect(pcli->hwndContactList, &w);
- if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0);
- if (g_pCachedWindow == NULL)
- return ske_ValidateFrameImageProc(&w);
-
- wnd = w;
- OffsetRect(&w, -w.left, -w.top);
- if (Erase) {
- HBITMAP hb2;
- hb2 = ske_CreateDIB32(g_pCachedWindow->Width, g_pCachedWindow->Height);
- SelectObject(g_pCachedWindow->hBackDC, hb2);
- DeleteObject(g_pCachedWindow->hBackDIB);
- g_pCachedWindow->hBackDIB = hb2;
- }
-
- SkinDrawGlyph(g_pCachedWindow->hBackDC, &w, &w, "Main,ID=Background");
-
- //--Draw frames captions
- for (int i = 0; i < g_nFramesCount; i++) {
- if (g_pfwFrames[i].TitleBar.ShowTitleBar && g_pfwFrames[i].visible && !g_pfwFrames[i].floating) {
- RECT rc;
- SetRect(&rc, g_pfwFrames[i].wndSize.left, g_pfwFrames[i].wndSize.top - g_nTitleBarHeight - g_CluiData.nGapBetweenTitlebar, g_pfwFrames[i].wndSize.right, g_pfwFrames[i].wndSize.top - g_CluiData.nGapBetweenTitlebar);
- Sync(DrawTitleBar, g_pCachedWindow->hBackDC, &rc, g_pfwFrames[i].id);
- }
- }
- g_mutex_bLockUpdating = 1;
-
- flag_bJustDrawNonFramedObjects = 1;
- return 0;
-}
-
-int ske_ValidateFrameImageProc(RECT *r) // Calling queued frame paint procs and refresh image
-{
- RECT wnd = {0};
- BOOL IsNewCache = 0;
- BOOL IsForceAllPainting = 0;
- if (r) wnd = *r;
- else GetWindowRect(pcli->hwndContactList,&wnd);
- if (wnd.right-wnd.left == 0 || wnd.bottom-wnd.top == 0)
- return 0;
-
- g_mutex_bLockUpdating = 1;
-
- //-- Check cached.
- if (g_pCachedWindow == NULL) {
- //-- Create New Cache
- g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
- g_pCachedWindow->hScreenDC = GetDC(NULL);
- g_pCachedWindow->hBackDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
- g_pCachedWindow->hImageDC = CreateCompatibleDC(g_pCachedWindow->hScreenDC);
- g_pCachedWindow->Width = wnd.right-wnd.left;
- g_pCachedWindow->Height = wnd.bottom-wnd.top;
- g_pCachedWindow->hImageDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
- g_pCachedWindow->hBackDIB = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
- g_pCachedWindow->hImageOld = (HBITMAP)SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageDIB);
- g_pCachedWindow->hBackOld = (HBITMAP)SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackDIB);
- IsNewCache = 1;
- }
- if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) {
- HBITMAP hb1,hb2;
- g_pCachedWindow->Width = wnd.right-wnd.left;
- g_pCachedWindow->Height = wnd.bottom-wnd.top;
- hb1 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hImageDIBByte));
- hb2 = ske_CreateDIB32Point(g_pCachedWindow->Width,g_pCachedWindow->Height,(void**)&(g_pCachedWindow->hBackDIBByte));
- SelectObject(g_pCachedWindow->hImageDC,hb1);
- SelectObject(g_pCachedWindow->hBackDC,hb2);
- DeleteObject(g_pCachedWindow->hImageDIB);
- DeleteObject(g_pCachedWindow->hBackDIB);
- g_pCachedWindow->hImageDIB = hb1;
- g_pCachedWindow->hBackDIB = hb2;
- IsNewCache = 1;
- }
- if (IsNewCache) {
- ske_DrawNonFramedObjects(0, &wnd);
- IsForceAllPainting = 1;
- }
- if (flag_bJustDrawNonFramedObjects) {
- IsForceAllPainting = 1;
- flag_bJustDrawNonFramedObjects = 0;
- }
- if (IsForceAllPainting) {
- BitBlt(g_pCachedWindow->hImageDC, 0, 0, g_pCachedWindow->Width,g_pCachedWindow->Height,g_pCachedWindow->hBackDC, 0, 0, SRCCOPY);
- Sync( QueueAllFramesUpdating, (BYTE)1 );
- }
- //-- Validating frames
- for (int i=0; i < g_nFramesCount; i++)
- if (g_pfwFrames[i].PaintCallbackProc && g_pfwFrames[i].visible && !g_pfwFrames[i].floating)
- if (g_pfwFrames[i].bQueued || IsForceAllPainting)
- ske_ValidateSingleFrameImage(&g_pfwFrames[i], IsForceAllPainting);
-
- g_mutex_bLockUpdating = 1;
- ModernSkinButtonRedrawAll(0);
- g_mutex_bLockUpdating = 0;
- if (!mutex_bLockUpdate)
- ske_UpdateWindowImageRect(&wnd);
-
- //-- Clear queue
- Sync(QueueAllFramesUpdating, 0);
- flag_bUpdateQueued = 0;
- g_flag_bPostWasCanceled = 0;
- return 1;
-}
-
-int ske_UpdateWindowImage()
-{
- if (MirandaExiting())
- return 0;
-
- if (g_CluiData.fLayered) {
- RECT r;
- GetWindowRect(pcli->hwndContactList,&r);
- return ske_UpdateWindowImageRect(&r);
- }
- else ske_ReCreateBackImage(FALSE,0);
- ske_ApplyTranslucency();
- return 0;
-}
-
-int ske_UpdateWindowImageRect(RECT *r) // Update window with current image and
-{
- //if not validity -> ValidateImageProc
- //else Update using current alpha
- RECT wnd = *r;
-
- if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, 0);
- if (g_pCachedWindow == NULL) return ske_ValidateFrameImageProc(&wnd);
- if (g_pCachedWindow->Width != wnd.right-wnd.left || g_pCachedWindow->Height != wnd.bottom-wnd.top) return ske_ValidateFrameImageProc(&wnd);
- if (g_flag_bFullRepaint) {
- g_flag_bFullRepaint = 0;
- return ske_ValidateFrameImageProc(&wnd);
- }
- ske_JustUpdateWindowImageRect(&wnd);
- return 0;
-}
-
-void ske_ApplyTranslucency()
-{
- int IsTransparancy;
- HWND hwnd = pcli->hwndContactList;
- BOOL layered = (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED)?TRUE:FALSE;
-
- IsTransparancy = g_CluiData.fSmoothAnimation || g_bTransparentFlag;
- if (!g_bTransparentFlag && !g_CluiData.fSmoothAnimation && g_CluiData.bCurrentAlpha != 0)
- g_CluiData.bCurrentAlpha = 255;
-
- if (!g_CluiData.fLayered && IsTransparancy) {
- if (!layered)
- SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
- SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE)g_CluiData.bCurrentAlpha, LWA_ALPHA);
- }
-
- AniAva_RedrawAllAvatars(FALSE);
- return;
-}
-
-int ske_JustUpdateWindowImage()
-{
- RECT r;
- if (!g_CluiData.fLayered) {
- ske_ApplyTranslucency();
- return 0;
- }
- GetWindowRect(pcli->hwndContactList,&r);
- return ske_JustUpdateWindowImageRect(&r);
-}
-
-// Update window image
-int ske_JustUpdateWindowImageRect(RECT *rty)
-{
- if (!g_CluiData.fLayered) {
- ske_ApplyTranslucency();
- return 0;
- }
- if (!pcli->hwndContactList)
- return 0;
-
- RECT wnd = *rty;
- RECT rect = wnd;
- POINT dest = { 0 }, src = { 0 };
- dest.x = rect.left;
- dest.y = rect.top;
- SIZE sz = { rect.right - rect.left, rect.bottom - rect.top };
- if (g_CluiData.fLayered) {
- if (!(GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE)&WS_EX_LAYERED))
- SetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE, GetWindowLongPtr(pcli->hwndContactList, GWL_EXSTYLE) | WS_EX_LAYERED);
- Sync(SetAlpha, g_CluiData.bCurrentAlpha);
-
- BLENDFUNCTION bf = { AC_SRC_OVER, 0, g_CluiData.bCurrentAlpha, AC_SRC_ALPHA };
- UpdateLayeredWindow(pcli->hwndContactList, g_pCachedWindow->hScreenDC, &dest, &sz, g_pCachedWindow->hImageDC, &src, RGB(1, 1, 1), &bf, ULW_ALPHA);
- g_CluiData.fAeroGlass = false;
- CLUI_UpdateAeroGlass();
- }
- else InvalidateRect(pcli->hwndContactList,NULL,TRUE);
- return 0;
-}
-
-int ske_DrawImageAt(HDC hdc, RECT *rc)
-{
- BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
- BitBlt(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,g_pCachedWindow->hBackDC,rc->left,rc->top,SRCCOPY);
- ske_AlphaBlend(g_pCachedWindow->hImageDC,rc->left,rc->top,rc->right-rc->left,rc->bottom-rc->top,hdc, 0, 0, rc->right-rc->left,rc->bottom-rc->top,bf);
- if (!g_mutex_bLockUpdating)
- ske_UpdateWindowImage();
- return 0;
-}
-
-HBITMAP ske_GetCurrentWindowImage()
-{
- return g_pCachedWindow->hImageDIB;
-}
-
-/*
-* Glyph text routine
-*/
-
-static DWORD ske_HexToARGB(char * Hex)
-{
- char buf[10] = {0};
- char buf2[11] = {0};
- mir_snprintf(buf, SIZEOF(buf), "%s\n", Hex);
- if (buf[1] == 'x' || buf[1] == 'X')
- mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf+2);
- else
- mir_snprintf(buf2, SIZEOF(buf2), "0x%s\n", buf);
- buf2[10] = '\0';
-
- char *st;
- DWORD AARRGGBB = strtoul(buf2, &st, 16);
- BYTE alpha = (BYTE)((AARRGGBB & 0xFF000000) >> 24);
- alpha = 255-((alpha == 0)?255:alpha);
- AARRGGBB = (alpha << 24)+((AARRGGBB&0x00FF0000)>>16)+((AARRGGBB&0x000000FF) << 16)+(AARRGGBB&0x0000FF00);
- return AARRGGBB;
-}
-
-static TCHAR *ske_ReAppend(TCHAR *lfirst, TCHAR * lsecond, int len)
-{
- int l1 = lfirst?lstrlen(lfirst):0;
- int l2 = (len?len:(lstrlen(lsecond)+1));
- TCHAR *buf = (TCHAR *)mir_alloc((l1+l2+1)*sizeof(TCHAR));
- if (lfirst) memmove(buf,lfirst,l1*sizeof(TCHAR));
- memmove(buf+l1,lsecond,l2*sizeof(TCHAR));
- mir_free(lfirst);
- if (len) buf[l1+l2] = _T('\0');
- return buf;
-}
-
-TCHAR* ske_ReplaceVar(TCHAR *var)
-{
- if (!var) return mir_tstrdup(_T(""));
- if (!lstrcmpi(var,_T("Profile"))) {
- char buf[MAX_PATH] = {0};
- CallService(MS_DB_GETPROFILENAME,(WPARAM)MAX_PATH,(LPARAM)buf);
-
- int i = strlen(buf);
- while (buf[i] != '.' && i>0) i--;
- buf[i] = '\0';
-
- mir_free(var);
- return mir_a2u(buf);
- }
-
- mir_free(var);
- return mir_tstrdup(_T(""));
-}
-
-TCHAR *ske_ParseText(TCHAR *stzText)
-{
- int len = lstrlen(stzText);
- TCHAR *result = NULL;
- int stpos = 0;
- int curpos = 0;
-
- while (curpos < len) {
- //1 find first %
- while (curpos < len && stzText[curpos] != (TCHAR)'%')
- curpos++;
- if (curpos < len) { //% found
- if (curpos-stpos>0)
- result = ske_ReAppend(result,stzText+stpos,curpos-stpos);
- stpos = curpos+1;
- curpos++;
- //3 find second %
- while(curpos < len && stzText[curpos] != (TCHAR)'%')
- curpos++;
- if (curpos >= len)
- break;
- if (curpos - stpos > 0) {
- TCHAR *var = (TCHAR *)mir_alloc((curpos - stpos + 1)*sizeof(TCHAR));
- memmove(var, stzText + stpos, (curpos - stpos)*sizeof(TCHAR));
- var[curpos - stpos] = (TCHAR)'\0';
- var = ske_ReplaceVar(var);
- result = ske_ReAppend(result, var, 0);
- mir_free(var);
- }
- else result = ske_ReAppend(result, _T("%"), 0);
-
- curpos++;
- stpos = curpos;
- }
- else {
- if (curpos - stpos > 0)
- result = ske_ReAppend(result, stzText + stpos, curpos - stpos);
- break;
- }
- }
- return result;
-}
-/*
-* Parse text object string, find glyph object and add text to it.
-* szGlyphTextID and Define string is:
-* t[szGlyphTextID] = s[HostObjectID],[Left],[Top],[Right],[Bottom],[LTRBHV],[FontID],[Color1],[reservedforColor2],[Text]
-*/
-
-static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin)
-{
- char buf[255] = {0};
- GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE);
- if (buf[0] == 0)
- return;
-
- GLYPHTEXT *glText = (GLYPHTEXT*)mir_calloc(sizeof(GLYPHTEXT));
- glText->szGlyphTextID = mir_strdup(szGlyphTextID);
- glText->szObjectName = mir_strdup(buf);
- glText->iLeft = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE));
- glText->iTop = atoi(GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE));
- glText->iRight = atoi(GetParamN(szDefineString,buf,sizeof(buf),3,',',TRUE));
- glText->iBottom = atoi(GetParamN(szDefineString,buf,sizeof(buf),4,',',TRUE));
- {
- memset(buf, 0, 6);
- GetParamN(szDefineString,buf,sizeof(buf),5,',',TRUE);
- buf[0] &= 95; buf[1] &= 95; buf[2] &= 95; buf[3] &= 95; buf[4] &= 95; buf[5] &= 95; //to uppercase: &01011111 (0-95)
- glText->RelativeFlags =
- (buf[0] == 'C'?1:((buf[0] == 'R')?2:0)) //[BC][RC][BC][RC] --- Left relative
- |(buf[1] == 'C'?4:((buf[1] == 'B')?8:0)) // | | |--------- Top relative
- |(buf[2] == 'C'?16:((buf[2] == 'R')?32:0)) // | |--------------Right relative
- |(buf[3] == 'C'?64:((buf[3] == 'B')?128:0)); // |------------------Bottom relative
- glText->dwFlags = (buf[4] == 'C'?DT_CENTER:((buf[4] == 'R')?DT_RIGHT:DT_LEFT))
- |(buf[5] == 'C'?DT_VCENTER:((buf[5] == 'B')?DT_BOTTOM:DT_TOP));
- }
- glText->szFontID = mir_strdup(GetParamN(szDefineString,buf,sizeof(buf),6,',',TRUE));
-
- glText->dwColor = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),7,',',TRUE));
- glText->dwShadow = ske_HexToARGB(GetParamN(szDefineString,buf,sizeof(buf),8,',',TRUE));
- glText->stValueText = mir_a2u(GetParamN(szDefineString,buf,sizeof(buf),9,',',TRUE));
- glText->stText = ske_ParseText(glText->stValueText);
-
- if (!Skin->pTextList)
- Skin->pTextList = List_Create(0, 1);
- List_InsertPtr(Skin->pTextList,glText);
-}
-
-
-/*
-* Parse font definition string.
-* szGlyphTextID and Define string is:
-* f[szFontID] = s[FontTypefaceName],[size],[BIU]
-*/
-static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin)
-{
- SKINFONT *sf = (SKINFONT*)mir_calloc(sizeof(SKINFONT));
- if (!sf)
- return;
-
- char buf[255];
- int fntSize = 0;
- BOOL fntBold = FALSE, fntItalic = FALSE, fntUnderline = FALSE;
- LOGFONTA logfont = {0};
- logfont.lfCharSet = DEFAULT_CHARSET;
- logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
- logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- logfont.lfQuality = DEFAULT_QUALITY;
- logfont.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
-
- strncpy(logfont.lfFaceName,GetParamN(szDefineString,buf,sizeof(buf), 0, ',',TRUE),32);
- logfont.lfHeight = atoi(GetParamN(szDefineString,buf,sizeof(buf),1,',',TRUE));
- if (logfont.lfHeight < 0) {
- HDC hdc = CreateCompatibleDC(NULL);
- logfont.lfHeight = (long)-MulDiv(logfont.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
- DeleteDC(hdc);
- }
- logfont.lfHeight = -logfont.lfHeight;
- GetParamN(szDefineString,buf,sizeof(buf),2,',',TRUE);
- buf[0] &= 95; buf[1] &= 95; buf[2] &= 95;
- logfont.lfWeight = (buf[0] == 'B')?FW_BOLD:FW_NORMAL;
- logfont.lfItalic = (buf[1] == 'I')?1:0;
- logfont.lfUnderline = (buf[2] == 'U')?1:0;
-
- sf->hFont = CreateFontIndirectA(&logfont);
- if (sf->hFont) {
- sf->szFontID = mir_strdup(szFontID);
- if (!gl_plSkinFonts)
- gl_plSkinFonts = List_Create(0, 1);
- if (gl_plSkinFonts)
- List_Insert(gl_plSkinFonts,(void*)sf,gl_plSkinFonts->realCount);
- }
-}
-
-/*
- * ske_CheckHasAlfaChannel - checks if image has at least one BYTE in alpha chennel
- * that is not a 0. (is image real 32 bit or just 24 bit)
- */
-static BOOL ske_CheckHasAlfaChannel(BYTE * from, int widthByte, int height)
-{
- DWORD *pt = (DWORD*)from;
- for (int j = 0; j < height; j++) {
- BYTE *add = (BYTE*)pt+widthByte;
- while (pt < (DWORD*)add) {
- if ((*pt & 0xFF000000) != 0)
- return TRUE;
- pt++;
- }
- pt = (DWORD*)(from+widthByte*j);
- }
- return FALSE;
-}
-
-/*
- * ske_CheckIconHasMask - checks if mask image has at least one that is not a 0.
- * Not sure is ir required or not
- */
-static BOOL ske_CheckIconHasMask(BYTE * from)
-{
- for (int i=0; i < 16*16/8; i++)
- if (from[i] != 0)
- return TRUE;
-
- return FALSE;
-}
-
-/*
- * ske_GetMaskBit - return value of apropriate mask bit in line at x position
- */
-static BOOL ske_GetMaskBit(BYTE *line, int x)
-{
- return ((*(line+(x>>3)))&(0x01 << (7-(x&0x07)))) != 0;
-}
-
-/*
- * ske_Blend - alpha ske_Blend ARGB values of 2 pixels. X1 - underlaying,
- * X2 - overlaying points.
- */
-
-static DWORD ske_Blend(DWORD X1,DWORD X2, BYTE alpha)
-{
- BYTE a1 = (BYTE)(X1>>24);
- BYTE a2 = (BYTE)(((X2>>24)*alpha)>>8);
- BYTE r1 = (BYTE)(X1>>16);
- BYTE r2 = (BYTE)(X2>>16);
- BYTE g1 = (BYTE)(X1>>8);
- BYTE g2 = (BYTE)(X2>>8);
- BYTE b1 = (BYTE)(X1);
- BYTE b2 = (BYTE)(X2);
-
- BYTE a_1 = ~a1;
- BYTE a_2 = ~a2;
- WORD am = (WORD)a1*a_2;
-
- /* it is possible to use >>8 instead of /255 but it is require additional
- * checking of alphavalues
- */
- WORD ar = a1+(((WORD)a_1*a2)/255);
- // if a2 more than 0 than result should be more
- // or equal (if a1 == 0) to a2, else in combination
- // with mask we can get here black points
-
- ar = (a2>ar)?a2:ar;
-
- if (ar == 0) return 0;
-
- WORD arm = ar*255;
- WORD rr = (((WORD)r1*am+(WORD)r2*a2*255))/arm;
- WORD gr = (((WORD)g1*am+(WORD)g2*a2*255))/arm;
- WORD br = (((WORD)b1*am+(WORD)b2*a2*255))/arm;
- return (ar << 24)|(rr << 16)|(gr << 8)|br;
-}
-
-/*
- * CreateJoinedIcon - creates new icon by drawing hTop over hBottom.
- */
-
-HICON ske_CreateJoinedIcon(HICON hBottom, HICON hTop, BYTE alpha)
-{
- HBITMAP nMask;
- BITMAP bmp = { 0 };
- BYTE *ptPixels;
- ICONINFO iNew = { 0 };
- ICONINFO iciBottom = { 0 };
- ICONINFO iciTop = { 0 };
-
- BITMAP bmp_top = { 0 };
- BITMAP bmp_top_mask = { 0 };
-
- BITMAP bmp_bottom = { 0 };
- BITMAP bmp_bottom_mask = { 0 };
-
- HDC tempDC = CreateCompatibleDC(NULL);
- HBITMAP nImage = ske_CreateDIB32Point(16, 16, (void**)&ptPixels);
- HBITMAP oImage = (HBITMAP)SelectObject(tempDC, nImage);
-
- GetIconInfo(hBottom, &iciBottom);
- GetObject(iciBottom.hbmColor, sizeof(BITMAP), &bmp_bottom);
- GetObject(iciBottom.hbmMask, sizeof(BITMAP), &bmp_bottom_mask);
-
- GetIconInfo(hTop, &iciTop);
- GetObject(iciTop.hbmColor, sizeof(BITMAP), &bmp_top);
- GetObject(iciTop.hbmMask, sizeof(BITMAP), &bmp_top_mask);
-
- if (bmp_bottom.bmBitsPixel == 32 && bmp_top.bmBitsPixel == 32) {
- BYTE *BottomBuffer, *TopBuffer, *BottomMaskBuffer, *TopMaskBuffer;
- BYTE *bb, *tb, *bmb, *tmb;
- BYTE *db = ptPixels;
- int vstep_d = 16 * 4;
- int vstep_b = bmp_bottom.bmWidthBytes;
- int vstep_t = bmp_top.bmWidthBytes;
- int vstep_bm = bmp_bottom_mask.bmWidthBytes;
- int vstep_tm = bmp_top_mask.bmWidthBytes;
- alpha = alpha ? alpha : 255;
- if (bmp_bottom.bmBits) bb = BottomBuffer = (BYTE*)bmp_bottom.bmBits;
- else {
- BottomBuffer = (BYTE*)malloc(bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes);
- GetBitmapBits(iciBottom.hbmColor, bmp_bottom.bmHeight*bmp_bottom.bmWidthBytes, BottomBuffer);
- bb = BottomBuffer + vstep_b*(bmp_bottom.bmHeight - 1);
- vstep_b = -vstep_b;
- }
-
- if (bmp_top.bmBits) tb = TopBuffer = (BYTE*)bmp_top.bmBits;
- else {
- TopBuffer = (BYTE*)malloc(bmp_top.bmHeight*bmp_top.bmWidthBytes);
- GetBitmapBits(iciTop.hbmColor,bmp_top.bmHeight*bmp_top.bmWidthBytes,TopBuffer);
- tb = TopBuffer+vstep_t*(bmp_top.bmHeight-1);
- vstep_t = -vstep_t;
- }
-
- if (bmp_bottom_mask.bmBits) {
- BottomMaskBuffer = (BYTE*)bmp_bottom_mask.bmBits;
- bmb = BottomMaskBuffer;
- }
- else {
- BottomMaskBuffer = (BYTE*)malloc(bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes);
- GetBitmapBits(iciBottom.hbmMask,bmp_bottom_mask.bmHeight*bmp_bottom_mask.bmWidthBytes,BottomMaskBuffer);
- bmb = BottomMaskBuffer+vstep_bm*(bmp_bottom_mask.bmHeight-1);
- vstep_bm = -vstep_bm;
-
- }
-
- if (bmp_top_mask.bmBits) {
- TopMaskBuffer = (BYTE*)bmp_top_mask.bmBits;
- tmb = TopMaskBuffer;
- }
- else {
- TopMaskBuffer = (BYTE*)malloc(bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes);
- GetBitmapBits(iciTop.hbmMask,bmp_top_mask.bmHeight*bmp_top_mask.bmWidthBytes,TopMaskBuffer);
- tmb = TopMaskBuffer+vstep_tm*(bmp_top_mask.bmHeight-1);
- vstep_tm = -vstep_tm;
- }
-
- BOOL topHasAlpha = ske_CheckHasAlfaChannel(TopBuffer, bmp_top.bmWidthBytes, bmp_top.bmHeight);
- BOOL bottomHasAlpha = ske_CheckHasAlfaChannel(BottomBuffer, bmp_bottom.bmWidthBytes, bmp_bottom.bmHeight);
- BOOL topHasMask = ske_CheckIconHasMask(TopMaskBuffer);
- BOOL bottomHasMask = ske_CheckIconHasMask(BottomMaskBuffer);
- for (int y = 0; y < 16; y++) {
- for (int x = 0; x < 16; x++) {
- BOOL mask_b = ske_GetMaskBit(bmb, x);
- BOOL mask_t = ske_GetMaskBit(tmb, x);
- DWORD bottom_d = ((DWORD*)bb)[x];
- DWORD top_d = ((DWORD*)tb)[x];
- if (topHasMask) {
- if (mask_t == 1 && !topHasAlpha) top_d &= 0xFFFFFF;
- else if (!topHasAlpha) top_d |= 0xFF000000;
- }
- if (bottomHasMask) {
- if (mask_b == 1 && !bottomHasAlpha) bottom_d &= 0xFFFFFF;
- else if (!bottomHasAlpha) bottom_d |= 0xFF000000;
- }
- ((DWORD*)db)[x] = ske_Blend(bottom_d, top_d, alpha);
- }
- bb += vstep_b;
- tb += vstep_t;
- bmb += vstep_bm;
- tmb += vstep_tm;
- db += vstep_d;
- }
-
- if (!bmp_bottom.bmBits) free(BottomBuffer);
- if (!bmp_top.bmBits) free(TopBuffer);
- if (!bmp_bottom_mask.bmBits) free(BottomMaskBuffer);
- if (!bmp_top_mask.bmBits) free(TopMaskBuffer);
- }
- else {
- ske_DrawIconEx(tempDC, 0, 0, hBottom,16,16, 0, NULL,DI_NORMAL);
- ske_DrawIconEx(tempDC, 0, 0, hTop,16,16, 0, NULL,DI_NORMAL|(alpha << 24));
- }
-
- DeleteObject(iciBottom.hbmColor);
- DeleteObject(iciTop.hbmColor);
- DeleteObject(iciBottom.hbmMask);
- DeleteObject(iciTop.hbmMask);
-
- SelectObject(tempDC,oImage);
- DeleteDC(tempDC);
-
- BYTE p[32] = {0};
- nMask = CreateBitmap(16,16,1,1,(void*)&p);
- {
- HDC tempDC2 = CreateCompatibleDC(NULL);
- HDC tempDC3 = CreateCompatibleDC(NULL);
- HBITMAP hbm = CreateCompatibleBitmap(tempDC3,16,16);
- HBITMAP obmp = (HBITMAP)SelectObject(tempDC2,nMask);
- HBITMAP obmp2 = (HBITMAP)SelectObject(tempDC3,hbm);
- DrawIconEx(tempDC2, 0, 0, hBottom,16,16, 0, NULL,DI_MASK);
- DrawIconEx(tempDC3, 0, 0, hTop,16,16, 0, NULL,DI_MASK);
- BitBlt(tempDC2, 0, 0, 16,16,tempDC3, 0, 0, SRCAND);
- SelectObject(tempDC2,obmp);
- SelectObject(tempDC3,obmp2);
- DeleteObject(hbm);
- DeleteDC(tempDC2);
- DeleteDC(tempDC3);
- }
- iNew.fIcon = TRUE;
- iNew.hbmColor = nImage;
- iNew.hbmMask = nMask;
- HICON res = CreateIconIndirect(&iNew);
- DeleteObject(nImage);
- DeleteObject(nMask);
- return res;
-}
-
-#define NEWJOINEDSTR( destination, first, separator, last) \
- destination = (char*)alloca(strlen(first)+strlen(separator)+strlen(last)+1); \
- if (destination) { \
- *destination = '\0'; \
- strcat(destination,first); \
- strcat(destination,separator); \
- strcat(destination,last); \
- }
-
-#define SKINSETSECTION "SkinnedSettings"
-
-BOOL SkinDBGetContactSetting(MCONTACT hContact, const char* szSection, const char*szKey, DBVARIANT * retdbv, BOOL * bSkinned )
-{
- if (!hContact) { //only for not contact settings
- char *szSkinKey;
- NEWJOINEDSTR(szSkinKey, szSection, "@", szKey);
- if (!db_get(hContact, SKINSETSECTION, szSkinKey, retdbv)) {
- if (bSkinned) *bSkinned = TRUE;
- return FALSE;
- }
- }
- // not skinned
- if (bSkinned) bSkinned = FALSE;
- return db_get(hContact, szSection, szKey, retdbv);
-}
-
-BYTE SkinDBGetContactSettingByte(MCONTACT hContact, const char* szSection, const char*szKey, BYTE bDefault)
-{
- DBVARIANT dbv = { 0 };
- BOOL bSkinned = FALSE;
- if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
- if (dbv.type == DBVT_BYTE) {
- BYTE retVal = dbv.bVal;
- db_free(&dbv);
- return retVal;
- }
- else {
- db_free(&dbv);
- if (!bSkinned)
- return db_get_b(hContact, szSection, szKey, bDefault);
- }
- }
- return bDefault;
-}
-
-WORD SkinDBGetContactSettingWord(MCONTACT hContact, const char* szSection, const char*szKey, WORD wDefault)
-{
- BOOL bSkinned = FALSE;
- DBVARIANT dbv = { 0 };
- if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
- if (dbv.type == DBVT_WORD) {
- WORD retVal = dbv.wVal;
- db_free(&dbv);
- return retVal;
- }
- db_free(&dbv);
- if (!bSkinned)
- return db_get_w(hContact, szSection, szKey, wDefault);
- }
- return wDefault;
-}
-
-DWORD SkinDBGetContactSettingDword(MCONTACT hContact, const char* szSection, const char*szKey, DWORD dwDefault)
-{
- DBVARIANT dbv = { 0 };
- BOOL bSkinned = FALSE;
- if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
- if (dbv.type == DBVT_DWORD) {
- DWORD retVal = dbv.dVal;
- db_free(&dbv);
- return retVal;
- }
- db_free(&dbv);
- if (!bSkinned)
- return db_get_dw(hContact, szSection, szKey, dwDefault);
- }
- return dwDefault;
-}
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (c) 2012-14 Miranda NG project (http://miranda-ng.org),
+Copyright (c) 2000-08 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+//Include
+#include "hdr/modern_commonheaders.h"
+#include <m_png.h>
+#include "m_api/m_skin_eng.h"
+#include "hdr/modern_skinselector.h"
+#include "CLUIFrames/cluiframes.h"
+
+#define _EFFECTENUM_FULL_H
+#include "hdr/modern_effectenum.h"
+#undef _EFFECTENUM_FULL_H
+
+#include "hdr/modern_skinengine.h"
+#include "hdr/modern_commonprototypes.h"
+#include "hdr/modern_sync.h"
+//Implementation
+
+/* Global variables */
+
+SKINOBJECTSLIST g_SkinObjectList = {0};
+CURRWNDIMAGEDATA *g_pCachedWindow = NULL;
+
+BOOL g_flag_bPostWasCanceled = FALSE;
+BOOL g_flag_bFullRepaint = FALSE;
+BOOL g_mutex_bLockUpdating = FALSE;
+
+SortedList *gl_plGlyphTexts = NULL;
+SortedList *gl_plSkinFonts = NULL;
+
+/* Private module variables */
+
+static HANDLE hSkinLoadedEvent;
+
+static GLYPHIMAGE *pLoadedImages = NULL;
+static DWORD dwLoadedImagesCount = 0;
+static DWORD dwLoadedImagesAlocated = 0;
+
+static BOOL flag_bUpdateQueued = FALSE;
+static BOOL flag_bJustDrawNonFramedObjects = FALSE;
+static BOOL mutex_bLockUpdate = FALSE;
+
+static LIST<EFFECTSSTACKITEM> arEffectStack(10, HandleKeySortT);
+static SKINOBJECTSLIST *pCurrentSkin = NULL;
+static char **pszSettingName = NULL;
+static int nArrayLen = 0;
+
+static BYTE pbGammaWeight[256] = {0};
+static BYTE pbGammaWeightAdv[256] = {0};
+static BOOL bGammaWeightFilled = FALSE;
+
+static CRITICAL_SECTION cs_SkinChanging = {0};
+
+static LISTMODERNMASK *MainModernMaskList = NULL;
+
+/* Private module procedures */
+static BOOL ske_GetMaskBit(BYTE *line, int x);
+static INT_PTR ske_Service_AlphaTextOut(WPARAM wParam, LPARAM lParam);
+static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, LPARAM lParam);
+
+static int ske_AlphaTextOut (HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, DWORD ARGBcolor);
+static void ske_AddParseTextGlyphObject(char * szGlyphTextID,char * szDefineString,SKINOBJECTSLIST *Skin);
+static void ske_AddParseSkinFont(char * szFontID,char * szDefineString,SKINOBJECTSLIST *Skin);
+static int ske_DeleteAllSettingInSection(char * SectionName);
+static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin);
+static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType,SKINOBJECTSLIST* Skin);
+static int ske_LoadSkinFromResource(BOOL bOnlyObjects);
+static void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult);
+static int ske_ValidateSingleFrameImage(FRAMEWND * Frame, BOOL SkipBkgBlitting);
+static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM lParam);
+static INT_PTR ske_Service_InvalidateFrameImage(WPARAM wParam, LPARAM lParam);
+static INT_PTR ske_Service_DrawTextWithEffect(WPARAM wParam, LPARAM lParam);
+
+static MODERNEFFECT meCurrentEffect = {-1,{0}, 0, 0};
+
+
+//////////////////////////////////////////////////////////////////////////
+// Ini file parser
+//////////////////////////////////////////////////////////////////////////
+IniParser::IniParser(TCHAR * tcsFileName, BYTE flags) : _Flags(flags)
+{
+ _DoInit();
+ if (!tcsFileName) return;
+
+ if (tcsFileName[0] == _T('%'))
+ {
+ //TODO: Add parser of resource filename here
+ _LoadResourceIni(g_hInst, MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF");
+ return;
+ }
+
+ _hFile = _tfopen(tcsFileName, _T("r"));
+
+ if (_hFile != NULL)
+ {
+ _eType = IT_FILE;
+ _isValid = true;
+ }
+}
+
+IniParser::IniParser(HINSTANCE hInst, const char * resourceName, const char * resourceType, BYTE flags) : _Flags(flags)
+{
+ _DoInit();
+ _LoadResourceIni(hInst, resourceName, resourceType);
+}
+
+IniParser::~IniParser()
+{
+ mir_free(_szSection);
+ if (_hFile) fclose(_hFile);
+ if (_hGlobalRes) {
+ UnlockResource(_hGlobalRes);
+ FreeResource(_hGlobalRes);
+ }
+
+ _szSection = NULL;
+ _hGlobalRes = NULL;
+ _hFile = NULL;
+ _isValid = false;
+ _eType = IT_UNKNOWN;
+}
+
+HRESULT IniParser::Parse(ParserCallback_t pLineCallBackProc, LPARAM SecCheck)
+{
+ if (_isValid && pLineCallBackProc)
+ {
+ _pLineCallBackProc = pLineCallBackProc;
+ _SecCheck = SecCheck;
+ switch (_eType) {
+ case IT_FILE:
+ return _DoParseFile();
+ case IT_RESOURCE:
+ return _DoParseResource();
+ }
+ }
+ return E_FAIL;
+}
+
+HRESULT IniParser::WriteStrToDb( const char * szSection, const char * szName, const char * szValue, IniParser * This )
+{
+ if ( This->_SecCheck) {
+ //TODO check security here
+ if ( wildcmp( szSection,"Skin_Description_Section"))
+ return S_OK;
+ }
+ if (( This->_Flags == IniParser::FLAG_ONLY_OBJECTS ) && !wildcmp( szSection, DEFAULTSKINSECTION))
+ return S_OK; // skip not objects
+
+ switch (szValue[0]) {
+ case 'b':
+ db_set_b(NULL, szSection, szName, (BYTE)atoi(szValue + 1));
+ break;
+
+ case 'w':
+ db_set_w(NULL, szSection, szName, (WORD)atoi(szValue + 1));
+ break;
+
+ case 'd':
+ db_set_dw(NULL, szSection, szName, (DWORD)atoi(szValue + 1));
+ break;
+
+ case 's':
+ db_set_s(NULL, szSection, szName, szValue + 1);
+ break;
+ }
+ return S_OK;
+}
+
+int IniParser::GetSkinFolder( IN const TCHAR * szFileName, OUT TCHAR * pszFolderName )
+{
+ TCHAR *szBuff = mir_tstrdup(szFileName);
+ TCHAR *pszPos = szBuff + _tcslen(szBuff);
+ while ( pszPos > szBuff && *pszPos != _T('.')) { pszPos--; }
+ *pszPos = _T('\0');
+ _tcscpy( pszFolderName, szBuff );
+
+ TCHAR custom_folder[MAX_PATH];
+ TCHAR cus[MAX_PATH];
+ TCHAR *b3;
+ _tcscpy( custom_folder, pszFolderName );
+ b3 = custom_folder + _tcslen( custom_folder );
+ while ( b3 > custom_folder && *b3 != _T('\\')) { b3--; }
+ *b3 = _T('\0');
+
+ GetPrivateProfileString(_T("Skin_Description_Section"),_T("SkinFolder"),_T(""),cus,SIZEOF(custom_folder),szFileName);
+ if (cus[0] != 0)
+ mir_sntprintf(pszFolderName, MAX_PATH, _T("%s\\%s"), custom_folder, cus);
+
+ mir_free(szBuff);
+ PathToRelativeT(pszFolderName, pszFolderName);
+ return 0;
+}
+
+void IniParser::_DoInit()
+{
+ _isValid = false;
+ _eType = IT_UNKNOWN;
+ _szSection = NULL;
+ _hFile = NULL;
+ _hGlobalRes = NULL;
+ _dwSizeOfRes = 0;
+ _pPosition = NULL;
+ _pLineCallBackProc = NULL;
+ _SecCheck = 0;
+}
+
+void IniParser::_LoadResourceIni( HINSTANCE hInst, const char * resourceName, const char * resourceType )
+{
+ if (_eType != IT_UNKNOWN)
+ return;
+
+ HRSRC hRSrc = FindResourceA(hInst, resourceName, resourceType);
+ if (!hRSrc)
+ return;
+
+ _hGlobalRes = LoadResource(hInst, hRSrc);
+ if (!_hGlobalRes)
+ return;
+
+ _dwSizeOfRes = SizeofResource(hInst, hRSrc);
+ _pPosition = (char*)LockResource(_hGlobalRes);
+
+ _isValid = true;
+ _eType = IT_RESOURCE;
+}
+
+HRESULT IniParser::_DoParseFile()
+{
+ char szLine[MAX_LINE_LEN];
+ _nLine = 0;
+ while (fgets(szLine, SIZEOF(szLine), _hFile) != NULL) {
+ size_t len = 0;
+ char * pLine = (char*)_RemoveTailings(szLine, len);
+ if (len > 0) {
+ pLine[len] = '\0';
+ if (!_DoParseLine(pLine)) return E_FAIL;
+ }
+ else _nLine++;
+ };
+
+ return S_OK;
+}
+
+HRESULT IniParser::_DoParseResource()
+{
+ _nLine = 0;
+ char szLine[MAX_LINE_LEN];
+ char * pos = (char*)_pPosition;
+
+ while (pos < _pPosition + _dwSizeOfRes) {
+ int i = 0;
+ while (pos < _pPosition + _dwSizeOfRes && *pos != '\n' && *pos != '\0' && i < MAX_LINE_LEN - 1) {
+ if ((*pos) != '\r')
+ szLine[i++] = *pos;
+ pos++;
+ }
+ szLine[i] = '\0';
+ pos++;
+
+ size_t len = 0;
+ char * pLine = (char*)_RemoveTailings(szLine, len);
+ if (len > 0) {
+ pLine[len] = '\0';
+ if (!_DoParseLine(pLine)) return E_FAIL;
+ }
+ else _nLine++;
+ }
+ return S_OK;
+}
+
+const char * IniParser::_RemoveTailings( const char * szLine, size_t& len )
+{
+ const char * pStart = szLine;
+ while (*pStart == ' ' || *pStart == '\t')
+ pStart++; //skip spaces at begin
+ const char * pEnd = pStart + strlen(pStart);
+ while (pEnd > pStart && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n' || *pEnd == '\r'))
+ pEnd--;
+
+ len = pEnd - pStart;
+ return pStart;
+}
+
+BOOL IniParser::_DoParseLine( char * szLine )
+{
+ _nLine++;
+ DWORD len = strlen( szLine );
+
+ if (len == 0) return TRUE;
+
+ switch( szLine[0] ) {
+ case ';':
+ return TRUE; // start of comment is found
+
+ case '[':
+ //New section start here
+ mir_free(_szSection);
+ _szSection = NULL;
+ {
+ char *tbuf = szLine + 1; // skip [
+
+ char *ebuf = tbuf;
+
+ while (*ebuf != ']' && *ebuf != '\0') ebuf++;
+ if (*ebuf == '\0')
+ return FALSE; // no close bracket
+
+ DWORD sectionLen = ebuf - tbuf;
+ _szSection = (char*)mir_alloc(sectionLen + 1);
+ strncpy(_szSection, tbuf, sectionLen);
+ _szSection[sectionLen] = '\0';
+ }
+ return TRUE;
+
+ default:
+ if (!_szSection )
+ return TRUE; //param found out of section
+
+ char *keyName = szLine;
+ char *keyValue = szLine;
+
+ DWORD eqPlace = 0;
+ DWORD len2 = strlen(keyName);
+
+ while ( eqPlace < len2 && keyName[ eqPlace ] != '=' )
+ eqPlace++; //find '='
+
+ if (eqPlace == 0 || eqPlace == len2)
+ return TRUE; // = not found or no key name //say false
+
+ keyName[eqPlace] = '\0';
+
+ keyValue = keyName + eqPlace + 1;
+
+ //remove tail spaces in Name
+ {
+ DWORD len3 = strlen(keyName);
+ int j = len3-1;
+ while (j>0 && (keyName[j] == ' ' || keyName[j] == '\t')) j--;
+ if (j >= 0) keyName[j+1] = '\0';
+ }
+ //remove start spaces in Value
+ {
+ DWORD len3 = strlen(keyValue);
+ DWORD j = 0;
+ while (j < len3 && (keyValue[j] == ' ' || keyValue[j] == '\t')) j++;
+ if (j < len3) keyValue += j;
+ }
+ //remove tail spaces in Value
+ {
+ DWORD len3 = strlen(keyValue);
+ int j = len3-1;
+ while (j>0 && (keyValue[j] == ' ' || keyValue[j] == '\t' || keyValue[j] == '\n')) j--;
+ if (j >= 0) keyValue[j+1] = '\0';
+ }
+ _pLineCallBackProc( _szSection, keyName, keyValue, this );
+ }
+ return TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+// End of IniParser
+//////////////////////////////////////////////////////////////////////////
+
+HRESULT SkinEngineLoadModule()
+{
+ ModernSkinButtonLoadModule();
+ InitializeCriticalSection(&cs_SkinChanging);
+ MainModernMaskList = (LISTMODERNMASK*)mir_calloc(sizeof(LISTMODERNMASK));
+ //init variables
+ g_SkinObjectList.dwObjLPAlocated = 0;
+ g_SkinObjectList.dwObjLPReserved = 0;
+ g_SkinObjectList.pObjects = NULL;
+ // Initialize GDI+
+ InitGdiPlus();
+ AniAva_InitModule();
+ //create services
+ CreateServiceFunction(MS_SKIN_DRAWGLYPH,ske_Service_DrawGlyph);
+ CreateServiceFunction(MS_SKINENG_UPTATEFRAMEIMAGE,ske_Service_UpdateFrameImage);
+ CreateServiceFunction(MS_SKINENG_INVALIDATEFRAMEIMAGE,ske_Service_InvalidateFrameImage);
+ CreateServiceFunction(MS_SKINENG_ALPHATEXTOUT,ske_Service_AlphaTextOut);
+ CreateServiceFunction(MS_SKINENG_DRAWICONEXFIX,ske_Service_DrawIconEx);
+
+ CreateServiceFunction(MS_DRAW_TEXT_WITH_EFFECT,ske_Service_DrawTextWithEffect);
+
+ //create event handle
+ hSkinLoadedEvent = HookEvent(ME_SKIN_SERVICESCREATED,CLUI_OnSkinLoad);
+ NotifyEventHooks(g_CluiData.hEventSkinServicesCreated, 0, 0);
+ return S_OK;
+}
+
+int SkinEngineUnloadModule()
+{
+ //unload services
+ ModernSkinButtonUnloadModule(0, 0);
+ ske_UnloadSkin(&g_SkinObjectList);
+
+ mir_free_and_nil(g_SkinObjectList.pObjects);
+ mir_free_and_nil(g_SkinObjectList.pMaskList);
+ mir_free_and_nil(MainModernMaskList);
+
+ for (int i=0; i < arEffectStack.getCount(); i++)
+ mir_free(arEffectStack[i]);
+ arEffectStack.destroy();
+
+ if (g_pCachedWindow) {
+ SelectObject(g_pCachedWindow->hBackDC,g_pCachedWindow->hBackOld);
+ SelectObject(g_pCachedWindow->hImageDC,g_pCachedWindow->hImageOld);
+ DeleteObject(g_pCachedWindow->hBackDIB);
+ DeleteObject(g_pCachedWindow->hImageDIB);
+ DeleteDC(g_pCachedWindow->hBackDC);
+ DeleteDC(g_pCachedWindow->hImageDC);
+ ReleaseDC(NULL,g_pCachedWindow->hScreenDC);
+ mir_free_and_nil(g_pCachedWindow);
+ }
+ DeleteCriticalSection(&cs_SkinChanging);
+ GdiFlush();
+ DestroyHookableEvent(g_CluiData.hEventSkinServicesCreated);
+ AniAva_UnloadModule();
+ ShutdownGdiPlus();
+ //free variables
+ return 1;
+}
+
+BOOL ske_AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int nHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction)
+{
+ if (g_CluiData.fDisableSkinEngine && !(blendFunction.BlendFlags&128))
+ {
+ if (nWidthDest != nWidthSrc || nHeightDest != nHeightSrc)
+ return StretchBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc, SRCCOPY);
+ else
+ return BitBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc, SRCCOPY);
+ }
+
+ if (blendFunction.BlendFlags&128) //Use gdi+ engine
+ {
+ return GDIPlus_AlphaBlend( hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,
+ hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,
+ &blendFunction);
+ }
+ blendFunction.BlendFlags &= ~128;
+ return AlphaBlend(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,blendFunction);
+}
+
+static int ske_LockSkin()
+{
+ EnterCriticalSection(&cs_SkinChanging);
+ return 0;
+}
+
+static int ske_UnlockSkin()
+{
+ LeaveCriticalSection(&cs_SkinChanging);
+ return 0;
+}
+
+struct DCBUFFER
+{
+ HDC hdcOwnedBy;
+ int nUsageID;
+ int width;
+ int height;
+ void* pImage;
+ HDC hDC;
+ HBITMAP oldBitmap;
+ HBITMAP hBitmap;
+ DWORD dwDestroyAfterTime;
+};
+
+static int SortBufferList(const DCBUFFER *buf1, const DCBUFFER *buf2)
+{
+ if (buf1->hdcOwnedBy != buf2->hdcOwnedBy) return (int)(buf1->hdcOwnedBy < buf2->hdcOwnedBy);
+ else if (buf1->nUsageID != buf2->nUsageID) return (int)(buf1->nUsageID < buf2->nUsageID);
+ else return (int)(buf1->hDC < buf2->hDC);
+}
+
+LIST<DCBUFFER> BufferList(2, SortBufferList);
+CRITICAL_SECTION BufferListCS = {0};
+
+enum
+{
+ BUFFER_DRAWICON = 0,
+ BUFFER_DRAWIMAGE
+};
+
+HDC ske_RequestBufferDC(HDC hdcOwner, int dcID, int width, int height, BOOL fClear)
+{
+ mir_cslock lck(BufferListCS);
+ //Try to find DC in buffer list
+ DCBUFFER buf;
+ buf.hdcOwnedBy = hdcOwner;
+ buf.nUsageID = dcID;
+ buf.hDC = NULL;
+ DCBUFFER *pBuf = BufferList.find(&buf);
+ if (!pBuf) {
+ //if not found - allocate it
+ pBuf = (DCBUFFER *)mir_alloc(sizeof(DCBUFFER));
+ *pBuf = buf;
+ pBuf->width = width;
+ pBuf->height = height;
+ pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage));
+ pBuf->hDC = CreateCompatibleDC(hdcOwner);
+ pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap);
+ pBuf->dwDestroyAfterTime = 0;
+ BufferList.insert(pBuf);
+ }
+ else
+ {
+ if (pBuf->width != width || pBuf->height != height)
+ {
+ //resize
+ SelectObject(pBuf->hDC,pBuf->oldBitmap);
+ DeleteObject(pBuf->hBitmap);
+ pBuf->width = width;
+ pBuf->height = height;
+ pBuf->hBitmap = ske_CreateDIB32Point(width,height,&(pBuf->pImage));
+ pBuf->oldBitmap = (HBITMAP)SelectObject(pBuf->hDC,pBuf->hBitmap);
+ } else if (fClear)
+ memset(pBuf->pImage, 0, width*height*sizeof(DWORD));
+ }
+ pBuf->dwDestroyAfterTime = 0;
+ return pBuf->hDC;
+}
+
+int ske_ReleaseBufferDC(HDC hDC, int keepTime)
+{
+ DWORD dwCurrentTime = GetTickCount();
+
+ //Try to find DC in buffer list - set flag to be release after time;
+ mir_cslock lck(BufferListCS);
+ for (int i=0; i < BufferList.getCount(); i++) {
+ DCBUFFER *pBuf = BufferList[i];
+ if (pBuf) {
+ if (hDC != NULL && pBuf->hDC == hDC) {
+ pBuf->dwDestroyAfterTime = dwCurrentTime+keepTime;
+ break;
+ }
+
+ if ((pBuf->dwDestroyAfterTime && pBuf->dwDestroyAfterTime < dwCurrentTime) || keepTime == -1) {
+ SelectObject(pBuf->hDC,pBuf->oldBitmap);
+ DeleteObject(pBuf->hBitmap);
+ DeleteDC(pBuf->hDC);
+ mir_free(pBuf);
+ BufferList.remove(i);
+ i--;
+ }
+ }
+ }
+ return 0;
+}
+
+BOOL ske_SetRgnOpaque(HDC memdc,HRGN hrgn, BOOL force)
+{
+ RGNDATA * rdata;
+ DWORD rgnsz;
+ DWORD d;
+ RECT *rect;
+ if (g_CluiData.fDisableSkinEngine && !force) return TRUE;
+ rgnsz = GetRegionData(hrgn, 0, NULL);
+ rdata = (RGNDATA *) mir_alloc(rgnsz);
+ GetRegionData(hrgn,rgnsz,rdata);
+ rect = (RECT *)rdata->Buffer;
+ for (d = 0; d < rdata->rdh.nCount; d++)
+ {
+ ske_SetRectOpaque(memdc,&rect[d], force);
+ }
+ mir_free(rdata);
+ return TRUE;
+}
+
+
+BOOL ske_SetRectOpaque(HDC memdc,RECT *fr, BOOL force)
+{
+ int f = 0;
+ BYTE * bits;
+ BITMAP bmp;
+ HBITMAP hbmp;
+
+ if ( g_CluiData.fDisableSkinEngine && !force )
+ return TRUE;
+
+ hbmp = (HBITMAP)GetCurrentObject( memdc,OBJ_BITMAP );
+ GetObject( hbmp, sizeof(bmp), &bmp );
+
+ if ( bmp.bmPlanes != 1 )
+ return FALSE;
+
+ if (!bmp.bmBits)
+ {
+ f = 1;
+ bits = (BYTE*)malloc(bmp.bmWidthBytes*bmp.bmHeight);
+ GetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits);
+ }
+ else
+ bits = (BYTE*)bmp.bmBits;
+
+ int sx = ( fr->left > 0 ) ? fr->left : 0;
+ int sy = ( fr->top > 0 ) ? fr->top : 0;
+ int ex = ( fr->right < bmp.bmWidth ) ? fr->right : bmp.bmWidth;
+ int ey = ( fr->bottom < bmp.bmHeight) ? fr->bottom : bmp.bmHeight;
+
+ int width = ex-sx;
+
+ BYTE* pLine = ((BYTE*)bits) + (bmp.bmHeight-sy-1)*bmp.bmWidthBytes + (sx << 2) + 3;
+ for ( int y = 0; y < (ey - sy); y++ )
+ {
+ BYTE * pColumn = pLine;
+ for ( int x = 0; x < width; x++ )
+ {
+ *pColumn = 255;
+ pColumn += 4;
+ }
+ pLine -= bmp.bmWidthBytes;
+ }
+ if (f)
+ {
+ SetBitmapBits(hbmp,bmp.bmWidthBytes*bmp.bmHeight,bits);
+ free(bits);
+ }
+ // DeleteObject(hbmp);
+ return 1;
+}
+
+static BOOL ske_SkinFillRectByGlyph(HDC hDest, HDC hSource, RECT *rFill, RECT *rGlyph, RECT *rClip, BYTE mode, BYTE drawMode, int depth)
+{
+ int destw = 0, desth = 0;
+ int xstart = 0, xmax = 0;
+ int ystart = 0, ymax = 0;
+ BLENDFUNCTION bfa = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+
+ //initializations
+ if (mode == FM_STRETCH)
+ {
+ HDC mem2dc;
+ HBITMAP mem2bmp, oldbmp;
+ RECT wr;
+ IntersectRect(&wr,rClip,rFill);
+ if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
+ if (drawMode != 2)
+ {
+ mem2dc = CreateCompatibleDC(hDest);
+ mem2bmp = ske_CreateDIB32(wr.right-wr.left,wr.bottom-wr.top);
+ oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
+
+ }
+
+ if (drawMode == 0 || drawMode == 2)
+ {
+ if (drawMode == 0)
+ {
+ ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top,
+ hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
+ ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf);
+ }
+ else
+ {
+ ske_AlphaBlend(hDest,rFill->left,rFill->top,rFill->right-rFill->left,rFill->bottom-rFill->top,
+ hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
+
+ }
+ }
+ else
+ {
+ // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
+ ske_AlphaBlend(mem2dc,rFill->left-wr.left,rFill->top-wr.top,rFill->right-rFill->left,rFill->bottom-rFill->top,
+ hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,rGlyph->bottom-rGlyph->top,bf);
+ ske_AlphaBlend(hDest,wr.left,wr.top,wr.right-wr.left, wr.bottom -wr.top,mem2dc, 0, 0, wr.right-wr.left, wr.bottom -wr.top,bf);
+ }
+ if (drawMode != 2)
+ {
+ SelectObject(mem2dc,oldbmp);
+ DeleteObject(mem2bmp);
+ DeleteDC(mem2dc);
+ }
+ return 1;
+ }
+ else if (mode == FM_TILE_VERT && (rGlyph->bottom-rGlyph->top>0) && (rGlyph->right-rGlyph->left>0))
+ {
+ HDC mem2dc;
+ HBITMAP mem2bmp,oldbmp;
+ RECT wr;
+ IntersectRect(&wr,rClip,rFill);
+ if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
+ mem2dc = CreateCompatibleDC(hDest);
+ //SetStretchBltMode(mem2dc, HALFTONE);
+ mem2bmp = ske_CreateDIB32(wr.right-wr.left, rGlyph->bottom-rGlyph->top);
+ oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
+ if (!oldbmp)
+ return 0;
+
+ /// draw here
+ {
+ int y = 0, sy = 0, maxy = 0;
+ int w = rFill->right-rFill->left;
+ int h = rGlyph->bottom-rGlyph->top;
+ if (h>0 && (wr.bottom-wr.top)*(wr.right-wr.left) != 0)
+ {
+ w = wr.right-wr.left;
+ {
+ // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
+ ske_AlphaBlend(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,bf);
+ //StretchBlt(mem2dc,-(wr.left-rFill->left), 0, rFill->right-rFill->left,h,hSource,rGlyph->left,rGlyph->top,rGlyph->right-rGlyph->left,h,SRCCOPY);
+ }
+ if (drawMode == 0 || drawMode == 2)
+ {
+ if (drawMode == 0 )
+ {
+
+ int dy;
+ dy = (wr.top-rFill->top)%h;
+ if (dy >= 0)
+ {
+ int ht;
+ y = wr.top;
+ ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top);
+ BitBlt(hDest,wr.left,y,w,ht,mem2dc, 0, dy,SRCCOPY);
+ }
+
+ y = wr.top+h-dy;
+ while (y < wr.bottom-h){
+ BitBlt(hDest,wr.left,y,w,h,mem2dc, 0, 0, SRCCOPY);
+ y += h;
+ }
+ if (y <= wr.bottom)
+ BitBlt(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, SRCCOPY);
+
+ }
+ else
+ {
+ y = wr.top;
+ while (y < wr.bottom-h)
+ {
+ // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
+ ske_AlphaBlend(hDest,wr.left,y,w,h, mem2dc, 0, 0, w,h,bf);
+ y += h;
+ }
+ if (y <= wr.bottom)
+ {
+ // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
+ ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf);
+ }
+ }
+
+ }
+ else
+ {
+ int dy;
+
+ BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+
+ dy = (wr.top-rFill->top)%h;
+
+ if (dy >= 0)
+ {
+ int ht;
+ y = wr.top;
+ ht = (y+h-dy <= wr.bottom)?(h-dy):(wr.bottom-wr.top);
+ ske_AlphaBlend(hDest,wr.left,y,w,ht,mem2dc, 0, dy,w,ht,bf);
+ }
+
+ y = wr.top+h-dy;
+ while (y < wr.bottom-h)
+ {
+ ske_AlphaBlend(hDest,wr.left,y,w,h,mem2dc, 0, 0, w,h,bf);
+ y += h;
+ }
+ if (y <= wr.bottom)
+ ske_AlphaBlend(hDest,wr.left,y,w,wr.bottom-y, mem2dc, 0, 0, w,wr.bottom-y,bf);
+ }
+ }
+ }
+ SelectObject(mem2dc,oldbmp);
+ DeleteObject(mem2bmp);
+ DeleteDC(mem2dc);
+ }
+ else if (mode == FM_TILE_HORZ && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0) && (rFill->bottom-rFill->top)>0 && (rFill->right-rFill->left)>0)
+ {
+ HDC mem2dc;
+ RECT wr;
+ HBITMAP mem2bmp,oldbmp;
+ int w = rGlyph->right-rGlyph->left;
+ int h = rFill->bottom-rFill->top;
+ IntersectRect(&wr,rClip,rFill);
+ if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
+ h = wr.bottom-wr.top;
+ mem2dc = CreateCompatibleDC(hDest);
+
+ mem2bmp = ske_CreateDIB32(w,h);
+ oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
+
+ if (!oldbmp)
+ return 0;
+ /// draw here
+ {
+ int x = 0, sy = 0, maxy = 0;
+ {
+ //SetStretchBltMode(mem2dc, HALFTONE);
+ //StretchBlt(mem2dc, 0, 0, w,h,hSource,rGlyph->left+(wr.left-rFill->left),rGlyph->top,w,h,SRCCOPY);
+
+ // BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, 0 };
+ ske_AlphaBlend(mem2dc, 0, -(wr.top-rFill->top),w,rFill->bottom-rFill->top,hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf);
+ if (drawMode == 0 || drawMode == 2)
+ {
+ if (drawMode == 0)
+ {
+
+ int dx;
+ dx = (wr.left-rFill->left)%w;
+ if (dx >= 0)
+ {
+ int wt;
+ x = wr.left;
+ wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
+ BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY);
+ }
+ x = wr.left+w-dx;
+ while (x < wr.right-w){
+ BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY);
+ x += w;
+ }
+ if (x <= wr.right)
+ BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY);
+ }
+ else
+ {
+ int dx;
+ dx = (wr.left-rFill->left)%w;
+ x = wr.left-dx;
+ while (x < wr.right-w){
+ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
+ x += w;
+ }
+ if (x <= wr.right)
+ ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
+ }
+
+ }
+ else
+ {
+ BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ int dx;
+ dx = (wr.left-rFill->left)%w;
+ if (dx >= 0)
+ {
+ int wt;
+ x = wr.left;
+ wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
+ ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf);
+ }
+ x = wr.left+w-dx;
+ while (x < wr.right-w){
+ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
+ x += w;
+ }
+ if (x <= wr.right)
+ ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
+
+ }
+ }
+ }
+ SelectObject(mem2dc,oldbmp);
+ DeleteObject(mem2bmp);
+ DeleteDC(mem2dc);
+ }
+ else if (mode == FM_TILE_BOTH && (rGlyph->right-rGlyph->left>0) && (rGlyph->bottom-rGlyph->top>0))
+ {
+ HDC mem2dc;
+ int w = rGlyph->right-rGlyph->left;
+ int x = 0, sy = 0, maxy = 0;
+ int h = rFill->bottom-rFill->top;
+ HBITMAP mem2bmp,oldbmp;
+ RECT wr;
+ IntersectRect(&wr,rClip,rFill);
+ if ((wr.bottom-wr.top)*(wr.right-wr.left) == 0) return 0;
+ mem2dc = CreateCompatibleDC(hDest);
+ mem2bmp = ske_CreateDIB32(w,wr.bottom-wr.top);
+ h = wr.bottom-wr.top;
+ oldbmp = (HBITMAP)SelectObject(mem2dc,mem2bmp);
+#ifdef _DEBUG
+ if (!oldbmp)
+ (NULL,"Tile bitmap not selected","ERROR", MB_OK);
+#endif
+ /// draw here
+ {
+
+ //fill temp bitmap
+ {
+ int y;
+ int dy;
+ dy = (wr.top-rFill->top)%(rGlyph->bottom-rGlyph->top);
+ y = -dy;
+ while (y < wr.bottom-wr.top)
+ {
+
+ ske_AlphaBlend(mem2dc, 0, y,w,rGlyph->bottom-rGlyph->top, hSource,rGlyph->left,rGlyph->top,w,rGlyph->bottom-rGlyph->top,bf);
+ y += rGlyph->bottom-rGlyph->top;
+ }
+
+ //--
+ //end temp bitmap
+ if (drawMode == 0 || drawMode == 2)
+ {
+ if (drawMode == 0)
+ {
+
+ int dx;
+ dx = (wr.left-rFill->left)%w;
+ if (dx >= 0)
+ {
+ int wt;
+ x = wr.left;
+ wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
+ BitBlt(hDest,x,wr.top,wt,h,mem2dc,dx, 0, SRCCOPY);
+ }
+ x = wr.left+w-dx;
+ while (x < wr.right-w){
+ BitBlt(hDest,x,wr.top,w,h,mem2dc, 0, 0, SRCCOPY);
+ x += w;
+ }
+ if (x <= wr.right)
+ BitBlt(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, SRCCOPY);
+ }
+ else
+ {
+ int dx;
+ dx = (wr.left-rFill->left)%w;
+ x = wr.left-dx;
+ while (x < wr.right-w){
+ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
+ x += w;
+ }
+ if (x <= wr.right)
+ ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
+ }
+
+ }
+ else
+ {
+ BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+
+ int dx;
+ dx = (wr.left-rFill->left)%w;
+ if (dx >= 0)
+ {
+ int wt;
+ x = wr.left;
+ wt = (x+w-dx <= wr.right)?(w-dx):(wr.right-wr.left);
+ ske_AlphaBlend(hDest,x,wr.top,wt,h,mem2dc,dx, 0, wt,h,bf);
+ }
+ x = wr.left+w-dx;
+ while (x < wr.right-w){
+ ske_AlphaBlend(hDest,x,wr.top,w,h,mem2dc, 0, 0, w,h,bf);
+ x += w;
+ }
+ if (x <= wr.right)
+ ske_AlphaBlend(hDest,x,wr.top,wr.right-x,h, mem2dc, 0, 0, wr.right-x,h,bf);
+
+ }
+ }
+
+ }
+ SelectObject(mem2dc,oldbmp);
+ DeleteObject(mem2bmp);
+ DeleteDC(mem2dc);
+ }
+ return 1;
+
+}
+
+HBITMAP ske_CreateDIB32(int cx, int cy)
+{
+ return ske_CreateDIB32Point(cx,cy,NULL);
+}
+
+HBITMAP ske_CreateDIB32Point(int cx, int cy, void ** bits)
+{
+ if (cx < 0 || cy < 0)
+ return NULL;
+
+ BITMAPINFO RGB32BitsBITMAPINFO = { 0 };
+ RGB32BitsBITMAPINFO.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ RGB32BitsBITMAPINFO.bmiHeader.biWidth = cx;//bm.bmWidth;
+ RGB32BitsBITMAPINFO.bmiHeader.biHeight = cy;//bm.bmHeight;
+ RGB32BitsBITMAPINFO.bmiHeader.biPlanes = 1;
+ RGB32BitsBITMAPINFO.bmiHeader.biBitCount = 32;
+ // pointer used for direct Bitmap pixels access
+
+ UINT *ptPixels;
+ HBITMAP DirectBitmap = CreateDIBSection(NULL,
+ (BITMAPINFO *)&RGB32BitsBITMAPINFO,
+ DIB_RGB_COLORS,
+ (void **)&ptPixels,
+ NULL, 0);
+ if ((DirectBitmap == NULL || ptPixels == NULL) && cx != 0 && cy != 0)
+ {
+#ifdef _DEBUG
+ MessageBoxA(NULL,"Object not allocated. Check GDI object count","ERROR",MB_OK|MB_ICONERROR);
+ DebugBreak();
+#endif
+ ;
+ }
+ else memset(ptPixels, 0, cx*cy*4);
+ if (bits != NULL) *bits = ptPixels;
+ return DirectBitmap;
+}
+
+HRGN ske_CreateOpaqueRgn(BYTE Level, bool Opaque)
+{
+ if (!g_pCachedWindow)
+ return NULL;
+
+ RGBQUAD *buf = (RGBQUAD *) g_pCachedWindow->hImageDIBByte;
+ if (buf == NULL)
+ return NULL;
+
+ unsigned int cRect = 64;
+ PRGNDATA pRgnData = (PRGNDATA)malloc(sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
+ memset(pRgnData, 0, sizeof(RGNDATAHEADER));
+ pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
+ pRgnData->rdh.iType = RDH_RECTANGLES;
+
+ for (int y = 0; y < g_pCachedWindow->Height; ++y) {
+ bool inside = false;
+ bool lastin = false;
+ unsigned int entry = 0;
+
+ for (int x = 0; x < g_pCachedWindow->Width; ++x) {
+ inside = Opaque ? (buf->rgbReserved > Level) : (buf->rgbReserved < Level);
+ ++buf;
+
+ if (inside != lastin) {
+ if (inside) {
+ lastin = true;
+ entry = x;
+ }
+ else {
+ if (pRgnData->rdh.nCount == cRect) {
+ cRect = cRect + 64;
+ pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
+ }
+ SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, x, g_pCachedWindow->Height - y + 1);
+
+ pRgnData->rdh.nCount++;
+ lastin = false;
+ }
+ }
+ }
+
+ if (lastin) {
+ if (pRgnData->rdh.nCount == cRect) {
+ cRect = cRect + 64;
+ pRgnData = (PRGNDATA)realloc(pRgnData, sizeof(RGNDATAHEADER) + (cRect)*sizeof(RECT));
+ }
+ SetRect(((LPRECT)pRgnData->Buffer) + pRgnData->rdh.nCount, entry, g_pCachedWindow->Height - y, g_pCachedWindow->Width, g_pCachedWindow->Height - y + 1);
+
+ pRgnData->rdh.nCount++;
+ }
+ }
+
+ HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData);
+ free(pRgnData);
+ return hRgn;
+}
+
+static int ske_DrawSkinObject(SKINDRAWREQUEST * preq, GLYPHOBJECT * pobj)
+{
+ HDC memdc = NULL, glyphdc = NULL;
+ int k = 0;
+ //BITMAP bmp = {0};
+ HBITMAP membmp = 0, oldbmp = 0, oldglyph = 0;
+ BYTE Is32Bit = 0;
+ RECT PRect;
+ POINT mode2offset = {0};
+ int depth = 0;
+ int mode = 0; //0-FastDraw, 1-DirectAlphaDraw, 2-BufferedAlphaDraw
+
+ if (!(preq && pobj)) return -1;
+ if ((!pobj->hGlyph || pobj->hGlyph == (HBITMAP)-1) && ((pobj->Style&7) == ST_IMAGE || (pobj->Style&7) == ST_FRAGMENT || (pobj->Style&7) == ST_SOLARIZE)) return 0;
+ // Determine painting mode
+ depth = GetDeviceCaps(preq->hDC,BITSPIXEL);
+ depth = depth < 16?16:depth;
+ Is32Bit = pobj->bmBitsPixel == 32;
+ if ((!Is32Bit && pobj->dwAlpha == 255) && pobj->Style != ST_BRUSH) mode = 0;
+ else if (pobj->dwAlpha == 255 && pobj->Style != ST_BRUSH) mode = 1;
+ else mode = 2;
+ // End painting mode
+
+ //force mode
+
+ if (preq->rcClipRect.bottom-preq->rcClipRect.top*preq->rcClipRect.right-preq->rcClipRect.left == 0)
+ preq->rcClipRect = preq->rcDestRect;
+ IntersectRect(&PRect,&preq->rcDestRect,&preq->rcClipRect);
+ if (IsRectEmpty(&PRect))
+ {
+ return 0;
+ }
+ if (mode == 2)
+ {
+ memdc = CreateCompatibleDC(preq->hDC);
+ membmp = ske_CreateDIB32(PRect.right-PRect.left,PRect.bottom-PRect.top);
+ oldbmp = (HBITMAP)SelectObject(memdc,membmp);
+ if (oldbmp == NULL)
+ {
+ if (mode == 2)
+ {
+ SelectObject(memdc,oldbmp);
+ DeleteDC(memdc);
+ DeleteObject(membmp);
+ }
+ return 0;
+ }
+ }
+
+ if (mode != 2) memdc = preq->hDC;
+ {
+ if (pobj->hGlyph && pobj->hGlyph != (HBITMAP)-1)
+ {
+ glyphdc = CreateCompatibleDC(preq->hDC);
+ if (!oldglyph)
+ oldglyph = (HBITMAP)SelectObject(glyphdc,pobj->hGlyph);
+ else
+ SelectObject(glyphdc,pobj->hGlyph);
+ }
+ // Drawing
+ {
+ RECT rFill, rGlyph, rClip;
+ if ((pobj->Style&7) == ST_BRUSH)
+ {
+ HBRUSH br = CreateSolidBrush(pobj->dwColor);
+ RECT fr;
+ if (mode == 2)
+ {
+ SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top);
+ FillRect(memdc,&fr,br);
+ ske_SetRectOpaque(memdc,&fr);
+ // FillRectAlpha(memdc,&fr,pobj->dwColor|0xFF000000);
+ }
+ else
+ {
+ fr = PRect;
+ // SetRect(&fr, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top);
+ FillRect(preq->hDC,&fr,br);
+ }
+ DeleteObject(br);
+ k = -1;
+ }
+ else
+ {
+ if (mode == 2)
+ {
+ mode2offset.x = PRect.left;
+ mode2offset.y = PRect.top;
+ OffsetRect(&PRect,-mode2offset.x,-mode2offset.y);
+ }
+ rClip = (preq->rcClipRect);
+
+ {
+ int lft = 0;
+ int top = 0;
+ int rgh = pobj->bmWidth;
+ int btm = pobj->bmHeight;
+ if ((pobj->Style&7) == ST_FRAGMENT)
+ {
+ lft = pobj->clipArea.x;
+ top = pobj->clipArea.y;
+ rgh = min(rgh,lft+pobj->szclipArea.cx);
+ btm = min(btm,top+pobj->szclipArea.cy);
+ }
+
+ // Draw center...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.top+pobj->dwTop;
+ rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
+ rFill.left = preq->rcDestRect.left+pobj->dwLeft;
+ rFill.right = preq->rcDestRect.right-pobj->dwRight;
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+ rGlyph.top = top+pobj->dwTop;
+ rGlyph.left = lft+pobj->dwLeft;
+ rGlyph.right = rgh-pobj->dwRight;
+ rGlyph.bottom = btm-pobj->dwBottom;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode,mode,depth);
+ }
+
+ // Draw top side...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.top;
+ rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
+ rFill.left = preq->rcDestRect.left+pobj->dwLeft;
+ rFill.right = preq->rcDestRect.right-pobj->dwRight;
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+ rGlyph.top = top+0;
+ rGlyph.left = lft+pobj->dwLeft;
+ rGlyph.right = rgh-pobj->dwRight;
+ rGlyph.bottom = top+pobj->dwTop;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth);
+ }
+ // Draw bottom side...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
+ rFill.bottom = preq->rcDestRect.bottom;
+ rFill.left = preq->rcDestRect.left+pobj->dwLeft;
+ rFill.right = preq->rcDestRect.right-pobj->dwRight;
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+
+ rGlyph.top = btm-pobj->dwBottom;
+ rGlyph.left = lft+pobj->dwLeft;
+ rGlyph.right = rgh-pobj->dwRight;
+ rGlyph.bottom = btm;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_HORZ,mode,depth);
+ }
+ // Draw left side...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.top+pobj->dwTop;
+ rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
+ rFill.left = preq->rcDestRect.left;
+ rFill.right = preq->rcDestRect.left+pobj->dwLeft;
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+
+ rGlyph.top = top+pobj->dwTop;
+ rGlyph.left = lft;
+ rGlyph.right = lft+pobj->dwLeft;
+ rGlyph.bottom = btm-pobj->dwBottom;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth);
+ }
+
+ // Draw right side...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.top+pobj->dwTop;
+ rFill.bottom = preq->rcDestRect.bottom-pobj->dwBottom;
+ rFill.left = preq->rcDestRect.right-pobj->dwRight;
+ rFill.right = preq->rcDestRect.right;
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+
+ rGlyph.top = top+pobj->dwTop;
+ rGlyph.left = rgh-pobj->dwRight;
+ rGlyph.right = rgh;
+ rGlyph.bottom = btm-pobj->dwBottom;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect,pobj->FitMode&FM_TILE_VERT,mode,depth);
+ }
+
+
+ // Draw Top-Left corner...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.top;
+ rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
+ rFill.left = preq->rcDestRect.left;
+ rFill.right = preq->rcDestRect.left+pobj->dwLeft;
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+
+ rGlyph.top = top;
+ rGlyph.left = lft;
+ rGlyph.right = lft+pobj->dwLeft;
+ rGlyph.bottom = top+pobj->dwTop;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
+ }
+ // Draw Top-Right corner...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.top;
+ rFill.bottom = preq->rcDestRect.top+pobj->dwTop;
+ rFill.left = preq->rcDestRect.right-pobj->dwRight;
+ rFill.right = preq->rcDestRect.right;
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+
+ rGlyph.top = top;
+ rGlyph.left = rgh-pobj->dwRight;
+ rGlyph.right = rgh;
+ rGlyph.bottom = top+pobj->dwTop;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
+ }
+
+ // Draw Bottom-Left corner...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
+ rFill.bottom = preq->rcDestRect.bottom;
+ rFill.left = preq->rcDestRect.left;
+ rFill.right = preq->rcDestRect.left+pobj->dwLeft;
+
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+
+ rGlyph.left = lft;
+ rGlyph.right = lft+pobj->dwLeft;
+ rGlyph.top = btm-pobj->dwBottom;
+ rGlyph.bottom = btm;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
+ }
+ // Draw Bottom-Right corner...
+ if (1)
+ {
+ rFill.top = preq->rcDestRect.bottom-pobj->dwBottom;
+ rFill.bottom = preq->rcDestRect.bottom;
+ rFill.left = preq->rcDestRect.right-pobj->dwRight;
+ rFill.right = preq->rcDestRect.right;
+
+
+ if (mode == 2)
+ OffsetRect(&rFill,-mode2offset.x,-mode2offset.y);
+
+ rGlyph.left = rgh-pobj->dwRight;
+ rGlyph.right = rgh;
+ rGlyph.top = btm-pobj->dwBottom;
+ rGlyph.bottom = btm;
+
+ k += ske_SkinFillRectByGlyph(memdc,glyphdc,&rFill,&rGlyph,&PRect, 0, mode,depth);
+ }
+ }
+
+ }
+
+ if ((k>0 || k == -1) && mode == 2)
+ {
+ {
+ BLENDFUNCTION bf = {AC_SRC_OVER, 0, /*(bm.bmBitsPixel == 32)?255:*/pobj->dwAlpha, (pobj->bmBitsPixel == 32 && pobj->Style != ST_BRUSH)?AC_SRC_ALPHA:0};
+ if (mode == 2)
+ OffsetRect(&PRect,mode2offset.x,mode2offset.y);
+ ske_AlphaBlend( preq->hDC,PRect.left,PRect.top,PRect.right-PRect.left,PRect.bottom-PRect.top,
+ memdc, 0, 0, PRect.right-PRect.left,PRect.bottom-PRect.top,bf);
+ }
+ }
+ }
+ //free GDI resources
+ //--++--
+
+ //free GDI resources
+ {
+
+ if (oldglyph) SelectObject(glyphdc,oldglyph);
+ if (glyphdc) DeleteDC(glyphdc);
+ }
+ if (mode == 2)
+ {
+ SelectObject(memdc,oldbmp);
+ DeleteDC(memdc);
+ DeleteObject(membmp);
+ }
+
+ }
+ if (pobj->plTextList && pobj->plTextList->realCount>0)
+ {
+ int i;
+ HFONT hOldFont;
+ for (i=0; i < pobj->plTextList->realCount; i++)
+ {
+ GLYPHTEXT * gt = (GLYPHTEXT *)pobj->plTextList->items[i];
+ if (!gt->hFont)
+ {
+ if (gl_plSkinFonts && gl_plSkinFonts->realCount>0)
+ {
+ int j = 0;
+ for (j = 0; j < gl_plSkinFonts->realCount; j++)
+ {
+ SKINFONT * sf;
+ sf = (SKINFONT*)gl_plSkinFonts->items[j];
+ if (sf->szFontID && !strcmp(sf->szFontID,gt->szFontID))
+ {
+ gt->hFont = sf->hFont;
+ break;
+ }
+ }
+ }
+ if (!gt->hFont) gt->hFont = (HFONT)-1;
+ }
+ if (gt->hFont != (HFONT)-1)
+ {
+ RECT rc = {0};
+ hOldFont = (HFONT)SelectObject(preq->hDC,gt->hFont);
+
+
+
+ if (gt->RelativeFlags&2) rc.left = preq->rcDestRect.right+gt->iLeft;
+ else if (gt->RelativeFlags&1) rc.left = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iLeft;
+ else rc.left = preq->rcDestRect.left+gt->iLeft;
+
+ if (gt->RelativeFlags&8) rc.top = preq->rcDestRect.bottom+gt->iTop;
+ else if (gt->RelativeFlags&4) rc.top = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iTop;
+ else rc.top = preq->rcDestRect.top+gt->iTop;
+
+ if (gt->RelativeFlags&32) rc.right = preq->rcDestRect.right+gt->iRight;
+ else if (gt->RelativeFlags&16) rc.right = ((preq->rcDestRect.right-preq->rcDestRect.left)>>1)+gt->iRight;
+ else rc.right = preq->rcDestRect.left+gt->iRight;
+
+ if (gt->RelativeFlags&128) rc.bottom = preq->rcDestRect.bottom+gt->iBottom;
+ else if (gt->RelativeFlags&64) rc.bottom = ((preq->rcDestRect.bottom-preq->rcDestRect.top)>>1)+gt->iBottom;
+ else rc.bottom = preq->rcDestRect.top+gt->iBottom;
+
+ ske_AlphaTextOut(preq->hDC, gt->stText, -1, &rc,gt->dwFlags, gt->dwColor);
+ SelectObject(preq->hDC,hOldFont);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+int ske_AddDescriptorToSkinObjectList (LPSKINOBJECTDESCRIPTOR lpDescr, SKINOBJECTSLIST* Skin)
+{
+ SKINOBJECTSLIST *sk;
+ if (Skin) sk = Skin; else sk = &g_SkinObjectList;
+ if (!sk) return 0;
+ if (mir_bool_strcmpi(lpDescr->szObjectID,"_HEADER_")) return 0;
+ {//check if new object allready presents.
+ DWORD i=0;
+ for (i=0; i < sk->dwObjLPAlocated; i++)
+ if (!mir_strcmp(sk->pObjects[i].szObjectID,lpDescr->szObjectID)) return 0;
+ }
+ if (sk->dwObjLPAlocated+1>sk->dwObjLPReserved)
+ { // Realocated list to add space for new object
+
+ sk->pObjects = (SKINOBJECTDESCRIPTOR*)mir_realloc(sk->pObjects,sizeof(SKINOBJECTDESCRIPTOR)*(sk->dwObjLPReserved+1)/*alloc step*/);
+ sk->dwObjLPReserved++;
+ }
+ { //filling new objects field
+ sk->pObjects[sk->dwObjLPAlocated].bType = lpDescr->bType;
+ sk->pObjects[sk->dwObjLPAlocated].Data = NULL;
+ sk->pObjects[sk->dwObjLPAlocated].szObjectID = mir_strdup(lpDescr->szObjectID);
+ // sk->Objects[sk->dwObjLPAlocated].szObjectName = mir_strdup(lpDescr->szObjectName);
+ if (lpDescr->Data != NULL)
+ { //Copy defaults values
+ switch (lpDescr->bType)
+ {
+ case OT_GLYPHOBJECT:
+ {
+ GLYPHOBJECT * obdat;
+ GLYPHOBJECT * gl = (GLYPHOBJECT*)lpDescr->Data;
+ sk->pObjects[sk->dwObjLPAlocated].Data = mir_alloc(sizeof(GLYPHOBJECT));
+ obdat = (GLYPHOBJECT*)sk->pObjects[sk->dwObjLPAlocated].Data;
+ memcpy(obdat,gl,sizeof(GLYPHOBJECT));
+ if (gl->szFileName != NULL)
+ {
+ obdat->szFileName = mir_strdup(gl->szFileName);
+ mir_free_and_nil(gl->szFileName);
+ }
+ else obdat->szFileName = NULL;
+
+ obdat->hGlyph = NULL;
+ break;
+ }
+ }
+
+ }
+ }
+ sk->dwObjLPAlocated++;
+ return 1;
+}
+
+static LPSKINOBJECTDESCRIPTOR ske_FindObject(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin)
+{
+ // DWORD i;
+ SKINOBJECTSLIST* sk;
+ sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
+ return skin_FindObjectByRequest((char *)szName,sk->pMaskList);
+}
+
+static LPSKINOBJECTDESCRIPTOR ske_FindObjectByMask(MODERNMASK *pModernMask, BYTE objType, SKINOBJECTSLIST* Skin)
+{
+ // DWORD i;
+ SKINOBJECTSLIST* sk;
+ sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
+ if (!sk->pMaskList) return NULL;
+ return skin_FindObjectByMask(pModernMask,sk->pMaskList);
+}
+
+LPSKINOBJECTDESCRIPTOR ske_FindObjectByName(const char * szName, BYTE objType, SKINOBJECTSLIST* Skin)
+{
+ DWORD i;
+ SKINOBJECTSLIST* sk;
+ sk = (Skin == NULL)?(&g_SkinObjectList):Skin;
+ for (i=0; i < sk->dwObjLPAlocated; i++)
+ {
+ if (sk->pObjects[i].bType == objType || objType == OT_ANY)
+ {
+ if (!mir_strcmp(sk->pObjects[i].szObjectID,szName))
+ return &(sk->pObjects[i]);
+ }
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Paint glyph
+// wParam - LPSKINDRAWREQUEST
+// lParam - possible direct pointer to modern mask
+//////////////////////////////////////////////////////////////////////////
+
+INT_PTR ske_Service_DrawGlyph(WPARAM wParam, LPARAM lParam)
+{
+ LPSKINDRAWREQUEST preq;
+ LPSKINOBJECTDESCRIPTOR pgl;
+ LPGLYPHOBJECT gl;
+ if (!wParam) return -1;
+ ske_LockSkin();
+ __try
+ {
+ preq = (LPSKINDRAWREQUEST)wParam;
+ if (lParam)
+ pgl = ske_FindObjectByMask((MODERNMASK*)lParam, OT_GLYPHOBJECT,NULL);
+ else
+ pgl = ske_FindObject(preq->szObjectID, OT_GLYPHOBJECT,NULL);
+ if (pgl == NULL) return -1;
+ if (pgl->Data == NULL) return -1;
+
+ gl = (LPGLYPHOBJECT)pgl->Data;
+ int iStyle = gl->Style & 7;
+ if (iStyle == ST_SKIP)
+ return ST_SKIP;
+
+ if (gl->hGlyph == NULL && gl->hGlyph != (HBITMAP)-1 && (iStyle == ST_IMAGE || iStyle == ST_FRAGMENT || iStyle == ST_SOLARIZE))
+ if (gl->szFileName) {
+ gl->hGlyph = ske_LoadGlyphImage( _A2T(gl->szFileName));
+ if (gl->hGlyph) {
+ BITMAP bmp = {0};
+ GetObject(gl->hGlyph,sizeof(BITMAP),&bmp);
+ gl->bmBitsPixel = (BYTE)bmp.bmBitsPixel;
+ gl->bmHeight = bmp.bmHeight;
+ gl->bmWidth = bmp.bmWidth;
+ }
+ else gl->hGlyph = (HBITMAP)-1; //invalid
+ }
+ return ske_DrawSkinObject(preq,gl);
+ }
+ __finally
+ {
+ ske_UnlockSkin();
+ }
+ return -1;
+}
+
+
+void ske_PreMultiplyChanells(HBITMAP hbmp,BYTE Mult)
+{
+ BITMAP bmp;
+ BOOL flag = FALSE;
+ BYTE * pBitmapBits;
+ DWORD Len;
+ int bh,bw,y,x;
+
+ GetObject(hbmp, sizeof(BITMAP), (LPSTR)&bmp);
+ bh = bmp.bmHeight;
+ bw = bmp.bmWidth;
+ Len = bh*bw*4;
+ flag = (bmp.bmBits == NULL);
+ if (flag)
+ {
+ pBitmapBits = (LPBYTE)malloc(Len);
+ GetBitmapBits(hbmp,Len,pBitmapBits);
+ }
+ else
+ pBitmapBits = (BYTE*)bmp.bmBits;
+ for (y = 0; y < bh; ++y)
+ {
+ BYTE *pPixel = pBitmapBits + bw * 4 * y;
+
+ for (x = 0; x < bw ; ++x)
+ {
+ if (Mult)
+ {
+ pPixel[0] = pPixel[0]*pPixel[3]/255;
+ pPixel[1] = pPixel[1]*pPixel[3]/255;
+ pPixel[2] = pPixel[2]*pPixel[3]/255;
+ }
+ else
+ {
+ pPixel[3] = 255;
+ }
+ pPixel += 4;
+ }
+ }
+ if (flag)
+ {
+ Len = SetBitmapBits(hbmp,Len,pBitmapBits);
+ free (pBitmapBits);
+ }
+ return;
+}
+
+int ske_GetFullFilename(TCHAR *buf, const TCHAR *file, TCHAR *skinfolder, BOOL madeAbsolute)
+{
+ TCHAR *SkinPlace = db_get_tsa(NULL,SKIN,"SkinFolder");
+ if (SkinPlace == NULL)
+ SkinPlace = mir_tstrdup( _T("\\Skin\\default"));
+
+ TCHAR b2[MAX_PATH];
+ if (file[0] != '\\' && file[1] != ':')
+ mir_sntprintf(b2, MAX_PATH, _T("%s\\%s"), (skinfolder == NULL) ? SkinPlace : ((INT_PTR)skinfolder != -1) ? skinfolder : _T(""), file);
+ else
+ _tcsncpy(b2, file, SIZEOF(b2));
+
+ if (madeAbsolute) {
+ if (b2[0] == '\\' && b2[1] != '\\')
+ PathToAbsoluteT(b2+1, buf);
+ else
+ PathToAbsoluteT(b2, buf);
+ }
+ else _tcsncpy(buf, b2, MAX_PATH);
+
+ mir_free(SkinPlace);
+ return 0;
+}
+
+/*
+This function is required to load TGA to dib buffer myself
+Major part of routines is from http://tfcduke.developpez.com/tutoriel/format/tga/fichiers/tga.c
+*/
+
+static BOOL ske_ReadTGAImageData(void * From, DWORD fromSize, BYTE * destBuf, DWORD bufSize, BOOL RLE)
+{
+ BYTE * pos = destBuf;
+ BYTE * from = fromSize?(BYTE*)From:NULL;
+ FILE * fp = !fromSize?(FILE*)From:NULL;
+ DWORD destCount = 0;
+ DWORD fromCount = 0;
+ if (!RLE)
+ {
+ while (((from && fromCount < fromSize) || (fp && fromCount < bufSize))
+ && (destCount < bufSize))
+ {
+ BYTE r = from?from[fromCount++]:(BYTE)fgetc(fp);
+ BYTE g = from?from[fromCount++]:(BYTE)fgetc(fp);
+ BYTE b = from?from[fromCount++]:(BYTE)fgetc(fp);
+ BYTE a = from?from[fromCount++]:(BYTE)fgetc(fp);
+ pos[destCount++] = r;
+ pos[destCount++] = g;
+ pos[destCount++] = b;
+ pos[destCount++] = a;
+
+ if (destCount>bufSize) break;
+ if (from) if (fromCount < fromSize) break;
+ }
+ }
+ else
+ {
+ BYTE rgba[4];
+ BYTE packet_header;
+ BYTE *ptr = pos;
+ BYTE size;
+ int i;
+ while (ptr < pos + bufSize)
+ {
+ /* read first byte */
+ packet_header = from?from[fromCount]:(BYTE)fgetc(fp);
+ if (from) from++;
+ size = 1 + (packet_header & 0x7f);
+ if (packet_header & 0x80)
+ {
+ /* run-length packet */
+ if (from)
+ {
+ *((DWORD*)rgba) = *((DWORD*)(from+fromCount));
+ fromCount += 4;
+ }
+ else fread (rgba, sizeof (BYTE), 4, fp);
+ for (i=0; i < size; ++i, ptr += 4)
+ {
+ ptr[2] = rgba[2];
+ ptr[1] = rgba[1];
+ ptr[0] = rgba[0];
+ ptr[3] = rgba[3];
+ }
+ }
+ else
+ { /* not run-length packet */
+ for (i=0; i < size; ++i, ptr += 4)
+ {
+ ptr[0] = from? from[fromCount++]:(BYTE)fgetc (fp);
+ ptr[1] = from? from[fromCount++]:(BYTE)fgetc (fp);
+ ptr[2] = from? from[fromCount++]:(BYTE)fgetc (fp);
+ ptr[3] = from? from[fromCount++]:(BYTE)fgetc (fp);
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+static HBITMAP ske_LoadGlyphImage_TGA(const TCHAR *szFilename)
+{
+ BYTE *colormap = NULL;
+ int cx = 0, cy = 0;
+ BOOL err = FALSE;
+ tga_header_t header;
+ if (!szFilename) return NULL;
+ if (!wildcmpit(szFilename, _T("*\\*%.tga"))) {
+ //Loading TGA image from file
+ FILE *fp = _tfopen (szFilename, _T("rb"));
+ if (!fp) {
+ TRACEVAR("error: couldn't open \"%s\"!\n", szFilename);
+ return NULL;
+ }
+ /* read header */
+ fread (&header, sizeof (tga_header_t), 1, fp);
+ if ((header.pixel_depth != 32) || ((header.image_type != 10) && (header.image_type != 2))) {
+ fclose(fp);
+ return NULL;
+ }
+
+ /*memory allocation */
+ colormap = (BYTE*)malloc(header.width*header.height*4);
+ cx = header.width;
+ cy = header.height;
+ fseek (fp, header.id_lenght, SEEK_CUR);
+ fseek (fp, header.cm_length, SEEK_CUR);
+ err = !ske_ReadTGAImageData((void*)fp, 0, colormap, header.width*header.height*4,header.image_type == 10);
+ fclose(fp);
+ }
+ else {
+ /* reading from resources IDR_TGA_DEFAULT_SKIN */
+ DWORD size = 0;
+ BYTE * mem;
+ HGLOBAL hRes;
+ HRSRC hRSrc = FindResourceA(g_hInst,MAKEINTRESOURCEA(IDR_TGA_DEFAULT_SKIN),"TGA");
+ if (!hRSrc) return NULL;
+ hRes = LoadResource(g_hInst,hRSrc);
+ if (!hRes) return NULL;
+ size = SizeofResource(g_hInst,hRSrc);
+ mem = (BYTE*) LockResource(hRes);
+ if (size>sizeof(header))
+ {
+ tga_header_t * header = (tga_header_t *)mem;
+ if (header->pixel_depth == 32 && (header->image_type == 2 || header->image_type == 10))
+ {
+ colormap = (BYTE*)malloc(header->width*header->height*4);
+ cx = header->width;
+ cy = header->height;
+ ske_ReadTGAImageData((void*)(mem+sizeof(tga_header_t)+header->id_lenght+header->cm_length), size-(sizeof(tga_header_t)+header->id_lenght+header->cm_length), colormap, cx*cy*4,header->image_type == 10);
+ }
+ }
+ FreeResource(hRes);
+ }
+
+ if (colormap) { //create dib section
+ BYTE * pt;
+ HBITMAP hbmp = ske_CreateDIB32Point(cx,cy,(void**)&pt);
+ if (hbmp)
+ memcpy(pt,colormap,cx*cy*4);
+ free(colormap);
+ return hbmp;
+ }
+ return NULL;
+}
+
+
+//this function is required to load PNG to dib buffer myself
+static HBITMAP ske_LoadGlyphImage_Png2Dib(const TCHAR *tszFilename)
+{
+ HANDLE hFile, hMap = NULL;
+ BYTE* ppMap = NULL;
+ long cbFileSize = 0;
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+
+ if (!ServiceExists( MS_PNG2DIB )) {
+ MessageBox( NULL, TranslateT("You need an image services plugin to process PNG images."), TranslateT("Error"), MB_OK );
+ return (HBITMAP)NULL;
+ }
+
+ if ((hFile = CreateFile(tszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
+ if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL)
+ if ((ppMap = ( BYTE* )MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL)
+ cbFileSize = GetFileSize(hFile, NULL);
+
+ if (cbFileSize != 0) {
+ PNG2DIB param;
+ param.pSource = ppMap;
+ param.cbSourceSize = cbFileSize;
+ param.pResult = &pDib;
+ if ( CallService(MS_PNG2DIB, 0, (LPARAM)&param ))
+ 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;
+}