summaryrefslogtreecommitdiff
path: root/plugins/Clist_modern
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2023-01-02 21:10:29 +0300
committerdartraiden <wowemuh@gmail.com>2023-01-02 21:10:29 +0300
commit1979fd80424d16b2e489f9b57d01d9c7811d25a2 (patch)
tree960d42c5fe4a51f0fe2850bea91256e226bce221 /plugins/Clist_modern
parentadfbbb217d4f4a05acf198755f219a5223d31c27 (diff)
Update copyrights
Diffstat (limited to 'plugins/Clist_modern')
-rw-r--r--plugins/Clist_modern/src/cluiframes.cpp2
-rw-r--r--plugins/Clist_modern/src/groupmenu.cpp2
-rw-r--r--plugins/Clist_modern/src/init.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_aniavatars.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_awaymsg.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_awaymsg.h2
-rw-r--r--plugins/Clist_modern/src/modern_cache_funcs.h2
-rw-r--r--plugins/Clist_modern/src/modern_cachefuncs.cpp1490
-rw-r--r--plugins/Clist_modern/src/modern_clc.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clc.h2
-rw-r--r--plugins/Clist_modern/src/modern_clcidents.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clcitems.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clcmsgs.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clcopts.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clcpaint.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clcutils.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clist.h2
-rw-r--r--plugins/Clist_modern/src/modern_clistevents.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clistmenus.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clistmod.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clistopts.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clistsettings.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clisttray.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clui.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_clui.h2
-rw-r--r--plugins/Clist_modern/src/modern_cluiservices.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_contact.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_defsettings.h2
-rw-r--r--plugins/Clist_modern/src/modern_docking.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_global.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_image_array.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_image_array.h2
-rw-r--r--plugins/Clist_modern/src/modern_keyboard.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_rowheight_funcs.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_rowheight_funcs.h2
-rw-r--r--plugins/Clist_modern/src/modern_skinbutton.cpp1432
-rw-r--r--plugins/Clist_modern/src/modern_skinengine.cpp7514
-rw-r--r--plugins/Clist_modern/src/modern_skinopt.cpp1092
-rw-r--r--plugins/Clist_modern/src/modern_skinselector.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_skinselector.h2
-rw-r--r--plugins/Clist_modern/src/modern_static_clui.h228
-rw-r--r--plugins/Clist_modern/src/modern_statusbar_options.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_toolbar.cpp2
-rw-r--r--plugins/Clist_modern/src/modern_viewmodebar.cpp2
-rw-r--r--plugins/Clist_modern/src/stdafx.h2
45 files changed, 5918 insertions, 5918 deletions
diff --git a/plugins/Clist_modern/src/cluiframes.cpp b/plugins/Clist_modern/src/cluiframes.cpp
index c2cb8b459c..250c221327 100644
--- a/plugins/Clist_modern/src/cluiframes.cpp
+++ b/plugins/Clist_modern/src/cluiframes.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/groupmenu.cpp b/plugins/Clist_modern/src/groupmenu.cpp
index 82e2873a2f..c3d6d99d0b 100644
--- a/plugins/Clist_modern/src/groupmenu.cpp
+++ b/plugins/Clist_modern/src/groupmenu.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/init.cpp b/plugins/Clist_modern/src/init.cpp
index cfddf29267..3026d17ba2 100644
--- a/plugins/Clist_modern/src/init.cpp
+++ b/plugins/Clist_modern/src/init.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_aniavatars.cpp b/plugins/Clist_modern/src/modern_aniavatars.cpp
index 327ed73f7f..babff44fa8 100644
--- a/plugins/Clist_modern/src/modern_aniavatars.cpp
+++ b/plugins/Clist_modern/src/modern_aniavatars.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_awaymsg.cpp b/plugins/Clist_modern/src/modern_awaymsg.cpp
index 31a9bcabed..cf8897d329 100644
--- a/plugins/Clist_modern/src/modern_awaymsg.cpp
+++ b/plugins/Clist_modern/src/modern_awaymsg.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_awaymsg.h b/plugins/Clist_modern/src/modern_awaymsg.h
index e8b3e1c3cb..d5c0cf6337 100644
--- a/plugins/Clist_modern/src/modern_awaymsg.h
+++ b/plugins/Clist_modern/src/modern_awaymsg.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_cache_funcs.h b/plugins/Clist_modern/src/modern_cache_funcs.h
index 5adc1db25b..03f8d5ab7d 100644
--- a/plugins/Clist_modern/src/modern_cache_funcs.h
+++ b/plugins/Clist_modern/src/modern_cache_funcs.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_cachefuncs.cpp b/plugins/Clist_modern/src/modern_cachefuncs.cpp
index cb977bea6e..1fff523f92 100644
--- a/plugins/Clist_modern/src/modern_cachefuncs.cpp
+++ b/plugins/Clist_modern/src/modern_cachefuncs.cpp
@@ -1,745 +1,745 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (C) 2012-22 Miranda NG team (https://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 "stdafx.h"
-#include "modern_sync.h"
-
-typedef BOOL(*ExecuteOnAllContactsFuncPtr) (ClcContact *contact, BOOL subcontact, void *param);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Module static declarations
-
-static int CopySkipUnprintableChars(wchar_t *to, wchar_t * buf, uint32_t size);
-
-static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param);
-static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Get time zone for contact
-//
-void Cache_GetTimezone(ClcData *dat, MCONTACT hContact)
-{
- ClcCacheEntry *pdnce = Clist_GetCacheEntry(hContact);
- if (dat == nullptr && g_clistApi.hwndContactTree)
- dat = (ClcData *)GetWindowLongPtr(g_clistApi.hwndContactTree, 0);
-
- if (dat && dat->hWnd == g_clistApi.hwndContactTree) {
- uint32_t flags = dat->contact_time_show_only_if_different ? TZF_DIFONLY : 0;
- pdnce->hTimeZone = TimeZone_CreateByContact(hContact, nullptr, flags);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Get all lines of text
-//
-void Cache_GetText(ClcData *dat, ClcContact *contact)
-{
- Cache_GetFirstLineText(dat, contact);
-
- if (!dat->bForceInDialog) {
- if (g_plugin.secondLine.bActive)
- Cache_GetNthLineText(dat, contact->pce, 2);
- if (g_plugin.thirdLine.bActive)
- Cache_GetNthLineText(dat, contact->pce, 3);
- }
-}
-
-void CSmileyString::AddListeningToIcon(ClcData *dat, wchar_t *szText)
-{
- iMaxSmileyHeight = 0;
- DestroySmileyList();
-
- if (szText == nullptr)
- return;
-
- int text_size = (int)mir_wstrlen(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)
-{
- 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 != nullptr) {
- 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()
-{
- if (plText == nullptr)
- return;
-
- if (IsBadReadPtr(plText, sizeof(SortedList))) {
- plText = nullptr;
- return;
- }
-
- if (plText->realCount != 0) {
- for (int i = 0; i < plText->realCount; i++) {
- if (plText->items[i] != nullptr) {
- 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 = nullptr;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Parsing of text for smiley
-//
-void CSmileyString::ReplaceSmileys(ClcData *dat, ClcCacheEntry *pdnce, wchar_t *szText, BOOL replace_smileys)
-{
- int last_pos = 0;
- iMaxSmileyHeight = 0;
-
- DestroySmileyList();
-
- if (!dat->text_replace_smileys || !replace_smileys || szText == nullptr)
- return;
-
- int text_size = (int)mir_wstrlen(szText);
-
- // Call service for the first time to see if needs to be used...
- SMADD_BATCHPARSE2 sp = {};
- sp.cbSize = sizeof(sp);
- sp.hContact = pdnce->hContact;
-
- if (dat->text_use_protocol_smileys) {
- sp.Protocolname = pdnce->szProto;
-
- if (db_get_b(0, "CLC", "Meta", SETTING_USEMETAICON_DEFAULT) != 1 && pdnce->szProto != nullptr && mir_strcmp(pdnce->szProto, META_PROTO) == 0) {
- MCONTACT hContact = db_mc_getMostOnline(pdnce->hContact);
- if (hContact != 0)
- sp.Protocolname = Proto_GetBaseAccountName(hContact);
- }
- }
- else sp.Protocolname = "clist";
-
- sp.str = szText;
- sp.flag = SAFL_TCHAR;
-
- SMADD_BATCHPARSERES *spr = (SMADD_BATCHPARSERES*)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp);
-
- // Did not find a simley
- if (spr == nullptr || (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 != nullptr) { // 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
-// returns -1 for XStatus, 1 for Status
-//
-int GetStatusName(wchar_t *text, int text_size, ClcCacheEntry *pdnce, BOOL bXstatusHasPriority)
-{
- BOOL noAwayMsg = FALSE;
- BOOL noXstatus = FALSE;
- // Hide status text if Offline /// no offline
- uint16_t nStatus = pdnce->getStatus();
- 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 && bXstatusHasPriority && pdnce->hContact && pdnce->szProto) {
- DBVARIANT dbv = { 0 };
- if (!db_get_ws(pdnce->hContact, pdnce->szProto, "XStatusName", &dbv)) {
- CopySkipUnprintableChars(text, dbv.pwszVal, text_size - 1);
- db_free(&dbv);
-
- if (text[0] != '\0')
- return -1;
- }
- }
-
- // Get Status name
- wchar_t *tmp = Clist_GetStatusModeDescription(nStatus, 0);
- if (tmp && *tmp) {
- mir_wstrncpy(text, tmp, text_size);
- return 1;
- }
-
- // Get XStatusName
- if (!noAwayMsg && !noXstatus && !bXstatusHasPriority && pdnce->hContact && pdnce->szProto) {
- DBVARIANT dbv = { 0 };
- if (!db_get_ws(pdnce->hContact, pdnce->szProto, "XStatusName", &dbv)) {
- CopySkipUnprintableChars(text, dbv.pwszVal, text_size - 1);
- db_free(&dbv);
-
- if (text[0] != '\0')
- return -1;
- }
- }
-
- return 1;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Get Listening to information
-//
-void GetListeningTo(wchar_t *text, int text_size, ClcCacheEntry *pdnce)
-{
- *text = '\0';
-
- if (pdnce->m_iStatus == ID_STATUS_OFFLINE || pdnce->m_iStatus == 0)
- return;
-
- ptrW tszValue(db_get_wsa(pdnce->hContact, pdnce->szProto, "ListeningTo"));
- if (tszValue != nullptr)
- CopySkipUnprintableChars(text, tszValue, text_size - 1);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Getting Status message(Away message)
-// returns -1 for XStatus, 1 for Status
-//
-int GetStatusMessage(wchar_t *text, int text_size, ClcCacheEntry *pdnce, BOOL bXstatusHasPriority)
-{
- BOOL noAwayMsg = FALSE;
- uint16_t wStatus = pdnce->getStatus();
- *text = '\0';
-
- // Hide status text if Offline /// no offline
- if (wStatus == ID_STATUS_OFFLINE || wStatus == 0)
- noAwayMsg = TRUE;
-
- // Get XStatusMsg
- if (!noAwayMsg && bXstatusHasPriority && pdnce->hContact && pdnce->szProto) {
- ptrW tszXStatusMsg(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusMsg"));
- if (tszXStatusMsg != nullptr) {
- CopySkipUnprintableChars(text, tszXStatusMsg, text_size - 1);
- if (text[0] != '\0')
- return -1;
- }
- }
-
- // Get StatusMsg
- if (pdnce->hContact && text[0] == '\0') {
- if (noAwayMsg && ServiceExists(MS_LASTSEEN_GET)) {
- ptrW pwszLastSeen((LPWSTR)CallService(MS_LASTSEEN_GET, (WPARAM)pdnce->hContact));
- if (pwszLastSeen) {
- CMStringW wszLastSeen(FORMAT, L"%s: %s", TranslateT("Last seen"), pwszLastSeen);
- CopySkipUnprintableChars(text, (wchar_t*)wszLastSeen.c_str(), text_size - 1);
- if (text[0] != '\0')
- return 1;
- }
- }
-
- ptrW tszStatusMsg(g_plugin.getWStringA(pdnce->hContact, "StatusMsg"));
- if (tszStatusMsg != nullptr) {
- CopySkipUnprintableChars(text, tszStatusMsg, text_size - 1);
- if (text[0] != '\0')
- return 1;
- }
-
- }
-
- // Get XStatusMsg
- if (!noAwayMsg && !bXstatusHasPriority && pdnce->hContact && pdnce->szProto && text[0] == '\0') {
- // Try to get XStatusMsg
- ptrW tszXStatusMsg(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusMsg"));
- if (tszXStatusMsg != nullptr) {
- CopySkipUnprintableChars(text, tszXStatusMsg, text_size - 1);
- 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, ClcLineInfo &line)
-{
- if (text == nullptr)
- return TEXT_EMPTY;
- text[0] = '\0';
-
- switch (type) {
- case TEXT_STATUS:
-LBL_Status:
- if (GetStatusName(text, text_size, pdnce, line.bXstatusHasPriority) == -1 && line.bUseNameAndMessageForXstatus) {
- // Try to get XStatusMsg
- ptrW tszXStatusMsg(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusMsg"));
- if (tszXStatusMsg != nullptr && tszXStatusMsg[0] != 0) {
- wchar_t *tmp = NEWWSTR_ALLOCA(text);
- mir_snwprintf(text, text_size, L"%s: %s", tmp, tszXStatusMsg.get());
- CopySkipUnprintableChars(text, text, text_size - 1);
- }
- }
- return TEXT_STATUS;
-
- case TEXT_NICKNAME:
- if (pdnce->hContact && pdnce->szProto) {
- ptrW tszNick(db_get_wsa(pdnce->hContact, pdnce->szProto, "Nick"));
- if (tszNick != nullptr) {
- mir_wstrncpy(text, tszNick, text_size);
- CopySkipUnprintableChars(text, text, text_size - 1);
- }
- }
- return TEXT_NICKNAME;
-
- case TEXT_STATUS_MESSAGE:
- if (GetStatusMessage(text, text_size, pdnce, line.bXstatusHasPriority) == -1 && line.bUseNameAndMessageForXstatus) {
- // Try to get XStatusName
- ptrW tszXStatusName(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusName"));
- if (tszXStatusName != nullptr && tszXStatusName[0] != 0) {
- wchar_t *tmp = NEWWSTR_ALLOCA(text);
- mir_snwprintf(text, text_size, L"%s: %s", tszXStatusName.get(), tmp);
- CopySkipUnprintableChars(text, text, text_size - 1);
- }
- }
- else if (line.bUseNameAndMessageForXstatus && line.bXstatusHasPriority) {
- // Try to get XStatusName
- ptrW tszXStatusName(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusName"));
- if (tszXStatusName != nullptr && tszXStatusName[0] != 0) {
- mir_wstrncpy(text, tszXStatusName, text_size);
- CopySkipUnprintableChars(text, text, text_size - 1);
- }
- }
-
- if (text[0] == '\0') {
- if (line.bShowListeningIfNoAway) {
- GetListeningTo(text, text_size, pdnce);
- if (text[0] != '\0')
- return TEXT_LISTENING_TO;
- }
-
- if (line.bShowStatusIfNoAway) // re-request status if no away
- goto LBL_Status;
- }
- return TEXT_STATUS_MESSAGE;
-
- case TEXT_LISTENING_TO:
- GetListeningTo(text, text_size, pdnce);
- return TEXT_LISTENING_TO;
-
- case TEXT_TEXT:
- {
- ptrW tmp(variables_parsedup(line.text, pdnce->tszName, pdnce->hContact));
- mir_wstrncpy(text, tmp, text_size);
- CopySkipUnprintableChars(text, text, text_size - 1);
- }
- return TEXT_TEXT;
-
- case TEXT_CONTACT_TIME:
- if (pdnce->hTimeZone) {
- // Get pdnce time
- text[0] = 0;
- TimeZone_PrintDateTime(pdnce->hTimeZone, L"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 = contact->pce;
- wchar_t *name = Clist_GetContactDisplayName(contact->hContact);
- if (dat->first_line_append_nick && !dat->bForceInDialog) {
- DBVARIANT dbv = { 0 };
- if (!db_get_ws(pdnce->hContact, pdnce->szProto, "Nick", &dbv)) {
- wchar_t nick[_countof(contact->szText)];
- wcsncpy_s(nick, dbv.pwszVal, _TRUNCATE);
- db_free(&dbv);
-
- // They are the same -> use the name to keep the case
- if (mir_wstrcmpi(name, nick) == 0)
- wcsncpy_s(contact->szText, name, _TRUNCATE);
- else // Append then
- mir_snwprintf(contact->szText, L"%s - %s", name, nick);
- }
- else wcsncpy_s(contact->szText, name, _TRUNCATE);
- }
- else wcsncpy_s(contact->szText, name, _TRUNCATE);
-
- if (!dat->bForceInDialog)
- contact->ssText.ReplaceSmileys(dat, pdnce, contact->szText, dat->first_line_draw_smileys);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Get the text for Second Line
-
-void Cache_GetNthLineText(ClcData *dat, ClcCacheEntry *pdnce, int n)
-{
- if (pdnce == nullptr)
- return;
-
- wchar_t Text[240 - EXTRA_ICON_COUNT]; Text[0] = 0;
- ClcLineInfo &line = (n == 2) ? g_plugin.secondLine : g_plugin.thirdLine;
- wchar_t* &szText = (n == 2) ? pdnce->szSecondLineText : pdnce->szThirdLineText;
-
- // in most cases replaceStrW does nothing
- if (!line.bActive) {
- replaceStrW(szText, nullptr);
- return;
- }
-
- int type = Cache_GetLineText(pdnce, line.iType, Text, _countof(Text), line);
- if (Text[0] == 0) {
- replaceStrW(szText, nullptr);
- return;
- }
-
- Text[_countof(Text) - 1] = 0; //to be sure that it is null terminated string
- replaceStrW(szText, Text);
-
- CSmileyString &ss = (n == 2) ? pdnce->ssSecondLine : pdnce->ssThirdLine;
- if (type == TEXT_LISTENING_TO && szText[0] != '\0')
- ss.AddListeningToIcon(dat, szText);
- else
- ss.ReplaceSmileys(dat, pdnce, szText, line.bDrawSmilies);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void RemoveTag(wchar_t *to, wchar_t *tag)
-{
- wchar_t *st = to;
- int len = (int)mir_wstrlen(tag);
- int lastsize = (int)mir_wstrlen(to) + 1;
- while (st = wcsstr(st, tag)) {
- lastsize -= len;
- memmove((void*)st, (void*)(st + len), (lastsize)*sizeof(wchar_t));
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Copy string with removing Escape chars from text and BBcodes
-
-static int CopySkipUnprintableChars(wchar_t *to, wchar_t * buf, uint32_t size)
-{
- uint32_t i;
- BOOL keep = 0;
- wchar_t * 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, L"[b]"); RemoveTag(to, L"[/b]");
- RemoveTag(to, L"[u]"); RemoveTag(to, L"[/u]");
- RemoveTag(to, L"[i]"); RemoveTag(to, L"[/i]");
-
- RemoveTag(to, L"<b>"); RemoveTag(to, L"</b>");
- RemoveTag(to, L"<u>"); RemoveTag(to, L"</u>");
- RemoveTag(to, L"<i>"); RemoveTag(to, L"</i>");
-
- RemoveTag(to, L"[B]"); RemoveTag(to, L"[/b]");
- RemoveTag(to, L"[U]"); RemoveTag(to, L"[/u]");
- RemoveTag(to, L"[I]"); RemoveTag(to, L"[/i]");
-
- RemoveTag(to, L"<B>"); RemoveTag(to, L"</B>");
- RemoveTag(to, L"<U>"); RemoveTag(to, L"</U>");
- RemoveTag(to, L"<I>"); RemoveTag(to, L"</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)
-{
- return ExecuteOnAllContactsOfGroup(&dat->list, func, param);
-}
-
-static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param)
-{
- if (!group)
- return TRUE;
-
- for (auto &it : group->cl) {
- if (it->type == CLCIT_CONTACT) {
- if (!func(it, FALSE, param))
- return FALSE;
-
- if (it->iSubAllocated > 0) {
- for (int i = 0; i < it->iSubAllocated; i++)
- if (!func(&it->subcontacts[i], TRUE, param))
- return FALSE;
- }
- }
- else if (it->type == CLCIT_GROUP)
- if (!ExecuteOnAllContactsOfGroup(it->group, func, param))
- return FALSE;
- }
-
- return TRUE;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Avatar working routines
-//
-BOOL UpdateAllAvatarsProxy(ClcContact *contact, BOOL, void *param)
-{
- Cache_GetAvatar((ClcData *)param, contact);
- return TRUE;
-}
-
-void UpdateAllAvatars(ClcData *dat)
-{
- ExecuteOnAllContacts(dat, UpdateAllAvatarsProxy, dat);
-}
-
-BOOL ReduceAvatarPosition(ClcContact *contact, BOOL, void *param)
-{
- if (contact->avatar_pos >= *((int *)param))
- contact->avatar_pos--;
-
- return TRUE;
-}
-
-void Cache_ProceedAvatarInList(ClcData *dat, ClcContact *contact)
-{
- AVATARCACHEENTRY *ace = contact->avatar_data;
- int old_pos = contact->avatar_pos;
-
- if (ace == nullptr || ace->dwFlags == AVS_BITMAP_EXPIRED || ace->hbmPic == nullptr) {
- // 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 != nullptr) { // let's add it
- // Clipping width and height
- LONG width_clip = dat->avatars_maxwidth_size ? dat->avatars_maxwidth_size : dat->avatars_maxheight_size;
- LONG 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 (wildcmpiw(contact->avatar_data->szFilename, L"*.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
- HDC hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
-
- void *pt;
- HBITMAP hDrawBmp = ske_CreateDIB32Point(width_clip, height_clip, &pt);
- HBITMAP oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
-
- // need to draw avatar bitmap here
- DrawAvatarImageWithGDIp(hdc, 0, 0, width_clip, height_clip, 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)
-{
- // workaround for avatar service
- if (g_CluiData.bSTATE != STATE_NORMAL) {
- contact->avatar_pos = AVATAR_POS_DONT_HAVE;
- contact->avatar_data = nullptr;
- return;
- }
-
- if (dat->avatars_show && !g_plugin.getByte(contact->hContact, "HideContactAvatar", 0)) {
- contact->avatar_data = (AVATARCACHEENTRY*)CallService(MS_AV_GETAVATARBITMAP, contact->hContact, 0);
- if (contact->avatar_data == nullptr || contact->avatar_data->dwFlags == AVS_BITMAP_EXPIRED)
- contact->avatar_data = nullptr;
-
- if (contact->avatar_data != nullptr)
- contact->avatar_data->t_lastAccess = (uint32_t)time(0);
- }
- else contact->avatar_data = nullptr;
-
- Cache_ProceedAvatarInList(dat, contact);
-}
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (C) 2012-23 Miranda NG team (https://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 "stdafx.h"
+#include "modern_sync.h"
+
+typedef BOOL(*ExecuteOnAllContactsFuncPtr) (ClcContact *contact, BOOL subcontact, void *param);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module static declarations
+
+static int CopySkipUnprintableChars(wchar_t *to, wchar_t * buf, uint32_t size);
+
+static BOOL ExecuteOnAllContacts(ClcData *dat, ExecuteOnAllContactsFuncPtr func, void *param);
+static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Get time zone for contact
+//
+void Cache_GetTimezone(ClcData *dat, MCONTACT hContact)
+{
+ ClcCacheEntry *pdnce = Clist_GetCacheEntry(hContact);
+ if (dat == nullptr && g_clistApi.hwndContactTree)
+ dat = (ClcData *)GetWindowLongPtr(g_clistApi.hwndContactTree, 0);
+
+ if (dat && dat->hWnd == g_clistApi.hwndContactTree) {
+ uint32_t flags = dat->contact_time_show_only_if_different ? TZF_DIFONLY : 0;
+ pdnce->hTimeZone = TimeZone_CreateByContact(hContact, nullptr, flags);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Get all lines of text
+//
+void Cache_GetText(ClcData *dat, ClcContact *contact)
+{
+ Cache_GetFirstLineText(dat, contact);
+
+ if (!dat->bForceInDialog) {
+ if (g_plugin.secondLine.bActive)
+ Cache_GetNthLineText(dat, contact->pce, 2);
+ if (g_plugin.thirdLine.bActive)
+ Cache_GetNthLineText(dat, contact->pce, 3);
+ }
+}
+
+void CSmileyString::AddListeningToIcon(ClcData *dat, wchar_t *szText)
+{
+ iMaxSmileyHeight = 0;
+ DestroySmileyList();
+
+ if (szText == nullptr)
+ return;
+
+ int text_size = (int)mir_wstrlen(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)
+{
+ 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 != nullptr) {
+ 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()
+{
+ if (plText == nullptr)
+ return;
+
+ if (IsBadReadPtr(plText, sizeof(SortedList))) {
+ plText = nullptr;
+ return;
+ }
+
+ if (plText->realCount != 0) {
+ for (int i = 0; i < plText->realCount; i++) {
+ if (plText->items[i] != nullptr) {
+ 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 = nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Parsing of text for smiley
+//
+void CSmileyString::ReplaceSmileys(ClcData *dat, ClcCacheEntry *pdnce, wchar_t *szText, BOOL replace_smileys)
+{
+ int last_pos = 0;
+ iMaxSmileyHeight = 0;
+
+ DestroySmileyList();
+
+ if (!dat->text_replace_smileys || !replace_smileys || szText == nullptr)
+ return;
+
+ int text_size = (int)mir_wstrlen(szText);
+
+ // Call service for the first time to see if needs to be used...
+ SMADD_BATCHPARSE2 sp = {};
+ sp.cbSize = sizeof(sp);
+ sp.hContact = pdnce->hContact;
+
+ if (dat->text_use_protocol_smileys) {
+ sp.Protocolname = pdnce->szProto;
+
+ if (db_get_b(0, "CLC", "Meta", SETTING_USEMETAICON_DEFAULT) != 1 && pdnce->szProto != nullptr && mir_strcmp(pdnce->szProto, META_PROTO) == 0) {
+ MCONTACT hContact = db_mc_getMostOnline(pdnce->hContact);
+ if (hContact != 0)
+ sp.Protocolname = Proto_GetBaseAccountName(hContact);
+ }
+ }
+ else sp.Protocolname = "clist";
+
+ sp.str = szText;
+ sp.flag = SAFL_TCHAR;
+
+ SMADD_BATCHPARSERES *spr = (SMADD_BATCHPARSERES*)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp);
+
+ // Did not find a simley
+ if (spr == nullptr || (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 != nullptr) { // 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
+// returns -1 for XStatus, 1 for Status
+//
+int GetStatusName(wchar_t *text, int text_size, ClcCacheEntry *pdnce, BOOL bXstatusHasPriority)
+{
+ BOOL noAwayMsg = FALSE;
+ BOOL noXstatus = FALSE;
+ // Hide status text if Offline /// no offline
+ uint16_t nStatus = pdnce->getStatus();
+ 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 && bXstatusHasPriority && pdnce->hContact && pdnce->szProto) {
+ DBVARIANT dbv = { 0 };
+ if (!db_get_ws(pdnce->hContact, pdnce->szProto, "XStatusName", &dbv)) {
+ CopySkipUnprintableChars(text, dbv.pwszVal, text_size - 1);
+ db_free(&dbv);
+
+ if (text[0] != '\0')
+ return -1;
+ }
+ }
+
+ // Get Status name
+ wchar_t *tmp = Clist_GetStatusModeDescription(nStatus, 0);
+ if (tmp && *tmp) {
+ mir_wstrncpy(text, tmp, text_size);
+ return 1;
+ }
+
+ // Get XStatusName
+ if (!noAwayMsg && !noXstatus && !bXstatusHasPriority && pdnce->hContact && pdnce->szProto) {
+ DBVARIANT dbv = { 0 };
+ if (!db_get_ws(pdnce->hContact, pdnce->szProto, "XStatusName", &dbv)) {
+ CopySkipUnprintableChars(text, dbv.pwszVal, text_size - 1);
+ db_free(&dbv);
+
+ if (text[0] != '\0')
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Get Listening to information
+//
+void GetListeningTo(wchar_t *text, int text_size, ClcCacheEntry *pdnce)
+{
+ *text = '\0';
+
+ if (pdnce->m_iStatus == ID_STATUS_OFFLINE || pdnce->m_iStatus == 0)
+ return;
+
+ ptrW tszValue(db_get_wsa(pdnce->hContact, pdnce->szProto, "ListeningTo"));
+ if (tszValue != nullptr)
+ CopySkipUnprintableChars(text, tszValue, text_size - 1);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Getting Status message(Away message)
+// returns -1 for XStatus, 1 for Status
+//
+int GetStatusMessage(wchar_t *text, int text_size, ClcCacheEntry *pdnce, BOOL bXstatusHasPriority)
+{
+ BOOL noAwayMsg = FALSE;
+ uint16_t wStatus = pdnce->getStatus();
+ *text = '\0';
+
+ // Hide status text if Offline /// no offline
+ if (wStatus == ID_STATUS_OFFLINE || wStatus == 0)
+ noAwayMsg = TRUE;
+
+ // Get XStatusMsg
+ if (!noAwayMsg && bXstatusHasPriority && pdnce->hContact && pdnce->szProto) {
+ ptrW tszXStatusMsg(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusMsg"));
+ if (tszXStatusMsg != nullptr) {
+ CopySkipUnprintableChars(text, tszXStatusMsg, text_size - 1);
+ if (text[0] != '\0')
+ return -1;
+ }
+ }
+
+ // Get StatusMsg
+ if (pdnce->hContact && text[0] == '\0') {
+ if (noAwayMsg && ServiceExists(MS_LASTSEEN_GET)) {
+ ptrW pwszLastSeen((LPWSTR)CallService(MS_LASTSEEN_GET, (WPARAM)pdnce->hContact));
+ if (pwszLastSeen) {
+ CMStringW wszLastSeen(FORMAT, L"%s: %s", TranslateT("Last seen"), pwszLastSeen);
+ CopySkipUnprintableChars(text, (wchar_t*)wszLastSeen.c_str(), text_size - 1);
+ if (text[0] != '\0')
+ return 1;
+ }
+ }
+
+ ptrW tszStatusMsg(g_plugin.getWStringA(pdnce->hContact, "StatusMsg"));
+ if (tszStatusMsg != nullptr) {
+ CopySkipUnprintableChars(text, tszStatusMsg, text_size - 1);
+ if (text[0] != '\0')
+ return 1;
+ }
+
+ }
+
+ // Get XStatusMsg
+ if (!noAwayMsg && !bXstatusHasPriority && pdnce->hContact && pdnce->szProto && text[0] == '\0') {
+ // Try to get XStatusMsg
+ ptrW tszXStatusMsg(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusMsg"));
+ if (tszXStatusMsg != nullptr) {
+ CopySkipUnprintableChars(text, tszXStatusMsg, text_size - 1);
+ 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, ClcLineInfo &line)
+{
+ if (text == nullptr)
+ return TEXT_EMPTY;
+ text[0] = '\0';
+
+ switch (type) {
+ case TEXT_STATUS:
+LBL_Status:
+ if (GetStatusName(text, text_size, pdnce, line.bXstatusHasPriority) == -1 && line.bUseNameAndMessageForXstatus) {
+ // Try to get XStatusMsg
+ ptrW tszXStatusMsg(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusMsg"));
+ if (tszXStatusMsg != nullptr && tszXStatusMsg[0] != 0) {
+ wchar_t *tmp = NEWWSTR_ALLOCA(text);
+ mir_snwprintf(text, text_size, L"%s: %s", tmp, tszXStatusMsg.get());
+ CopySkipUnprintableChars(text, text, text_size - 1);
+ }
+ }
+ return TEXT_STATUS;
+
+ case TEXT_NICKNAME:
+ if (pdnce->hContact && pdnce->szProto) {
+ ptrW tszNick(db_get_wsa(pdnce->hContact, pdnce->szProto, "Nick"));
+ if (tszNick != nullptr) {
+ mir_wstrncpy(text, tszNick, text_size);
+ CopySkipUnprintableChars(text, text, text_size - 1);
+ }
+ }
+ return TEXT_NICKNAME;
+
+ case TEXT_STATUS_MESSAGE:
+ if (GetStatusMessage(text, text_size, pdnce, line.bXstatusHasPriority) == -1 && line.bUseNameAndMessageForXstatus) {
+ // Try to get XStatusName
+ ptrW tszXStatusName(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusName"));
+ if (tszXStatusName != nullptr && tszXStatusName[0] != 0) {
+ wchar_t *tmp = NEWWSTR_ALLOCA(text);
+ mir_snwprintf(text, text_size, L"%s: %s", tszXStatusName.get(), tmp);
+ CopySkipUnprintableChars(text, text, text_size - 1);
+ }
+ }
+ else if (line.bUseNameAndMessageForXstatus && line.bXstatusHasPriority) {
+ // Try to get XStatusName
+ ptrW tszXStatusName(db_get_wsa(pdnce->hContact, pdnce->szProto, "XStatusName"));
+ if (tszXStatusName != nullptr && tszXStatusName[0] != 0) {
+ mir_wstrncpy(text, tszXStatusName, text_size);
+ CopySkipUnprintableChars(text, text, text_size - 1);
+ }
+ }
+
+ if (text[0] == '\0') {
+ if (line.bShowListeningIfNoAway) {
+ GetListeningTo(text, text_size, pdnce);
+ if (text[0] != '\0')
+ return TEXT_LISTENING_TO;
+ }
+
+ if (line.bShowStatusIfNoAway) // re-request status if no away
+ goto LBL_Status;
+ }
+ return TEXT_STATUS_MESSAGE;
+
+ case TEXT_LISTENING_TO:
+ GetListeningTo(text, text_size, pdnce);
+ return TEXT_LISTENING_TO;
+
+ case TEXT_TEXT:
+ {
+ ptrW tmp(variables_parsedup(line.text, pdnce->tszName, pdnce->hContact));
+ mir_wstrncpy(text, tmp, text_size);
+ CopySkipUnprintableChars(text, text, text_size - 1);
+ }
+ return TEXT_TEXT;
+
+ case TEXT_CONTACT_TIME:
+ if (pdnce->hTimeZone) {
+ // Get pdnce time
+ text[0] = 0;
+ TimeZone_PrintDateTime(pdnce->hTimeZone, L"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 = contact->pce;
+ wchar_t *name = Clist_GetContactDisplayName(contact->hContact);
+ if (dat->first_line_append_nick && !dat->bForceInDialog) {
+ DBVARIANT dbv = { 0 };
+ if (!db_get_ws(pdnce->hContact, pdnce->szProto, "Nick", &dbv)) {
+ wchar_t nick[_countof(contact->szText)];
+ wcsncpy_s(nick, dbv.pwszVal, _TRUNCATE);
+ db_free(&dbv);
+
+ // They are the same -> use the name to keep the case
+ if (mir_wstrcmpi(name, nick) == 0)
+ wcsncpy_s(contact->szText, name, _TRUNCATE);
+ else // Append then
+ mir_snwprintf(contact->szText, L"%s - %s", name, nick);
+ }
+ else wcsncpy_s(contact->szText, name, _TRUNCATE);
+ }
+ else wcsncpy_s(contact->szText, name, _TRUNCATE);
+
+ if (!dat->bForceInDialog)
+ contact->ssText.ReplaceSmileys(dat, pdnce, contact->szText, dat->first_line_draw_smileys);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Get the text for Second Line
+
+void Cache_GetNthLineText(ClcData *dat, ClcCacheEntry *pdnce, int n)
+{
+ if (pdnce == nullptr)
+ return;
+
+ wchar_t Text[240 - EXTRA_ICON_COUNT]; Text[0] = 0;
+ ClcLineInfo &line = (n == 2) ? g_plugin.secondLine : g_plugin.thirdLine;
+ wchar_t* &szText = (n == 2) ? pdnce->szSecondLineText : pdnce->szThirdLineText;
+
+ // in most cases replaceStrW does nothing
+ if (!line.bActive) {
+ replaceStrW(szText, nullptr);
+ return;
+ }
+
+ int type = Cache_GetLineText(pdnce, line.iType, Text, _countof(Text), line);
+ if (Text[0] == 0) {
+ replaceStrW(szText, nullptr);
+ return;
+ }
+
+ Text[_countof(Text) - 1] = 0; //to be sure that it is null terminated string
+ replaceStrW(szText, Text);
+
+ CSmileyString &ss = (n == 2) ? pdnce->ssSecondLine : pdnce->ssThirdLine;
+ if (type == TEXT_LISTENING_TO && szText[0] != '\0')
+ ss.AddListeningToIcon(dat, szText);
+ else
+ ss.ReplaceSmileys(dat, pdnce, szText, line.bDrawSmilies);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void RemoveTag(wchar_t *to, wchar_t *tag)
+{
+ wchar_t *st = to;
+ int len = (int)mir_wstrlen(tag);
+ int lastsize = (int)mir_wstrlen(to) + 1;
+ while (st = wcsstr(st, tag)) {
+ lastsize -= len;
+ memmove((void*)st, (void*)(st + len), (lastsize)*sizeof(wchar_t));
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copy string with removing Escape chars from text and BBcodes
+
+static int CopySkipUnprintableChars(wchar_t *to, wchar_t * buf, uint32_t size)
+{
+ uint32_t i;
+ BOOL keep = 0;
+ wchar_t * 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, L"[b]"); RemoveTag(to, L"[/b]");
+ RemoveTag(to, L"[u]"); RemoveTag(to, L"[/u]");
+ RemoveTag(to, L"[i]"); RemoveTag(to, L"[/i]");
+
+ RemoveTag(to, L"<b>"); RemoveTag(to, L"</b>");
+ RemoveTag(to, L"<u>"); RemoveTag(to, L"</u>");
+ RemoveTag(to, L"<i>"); RemoveTag(to, L"</i>");
+
+ RemoveTag(to, L"[B]"); RemoveTag(to, L"[/b]");
+ RemoveTag(to, L"[U]"); RemoveTag(to, L"[/u]");
+ RemoveTag(to, L"[I]"); RemoveTag(to, L"[/i]");
+
+ RemoveTag(to, L"<B>"); RemoveTag(to, L"</B>");
+ RemoveTag(to, L"<U>"); RemoveTag(to, L"</U>");
+ RemoveTag(to, L"<I>"); RemoveTag(to, L"</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)
+{
+ return ExecuteOnAllContactsOfGroup(&dat->list, func, param);
+}
+
+static BOOL ExecuteOnAllContactsOfGroup(ClcGroup *group, ExecuteOnAllContactsFuncPtr func, void *param)
+{
+ if (!group)
+ return TRUE;
+
+ for (auto &it : group->cl) {
+ if (it->type == CLCIT_CONTACT) {
+ if (!func(it, FALSE, param))
+ return FALSE;
+
+ if (it->iSubAllocated > 0) {
+ for (int i = 0; i < it->iSubAllocated; i++)
+ if (!func(&it->subcontacts[i], TRUE, param))
+ return FALSE;
+ }
+ }
+ else if (it->type == CLCIT_GROUP)
+ if (!ExecuteOnAllContactsOfGroup(it->group, func, param))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Avatar working routines
+//
+BOOL UpdateAllAvatarsProxy(ClcContact *contact, BOOL, void *param)
+{
+ Cache_GetAvatar((ClcData *)param, contact);
+ return TRUE;
+}
+
+void UpdateAllAvatars(ClcData *dat)
+{
+ ExecuteOnAllContacts(dat, UpdateAllAvatarsProxy, dat);
+}
+
+BOOL ReduceAvatarPosition(ClcContact *contact, BOOL, void *param)
+{
+ if (contact->avatar_pos >= *((int *)param))
+ contact->avatar_pos--;
+
+ return TRUE;
+}
+
+void Cache_ProceedAvatarInList(ClcData *dat, ClcContact *contact)
+{
+ AVATARCACHEENTRY *ace = contact->avatar_data;
+ int old_pos = contact->avatar_pos;
+
+ if (ace == nullptr || ace->dwFlags == AVS_BITMAP_EXPIRED || ace->hbmPic == nullptr) {
+ // 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 != nullptr) { // let's add it
+ // Clipping width and height
+ LONG width_clip = dat->avatars_maxwidth_size ? dat->avatars_maxwidth_size : dat->avatars_maxheight_size;
+ LONG 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 (wildcmpiw(contact->avatar_data->szFilename, L"*.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
+ HDC hdc = CreateCompatibleDC(dat->avatar_cache.hdc);
+
+ void *pt;
+ HBITMAP hDrawBmp = ske_CreateDIB32Point(width_clip, height_clip, &pt);
+ HBITMAP oldBmp = (HBITMAP)SelectObject(hdc, hDrawBmp);
+
+ // need to draw avatar bitmap here
+ DrawAvatarImageWithGDIp(hdc, 0, 0, width_clip, height_clip, 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)
+{
+ // workaround for avatar service
+ if (g_CluiData.bSTATE != STATE_NORMAL) {
+ contact->avatar_pos = AVATAR_POS_DONT_HAVE;
+ contact->avatar_data = nullptr;
+ return;
+ }
+
+ if (dat->avatars_show && !g_plugin.getByte(contact->hContact, "HideContactAvatar", 0)) {
+ contact->avatar_data = (AVATARCACHEENTRY*)CallService(MS_AV_GETAVATARBITMAP, contact->hContact, 0);
+ if (contact->avatar_data == nullptr || contact->avatar_data->dwFlags == AVS_BITMAP_EXPIRED)
+ contact->avatar_data = nullptr;
+
+ if (contact->avatar_data != nullptr)
+ contact->avatar_data->t_lastAccess = (uint32_t)time(0);
+ }
+ else contact->avatar_data = nullptr;
+
+ Cache_ProceedAvatarInList(dat, contact);
+}
diff --git a/plugins/Clist_modern/src/modern_clc.cpp b/plugins/Clist_modern/src/modern_clc.cpp
index e549d98f88..d89b70b541 100644
--- a/plugins/Clist_modern/src/modern_clc.cpp
+++ b/plugins/Clist_modern/src/modern_clc.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clc.h b/plugins/Clist_modern/src/modern_clc.h
index 1d0d2328e4..c0956ee8cd 100644
--- a/plugins/Clist_modern/src/modern_clc.h
+++ b/plugins/Clist_modern/src/modern_clc.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clcidents.cpp b/plugins/Clist_modern/src/modern_clcidents.cpp
index 36ac3c3291..29be4b6442 100644
--- a/plugins/Clist_modern/src/modern_clcidents.cpp
+++ b/plugins/Clist_modern/src/modern_clcidents.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clcitems.cpp b/plugins/Clist_modern/src/modern_clcitems.cpp
index 61b6d6eca5..a2472b99d8 100644
--- a/plugins/Clist_modern/src/modern_clcitems.cpp
+++ b/plugins/Clist_modern/src/modern_clcitems.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clcmsgs.cpp b/plugins/Clist_modern/src/modern_clcmsgs.cpp
index 7c64c944ff..663872a25c 100644
--- a/plugins/Clist_modern/src/modern_clcmsgs.cpp
+++ b/plugins/Clist_modern/src/modern_clcmsgs.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clcopts.cpp b/plugins/Clist_modern/src/modern_clcopts.cpp
index d5d25caf10..52e16a6d53 100644
--- a/plugins/Clist_modern/src/modern_clcopts.cpp
+++ b/plugins/Clist_modern/src/modern_clcopts.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clcpaint.cpp b/plugins/Clist_modern/src/modern_clcpaint.cpp
index 1bd6370e1d..aeb4dd1ade 100644
--- a/plugins/Clist_modern/src/modern_clcpaint.cpp
+++ b/plugins/Clist_modern/src/modern_clcpaint.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clcutils.cpp b/plugins/Clist_modern/src/modern_clcutils.cpp
index 1fa39e4c78..29e438a846 100644
--- a/plugins/Clist_modern/src/modern_clcutils.cpp
+++ b/plugins/Clist_modern/src/modern_clcutils.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clist.h b/plugins/Clist_modern/src/modern_clist.h
index 0aa53268d4..79d9ca48cf 100644
--- a/plugins/Clist_modern/src/modern_clist.h
+++ b/plugins/Clist_modern/src/modern_clist.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clistevents.cpp b/plugins/Clist_modern/src/modern_clistevents.cpp
index 264f15f57e..e918bcee65 100644
--- a/plugins/Clist_modern/src/modern_clistevents.cpp
+++ b/plugins/Clist_modern/src/modern_clistevents.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org),
Copyright (c) 2000-03 Miranda ICQ/IM project,
all portions of this codebase are copyrighted to the people
listed in contributors.txt.
diff --git a/plugins/Clist_modern/src/modern_clistmenus.cpp b/plugins/Clist_modern/src/modern_clistmenus.cpp
index caae8ff8d1..802cad6cd7 100644
--- a/plugins/Clist_modern/src/modern_clistmenus.cpp
+++ b/plugins/Clist_modern/src/modern_clistmenus.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clistmod.cpp b/plugins/Clist_modern/src/modern_clistmod.cpp
index 0f06f872d0..08373b20d4 100644
--- a/plugins/Clist_modern/src/modern_clistmod.cpp
+++ b/plugins/Clist_modern/src/modern_clistmod.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clistopts.cpp b/plugins/Clist_modern/src/modern_clistopts.cpp
index cef88490dd..4862068c16 100644
--- a/plugins/Clist_modern/src/modern_clistopts.cpp
+++ b/plugins/Clist_modern/src/modern_clistopts.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clistsettings.cpp b/plugins/Clist_modern/src/modern_clistsettings.cpp
index ac35bad94a..c786522386 100644
--- a/plugins/Clist_modern/src/modern_clistsettings.cpp
+++ b/plugins/Clist_modern/src/modern_clistsettings.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clisttray.cpp b/plugins/Clist_modern/src/modern_clisttray.cpp
index fde9a29921..c79aff2f00 100644
--- a/plugins/Clist_modern/src/modern_clisttray.cpp
+++ b/plugins/Clist_modern/src/modern_clisttray.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clui.cpp b/plugins/Clist_modern/src/modern_clui.cpp
index 7406276759..8eecc76542 100644
--- a/plugins/Clist_modern/src/modern_clui.cpp
+++ b/plugins/Clist_modern/src/modern_clui.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_clui.h b/plugins/Clist_modern/src/modern_clui.h
index c27ea5bb95..c6267ccabc 100644
--- a/plugins/Clist_modern/src/modern_clui.h
+++ b/plugins/Clist_modern/src/modern_clui.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_cluiservices.cpp b/plugins/Clist_modern/src/modern_cluiservices.cpp
index 3aa536ed2b..ba1011b445 100644
--- a/plugins/Clist_modern/src/modern_cluiservices.cpp
+++ b/plugins/Clist_modern/src/modern_cluiservices.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_contact.cpp b/plugins/Clist_modern/src/modern_contact.cpp
index c39b2504aa..4a8420752a 100644
--- a/plugins/Clist_modern/src/modern_contact.cpp
+++ b/plugins/Clist_modern/src/modern_contact.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_defsettings.h b/plugins/Clist_modern/src/modern_defsettings.h
index 966f33e47c..04bfb6f73b 100644
--- a/plugins/Clist_modern/src/modern_defsettings.h
+++ b/plugins/Clist_modern/src/modern_defsettings.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org),
Copyright (c) 2000-08 Miranda ICQ/IM project,
Copyright 2007 Artem Shpynov
diff --git a/plugins/Clist_modern/src/modern_docking.cpp b/plugins/Clist_modern/src/modern_docking.cpp
index 5820132744..ee9a5d9807 100644
--- a/plugins/Clist_modern/src/modern_docking.cpp
+++ b/plugins/Clist_modern/src/modern_docking.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_global.cpp b/plugins/Clist_modern/src/modern_global.cpp
index fc24f84c09..d5d3c5d765 100644
--- a/plugins/Clist_modern/src/modern_global.cpp
+++ b/plugins/Clist_modern/src/modern_global.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_image_array.cpp b/plugins/Clist_modern/src/modern_image_array.cpp
index de65d5b9fa..230cbd119a 100644
--- a/plugins/Clist_modern/src/modern_image_array.cpp
+++ b/plugins/Clist_modern/src/modern_image_array.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_image_array.h b/plugins/Clist_modern/src/modern_image_array.h
index c817883b5a..369535e687 100644
--- a/plugins/Clist_modern/src/modern_image_array.h
+++ b/plugins/Clist_modern/src/modern_image_array.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_keyboard.cpp b/plugins/Clist_modern/src/modern_keyboard.cpp
index d1c956982d..075b8b9cab 100644
--- a/plugins/Clist_modern/src/modern_keyboard.cpp
+++ b/plugins/Clist_modern/src/modern_keyboard.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_rowheight_funcs.cpp b/plugins/Clist_modern/src/modern_rowheight_funcs.cpp
index c35cb7fcf7..bd54fbd582 100644
--- a/plugins/Clist_modern/src/modern_rowheight_funcs.cpp
+++ b/plugins/Clist_modern/src/modern_rowheight_funcs.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_rowheight_funcs.h b/plugins/Clist_modern/src/modern_rowheight_funcs.h
index 8699035b3c..ba99a67cf8 100644
--- a/plugins/Clist_modern/src/modern_rowheight_funcs.h
+++ b/plugins/Clist_modern/src/modern_rowheight_funcs.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_skinbutton.cpp b/plugins/Clist_modern/src/modern_skinbutton.cpp
index aa517a5ef2..f04d68d3b7 100644
--- a/plugins/Clist_modern/src/modern_skinbutton.cpp
+++ b/plugins/Clist_modern/src/modern_skinbutton.cpp
@@ -1,716 +1,716 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (C) 2012-22 Miranda NG team (https://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 "stdafx.h"
-#include "modern_clcpaint.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);
-HWND SetToolTip(HWND hwnd, wchar_t * tip);
-
-typedef struct _ModernSkinButtonCtrl
-{
- HWND hwnd;
- uint8_t down; // button state
- uint8_t focus; // has focus (1 or 0)
- uint8_t hover;
- uint8_t IsSwitcher;
- BOOL fCallOnPress;
- char * ID;
- char * CommandService;
- char * StateService;
- char * HandleService;
- char * ValueDBSection;
- char * ValueTypeDef;
- int Left, Top, Bottom, Right;
- HMENU hMenu;
- wchar_t * Hint;
-
-} ModernSkinButtonCtrl;
-typedef struct _HandleServiceParams
-{
- HWND hwnd;
- uint32_t msg;
- WPARAM wParam;
- LPARAM lParam;
- BOOL handled;
-} HandleServiceParams;
-
-static mir_cs csTips;
-static HWND hwndToolTips = nullptr;
-
-int ModernSkinButtonLoadModule()
-{
- WNDCLASSEX wc;
- memset(&wc, 0, sizeof(wc));
- wc.cbSize = sizeof(wc);
- wc.lpszClassName = _A2W(MODERNSKINBUTTONCLASS);
- wc.lpfnWndProc = ModernSkinButtonWndProc;
- wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
- wc.cbWndExtra = sizeof(ModernSkinButtonCtrl*);
- wc.hbrBackground = nullptr;
- wc.style = CS_GLOBALCLASS;
- RegisterClassEx(&wc);
- ModernSkinButtonModuleIsLoaded = TRUE;
- return 0;
-}
-
-int ModernSkinButtonUnloadModule(WPARAM, LPARAM)
-{
- return 0;
-}
-
-static int ModernSkinButtonPaintWorker(HWND hwnd, HDC whdc)
-{
- HDC hdc;
- RECT rc;
- ModernSkinButtonCtrl* bct = (ModernSkinButtonCtrl *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
- if (!bct) return 0;
- if (!IsWindowVisible(hwnd)) return 0;
- if (!whdc && !g_CluiData.fLayered) InvalidateRect(hwnd, nullptr, FALSE);
-
- if (whdc && g_CluiData.fLayered) hdc = whdc;
- else {
- //sdc = GetWindowDC(GetParent(hwnd));
- hdc = CreateCompatibleDC(nullptr);
- }
- GetClientRect(hwnd, &rc);
- HBITMAP bmp = ske_CreateDIB32(rc.right, rc.bottom);
- HBITMAP oldbmp = (HBITMAP)SelectObject(hdc, bmp);
- if (!g_CluiData.fLayered)
- ske_BltBackImage(bct->hwnd, hdc, nullptr);
- {
- MODERNMASK Request = {};
- // int res;
- //HBRUSH br = CreateSolidBrush(RGB(255,255,255));
- char * Value = nullptr;
- {
- if (bct->ValueDBSection && bct->ValueTypeDef) {
- char * key;
- char * section;
- uint32_t defval = 0;
- char buf[20];
- key = mir_strdup(bct->ValueDBSection);
- section = key;
- if (bct->ValueTypeDef[0] != 's')
- defval = (uint32_t)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(0, section, key, bct->ValueTypeDef + 1);
- break;
- case 'd':
- defval = db_get_dw(0, section, key, defval);
- Value = mir_strdup(_ltoa(defval, buf, _countof(buf)));
- break;
- case 'w':
- defval = db_get_w(0, section, key, defval);
- Value = mir_strdup(_ltoa(defval, buf, _countof(buf)));
- break;
- case 'b':
- defval = db_get_b(0, section, key, defval);
- Value = mir_strdup(_ltoa(defval, buf, _countof(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);
- }
-
- 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 = 0, l2 = 0, curval;
- // 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 = (uint32_t)atol(val);
- l2 = (uint32_t)atol(val2);
- }
-
- switch (ValueTypeDef[0]) {
- case 's':
- Value = db_get_sa(0, section, key);
- if (!Value || (Value && !mir_strcmpi(Value, val2)))
- Value = mir_strdup(val);
- else
- Value = mir_strdup(val2);
- db_set_s(0, section, key, Value);
- mir_free(Value);
- break;
-
- case 'd':
- curval = db_get_dw(0, section, key, l2);
- curval = (curval == l2) ? l1 : l2;
- db_set_dw(0, section, key, (uint32_t)curval);
- break;
-
- case 'w':
- curval = db_get_w(0, section, key, l2);
- curval = (curval == l2) ? l1 : l2;
- db_set_w(0, section, key, (uint16_t)curval);
- break;
-
- case 'b':
- curval = db_get_b(0, section, key, l2);
- curval = (curval == l2) ? l1 : l2;
- db_set_b(0, section, key, (uint8_t)curval);
- break;
- }
- mir_free(section);
- mir_free(val);
- }
- return 0;
-}
-
-static char *_skipblank(char * str) //str will be modified;
-{
- char * endstr = str + mir_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)
-{
- int paramCount = 0;
- int result = 0;
-
- char *pszService = mir_strdup(toParce);
- if (!pszService)
- return 0;
- if (mir_strlen(pszService) == 0) {
- mir_free(pszService);
- return 0;
- }
- char *param2 = strrchr(pszService, '%');
- if (param2) {
- paramCount++;
- *param2 = '\0'; param2++;
- _skipblank(param2);
- if (mir_strlen(param2) == 0)
- param2 = nullptr;
- }
- char *param1 = strrchr(pszService, '%');
- if (param1) {
- paramCount++;
- *param1 = '\0'; param1++;
- _skipblank(param1);
- if (mir_strlen(param1) == 0)
- param1 = nullptr;
- }
- if (param1 && *param1 == '\"') {
- param1++;
- *(param1 + mir_strlen(param1)) = '\0';
- }
- else if (param1) {
- param1 = (char*)atoi(param1);
- }
- if (param2 && *param2 == '\"') {
- param2++;
- *(param2 + mir_strlen(param2)) = '\0';
- }
- else if (param2)
- param2 = (char*)atoi(param2);
-
- if (paramCount == 1) {
- param1 = param2;
- param2 = nullptr;
- }
- if (!ServiceExists(pszService)) {
- result = 0;
- }
- else {
- result = 1;
- int 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) : nullptr;
- if (bct) {
- if (bct->HandleService && IsBadStringPtrA(bct->HandleService, 255))
- bct->HandleService = nullptr;
- else if (bct->HandleService && ServiceExists(bct->HandleService)) {
- HandleServiceParams MSG = {};
- 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 == nullptr)
- break;
-
- if (hwndToolTips) {
- mir_cslock lck(csTips);
- TOOLINFO ti = { 0 };
- 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 = nullptr;
- }
- }
- 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(nullptr, 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 = {};
- BeginPaint(hwndDlg, &ps);
- ModernSkinButtonPaintWorker(hwndDlg, (HDC)ps.hdc);
- EndPaint(hwndDlg, &ps);
- }
- return DefWindowProc(hwndDlg, msg, wParam, lParam);
-
- case WM_CAPTURECHANGED:
- if (bct) {
- bct->hover = 0;
- bct->down = 0;
- ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
- }
- break;
-
- case WM_MOUSEMOVE:
- if (bct) {
- if (!bct->hover) {
- SetCapture(bct->hwnd);
- bct->hover = 1;
- ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
- }
- else {
- POINT t = UNPACK_POINT(lParam);
- ClientToScreen(bct->hwnd, &t);
- if (WindowFromPoint(t) != bct->hwnd)
- ReleaseCapture();
- }
- }
- return 0;
-
- case WM_LBUTTONDOWN:
- if (bct) {
- bct->down = 1;
- SetForegroundWindow(GetParent(bct->hwnd));
- ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
- if (bct->CommandService && IsBadStringPtrA(bct->CommandService, 255))
- bct->CommandService = nullptr;
- if (bct->fCallOnPress) {
- if (bct->CommandService) {
- if (!_CallServiceStrParams(bct->CommandService, nullptr) && (bct->ValueDBSection && bct->ValueTypeDef))
- ModernSkinButtonToggleDBValue(bct->ValueDBSection, bct->ValueTypeDef);
- }
- bct->down = 0;
-
- ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
- }
- }
- return 0;
-
- case WM_LBUTTONUP:
- if (bct && bct->down) {
- ReleaseCapture();
- bct->hover = 0;
- bct->down = 0;
- ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
- if (bct->CommandService && IsBadStringPtrA(bct->CommandService, 255))
- bct->CommandService = nullptr;
- if (bct->CommandService)
- if (_CallServiceStrParams(bct->CommandService, nullptr)) {
- }
- else if (bct->ValueDBSection && bct->ValueTypeDef)
- ModernSkinButtonToggleDBValue(bct->ValueDBSection, bct->ValueTypeDef);
- }
- }
- return DefWindowProc(hwndDlg, msg, wParam, lParam);
-}
-
-HWND SetToolTip(HWND hwnd, wchar_t * tip)
-{
- TOOLINFO ti;
- if (!tip) return nullptr;
- mir_cslock lck(csTips);
- if (!hwndToolTips) {
- hwndToolTips = CreateWindowEx(0, TOOLTIPS_CLASS, nullptr,
- WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
- CW_USEDEFAULT, CW_USEDEFAULT,
- CW_USEDEFAULT, CW_USEDEFAULT,
- hwnd, nullptr, g_hMirApp, nullptr);
-
- SetWindowPos(hwndToolTips, HWND_TOPMOST, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
- }
-
- memset(&ti, 0, 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 = (wchar_t*)tip;
- SendMessage(hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)&ti);
-
- return hwndToolTips;
-}
-
-
-
-typedef struct _MButton
-{
- HWND hwnd;
- uint8_t 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 = nullptr;
-uint32_t 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,
- uint32_t sbFlags,
- wchar_t * 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 = nullptr;
- if (TypeDef && *TypeDef != '\0') bct->ValueTypeDef = mir_strdup(TypeDef); else bct->ValueTypeDef = mir_strdup("sDefault");
- bct->ID = mir_strdup(ID);
- bct->Hint = mir_wstrdup(Hint);
- Buttons[ButtonsCount].bct = bct;
- Buttons[ButtonsCount].hwnd = nullptr;
- Buttons[ButtonsCount].OrL = Left;
- Buttons[ButtonsCount].OrT = Top;
- Buttons[ButtonsCount].OrR = Right;
- Buttons[ButtonsCount].OrB = Bottom;
- Buttons[ButtonsCount].ConstrainPositionFrom = (uint8_t)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)
-{
- uint32_t 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 (g_clistApi.hwndContactList && Buttons[i].hwnd != nullptr) {
- //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 == nullptr) return FALSE;
- {
- wchar_t *UnicodeID = mir_a2u(bct->ID);
- hwnd = CreateWindow(_A2W(MODERNSKINBUTTONCLASS), UnicodeID, WS_VISIBLE | WS_CHILD, bct->Left, bct->Top, bct->Right - bct->Left, bct->Bottom - bct->Top, parent, nullptr, g_plugin.getInst(), nullptr);
- mir_free(UnicodeID);
- }
-
- bct->hwnd = hwnd;
- bct->focus = 0;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)bct);
- return hwnd;
-}
-
-int ModernSkinButtonRedrawAll()
-{
- if (!ModernSkinButtonModuleIsLoaded) return 0;
- g_mutex_bLockUpdating++;
- for (uint32_t i = 0; i < ButtonsCount; i++) {
- if (g_clistApi.hwndContactList && Buttons[i].hwnd == nullptr)
- Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct, g_clistApi.hwndContactList);
- ModernSkinButtonPaintWorker(Buttons[i].hwnd, nullptr);
- }
- 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, uint8_t draw, RECT *pRect)
-{
- RECT rc, clr, rd;
- BOOL altDraw = FALSE;
- static SIZE oldWndSize = { 0 };
- if (!ModernSkinButtonModuleIsLoaded) return 0;
- GetWindowRect(parent, &rd);
- GetClientRect(parent, &clr);
- if (!pRect)
- GetWindowRect(parent, &rc);
- else
- rc = *pRect;
-
- 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 (uint32_t i = 0; i < ButtonsCount; i++) {
- int sbFlags = Buttons[i].ConstrainPositionFrom;
- if (parent && Buttons[i].hwnd == nullptr) {
- Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct, parent);
- altDraw = FALSE;
- }
-
- int 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);
-
- int 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);
-
- int 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);
-
- int 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 || rc.bottom - rc.top < Buttons[i].minH)
- 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();
- return 0;
-}
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (C) 2012-23 Miranda NG team (https://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 "stdafx.h"
+#include "modern_clcpaint.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);
+HWND SetToolTip(HWND hwnd, wchar_t * tip);
+
+typedef struct _ModernSkinButtonCtrl
+{
+ HWND hwnd;
+ uint8_t down; // button state
+ uint8_t focus; // has focus (1 or 0)
+ uint8_t hover;
+ uint8_t IsSwitcher;
+ BOOL fCallOnPress;
+ char * ID;
+ char * CommandService;
+ char * StateService;
+ char * HandleService;
+ char * ValueDBSection;
+ char * ValueTypeDef;
+ int Left, Top, Bottom, Right;
+ HMENU hMenu;
+ wchar_t * Hint;
+
+} ModernSkinButtonCtrl;
+typedef struct _HandleServiceParams
+{
+ HWND hwnd;
+ uint32_t msg;
+ WPARAM wParam;
+ LPARAM lParam;
+ BOOL handled;
+} HandleServiceParams;
+
+static mir_cs csTips;
+static HWND hwndToolTips = nullptr;
+
+int ModernSkinButtonLoadModule()
+{
+ WNDCLASSEX wc;
+ memset(&wc, 0, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = _A2W(MODERNSKINBUTTONCLASS);
+ wc.lpfnWndProc = ModernSkinButtonWndProc;
+ wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wc.cbWndExtra = sizeof(ModernSkinButtonCtrl*);
+ wc.hbrBackground = nullptr;
+ wc.style = CS_GLOBALCLASS;
+ RegisterClassEx(&wc);
+ ModernSkinButtonModuleIsLoaded = TRUE;
+ return 0;
+}
+
+int ModernSkinButtonUnloadModule(WPARAM, LPARAM)
+{
+ return 0;
+}
+
+static int ModernSkinButtonPaintWorker(HWND hwnd, HDC whdc)
+{
+ HDC hdc;
+ RECT rc;
+ ModernSkinButtonCtrl* bct = (ModernSkinButtonCtrl *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (!bct) return 0;
+ if (!IsWindowVisible(hwnd)) return 0;
+ if (!whdc && !g_CluiData.fLayered) InvalidateRect(hwnd, nullptr, FALSE);
+
+ if (whdc && g_CluiData.fLayered) hdc = whdc;
+ else {
+ //sdc = GetWindowDC(GetParent(hwnd));
+ hdc = CreateCompatibleDC(nullptr);
+ }
+ GetClientRect(hwnd, &rc);
+ HBITMAP bmp = ske_CreateDIB32(rc.right, rc.bottom);
+ HBITMAP oldbmp = (HBITMAP)SelectObject(hdc, bmp);
+ if (!g_CluiData.fLayered)
+ ske_BltBackImage(bct->hwnd, hdc, nullptr);
+ {
+ MODERNMASK Request = {};
+ // int res;
+ //HBRUSH br = CreateSolidBrush(RGB(255,255,255));
+ char * Value = nullptr;
+ {
+ if (bct->ValueDBSection && bct->ValueTypeDef) {
+ char * key;
+ char * section;
+ uint32_t defval = 0;
+ char buf[20];
+ key = mir_strdup(bct->ValueDBSection);
+ section = key;
+ if (bct->ValueTypeDef[0] != 's')
+ defval = (uint32_t)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(0, section, key, bct->ValueTypeDef + 1);
+ break;
+ case 'd':
+ defval = db_get_dw(0, section, key, defval);
+ Value = mir_strdup(_ltoa(defval, buf, _countof(buf)));
+ break;
+ case 'w':
+ defval = db_get_w(0, section, key, defval);
+ Value = mir_strdup(_ltoa(defval, buf, _countof(buf)));
+ break;
+ case 'b':
+ defval = db_get_b(0, section, key, defval);
+ Value = mir_strdup(_ltoa(defval, buf, _countof(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);
+ }
+
+ 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 = 0, l2 = 0, curval;
+ // 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 = (uint32_t)atol(val);
+ l2 = (uint32_t)atol(val2);
+ }
+
+ switch (ValueTypeDef[0]) {
+ case 's':
+ Value = db_get_sa(0, section, key);
+ if (!Value || (Value && !mir_strcmpi(Value, val2)))
+ Value = mir_strdup(val);
+ else
+ Value = mir_strdup(val2);
+ db_set_s(0, section, key, Value);
+ mir_free(Value);
+ break;
+
+ case 'd':
+ curval = db_get_dw(0, section, key, l2);
+ curval = (curval == l2) ? l1 : l2;
+ db_set_dw(0, section, key, (uint32_t)curval);
+ break;
+
+ case 'w':
+ curval = db_get_w(0, section, key, l2);
+ curval = (curval == l2) ? l1 : l2;
+ db_set_w(0, section, key, (uint16_t)curval);
+ break;
+
+ case 'b':
+ curval = db_get_b(0, section, key, l2);
+ curval = (curval == l2) ? l1 : l2;
+ db_set_b(0, section, key, (uint8_t)curval);
+ break;
+ }
+ mir_free(section);
+ mir_free(val);
+ }
+ return 0;
+}
+
+static char *_skipblank(char * str) //str will be modified;
+{
+ char * endstr = str + mir_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)
+{
+ int paramCount = 0;
+ int result = 0;
+
+ char *pszService = mir_strdup(toParce);
+ if (!pszService)
+ return 0;
+ if (mir_strlen(pszService) == 0) {
+ mir_free(pszService);
+ return 0;
+ }
+ char *param2 = strrchr(pszService, '%');
+ if (param2) {
+ paramCount++;
+ *param2 = '\0'; param2++;
+ _skipblank(param2);
+ if (mir_strlen(param2) == 0)
+ param2 = nullptr;
+ }
+ char *param1 = strrchr(pszService, '%');
+ if (param1) {
+ paramCount++;
+ *param1 = '\0'; param1++;
+ _skipblank(param1);
+ if (mir_strlen(param1) == 0)
+ param1 = nullptr;
+ }
+ if (param1 && *param1 == '\"') {
+ param1++;
+ *(param1 + mir_strlen(param1)) = '\0';
+ }
+ else if (param1) {
+ param1 = (char*)atoi(param1);
+ }
+ if (param2 && *param2 == '\"') {
+ param2++;
+ *(param2 + mir_strlen(param2)) = '\0';
+ }
+ else if (param2)
+ param2 = (char*)atoi(param2);
+
+ if (paramCount == 1) {
+ param1 = param2;
+ param2 = nullptr;
+ }
+ if (!ServiceExists(pszService)) {
+ result = 0;
+ }
+ else {
+ result = 1;
+ int 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) : nullptr;
+ if (bct) {
+ if (bct->HandleService && IsBadStringPtrA(bct->HandleService, 255))
+ bct->HandleService = nullptr;
+ else if (bct->HandleService && ServiceExists(bct->HandleService)) {
+ HandleServiceParams MSG = {};
+ 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 == nullptr)
+ break;
+
+ if (hwndToolTips) {
+ mir_cslock lck(csTips);
+ TOOLINFO ti = { 0 };
+ 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 = nullptr;
+ }
+ }
+ 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(nullptr, 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 = {};
+ BeginPaint(hwndDlg, &ps);
+ ModernSkinButtonPaintWorker(hwndDlg, (HDC)ps.hdc);
+ EndPaint(hwndDlg, &ps);
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+
+ case WM_CAPTURECHANGED:
+ if (bct) {
+ bct->hover = 0;
+ bct->down = 0;
+ ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ if (bct) {
+ if (!bct->hover) {
+ SetCapture(bct->hwnd);
+ bct->hover = 1;
+ ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
+ }
+ else {
+ POINT t = UNPACK_POINT(lParam);
+ ClientToScreen(bct->hwnd, &t);
+ if (WindowFromPoint(t) != bct->hwnd)
+ ReleaseCapture();
+ }
+ }
+ return 0;
+
+ case WM_LBUTTONDOWN:
+ if (bct) {
+ bct->down = 1;
+ SetForegroundWindow(GetParent(bct->hwnd));
+ ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
+ if (bct->CommandService && IsBadStringPtrA(bct->CommandService, 255))
+ bct->CommandService = nullptr;
+ if (bct->fCallOnPress) {
+ if (bct->CommandService) {
+ if (!_CallServiceStrParams(bct->CommandService, nullptr) && (bct->ValueDBSection && bct->ValueTypeDef))
+ ModernSkinButtonToggleDBValue(bct->ValueDBSection, bct->ValueTypeDef);
+ }
+ bct->down = 0;
+
+ ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
+ }
+ }
+ return 0;
+
+ case WM_LBUTTONUP:
+ if (bct && bct->down) {
+ ReleaseCapture();
+ bct->hover = 0;
+ bct->down = 0;
+ ModernSkinButtonPaintWorker(bct->hwnd, nullptr);
+ if (bct->CommandService && IsBadStringPtrA(bct->CommandService, 255))
+ bct->CommandService = nullptr;
+ if (bct->CommandService)
+ if (_CallServiceStrParams(bct->CommandService, nullptr)) {
+ }
+ else if (bct->ValueDBSection && bct->ValueTypeDef)
+ ModernSkinButtonToggleDBValue(bct->ValueDBSection, bct->ValueTypeDef);
+ }
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
+
+HWND SetToolTip(HWND hwnd, wchar_t * tip)
+{
+ TOOLINFO ti;
+ if (!tip) return nullptr;
+ mir_cslock lck(csTips);
+ if (!hwndToolTips) {
+ hwndToolTips = CreateWindowEx(0, TOOLTIPS_CLASS, nullptr,
+ WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ hwnd, nullptr, g_hMirApp, nullptr);
+
+ SetWindowPos(hwndToolTips, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+
+ memset(&ti, 0, 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 = (wchar_t*)tip;
+ SendMessage(hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)&ti);
+
+ return hwndToolTips;
+}
+
+
+
+typedef struct _MButton
+{
+ HWND hwnd;
+ uint8_t 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 = nullptr;
+uint32_t 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,
+ uint32_t sbFlags,
+ wchar_t * 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 = nullptr;
+ if (TypeDef && *TypeDef != '\0') bct->ValueTypeDef = mir_strdup(TypeDef); else bct->ValueTypeDef = mir_strdup("sDefault");
+ bct->ID = mir_strdup(ID);
+ bct->Hint = mir_wstrdup(Hint);
+ Buttons[ButtonsCount].bct = bct;
+ Buttons[ButtonsCount].hwnd = nullptr;
+ Buttons[ButtonsCount].OrL = Left;
+ Buttons[ButtonsCount].OrT = Top;
+ Buttons[ButtonsCount].OrR = Right;
+ Buttons[ButtonsCount].OrB = Bottom;
+ Buttons[ButtonsCount].ConstrainPositionFrom = (uint8_t)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)
+{
+ uint32_t 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 (g_clistApi.hwndContactList && Buttons[i].hwnd != nullptr) {
+ //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 == nullptr) return FALSE;
+ {
+ wchar_t *UnicodeID = mir_a2u(bct->ID);
+ hwnd = CreateWindow(_A2W(MODERNSKINBUTTONCLASS), UnicodeID, WS_VISIBLE | WS_CHILD, bct->Left, bct->Top, bct->Right - bct->Left, bct->Bottom - bct->Top, parent, nullptr, g_plugin.getInst(), nullptr);
+ mir_free(UnicodeID);
+ }
+
+ bct->hwnd = hwnd;
+ bct->focus = 0;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)bct);
+ return hwnd;
+}
+
+int ModernSkinButtonRedrawAll()
+{
+ if (!ModernSkinButtonModuleIsLoaded) return 0;
+ g_mutex_bLockUpdating++;
+ for (uint32_t i = 0; i < ButtonsCount; i++) {
+ if (g_clistApi.hwndContactList && Buttons[i].hwnd == nullptr)
+ Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct, g_clistApi.hwndContactList);
+ ModernSkinButtonPaintWorker(Buttons[i].hwnd, nullptr);
+ }
+ 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, uint8_t draw, RECT *pRect)
+{
+ RECT rc, clr, rd;
+ BOOL altDraw = FALSE;
+ static SIZE oldWndSize = { 0 };
+ if (!ModernSkinButtonModuleIsLoaded) return 0;
+ GetWindowRect(parent, &rd);
+ GetClientRect(parent, &clr);
+ if (!pRect)
+ GetWindowRect(parent, &rc);
+ else
+ rc = *pRect;
+
+ 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 (uint32_t i = 0; i < ButtonsCount; i++) {
+ int sbFlags = Buttons[i].ConstrainPositionFrom;
+ if (parent && Buttons[i].hwnd == nullptr) {
+ Buttons[i].hwnd = ModernSkinButtonCreateWindow(Buttons[i].bct, parent);
+ altDraw = FALSE;
+ }
+
+ int 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);
+
+ int 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);
+
+ int 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);
+
+ int 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 || rc.bottom - rc.top < Buttons[i].minH)
+ 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();
+ return 0;
+}
diff --git a/plugins/Clist_modern/src/modern_skinengine.cpp b/plugins/Clist_modern/src/modern_skinengine.cpp
index cda79568be..faf1616152 100644
--- a/plugins/Clist_modern/src/modern_skinengine.cpp
+++ b/plugins/Clist_modern/src/modern_skinengine.cpp
@@ -1,3757 +1,3757 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (C) 2012-22 Miranda NG team (https://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 "stdafx.h"
-
-#define _EFFECTENUM_FULL_H
-#include "modern_effectenum.h"
-#undef _EFFECTENUM_FULL_H
-
-#include "modern_sync.h"
-
-//Implementation
-
-#pragma pack(push, 1)
-/* tga header */
-struct tga_header_t
-{
- uint8_t id_lenght; /* size of image id */
- uint8_t colormap_type; /* 1 is has a colormap */
- uint8_t image_type; /* compression type */
-
- short cm_first_entry; /* colormap origin */
- short cm_length; /* colormap length */
- uint8_t cm_size; /* colormap size */
-
- short x_origin; /* bottom left x coord origin */
- short y_origin; /* bottom left y coord origin */
-
- short width; /* picture width (in pixels) */
- short height; /* picture height (in pixels) */
-
- uint8_t pixel_depth; /* bits per pixel: 8, 16, 24 or 32 */
- uint8_t image_descriptor; /* 24 bits = 0x00; 32 bits = 0x80 */
-};
-#pragma pack(pop)
-
-/* Global variables */
-
-SKINOBJECTSLIST g_SkinObjectList = { 0 };
-CURRWNDIMAGEDATA *g_pCachedWindow = nullptr;
-
-bool g_bPostWasCanceled = false;
-bool g_bFullRepaint = false;
-
-int g_mutex_bLockUpdating = 0;
-
-SortedList *gl_plGlyphTexts = nullptr;
-SortedList *gl_plSkinFonts = nullptr;
-
-/* Private module variables */
-
-static HANDLE hSkinLoadedEvent;
-
-static GLYPHIMAGE *pLoadedImages = nullptr;
-static uint32_t dwLoadedImagesCount = 0;
-static uint32_t 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 = nullptr;
-static char **pszSettingName = nullptr;
-static int nArrayLen = 0;
-
-static uint8_t pbGammaWeight[256] = { 0 };
-static uint8_t pbGammaWeightAdv[256] = { 0 };
-static BOOL bGammaWeightFilled = FALSE;
-
-static mir_cs cs_SkinChanging;
-
-static LISTMODERNMASK *MainModernMaskList = nullptr;
-
-/* Private module procedures */
-static BOOL ske_GetMaskBit(uint8_t *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, uint32_t ARGBcolor);
-static void ske_AddParseTextGlyphObject(char * szGlyphTextID, char * szDefineString, SKINOBJECTSLIST *Skin);
-static void ske_AddParseSkinFont(char * szFontID, char * szDefineString);
-static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin);
-static SKINOBJECTDESCRIPTOR* ske_FindObject(const char *szName, SKINOBJECTSLIST *Skin);
-static int ske_LoadSkinFromResource(BOOL bOnlyObjects);
-static void ske_PreMultiplyChannels(HBITMAP hbmp, uint8_t 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 = { 0xFF, { 0 }, 0, 0 };
-
-//////////////////////////////////////////////////////////////////////////
-// Ini file parser
-
-IniParser::IniParser(wchar_t * tcsFileName, uint8_t flags) : _Flags(flags)
-{
- _DoInit();
- if (!tcsFileName) return;
-
- if (tcsFileName[0] == '%') {
- //TODO: Add parser of resource filename here
- _LoadResourceIni(g_plugin.getInst(), MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF");
- return;
- }
-
- _hFile = _wfopen(tcsFileName, L"r");
- if (_hFile != nullptr) {
- _eType = IT_FILE;
- _isValid = true;
- }
-}
-
-IniParser::IniParser(HINSTANCE hInst, const char * resourceName, const char * resourceType, uint8_t flags) : _Flags(flags)
-{
- _DoInit();
- _LoadResourceIni(hInst, resourceName, resourceType);
-}
-
-IniParser::~IniParser()
-{
- mir_free(_szSection);
- if (_hFile) fclose(_hFile);
- if (_hGlobalRes) {
- UnlockResource(_hGlobalRes);
- FreeResource(_hGlobalRes);
- }
-
- _szSection = nullptr;
- _hGlobalRes = nullptr;
- _hFile = nullptr;
- _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(0, szSection, szName, (uint8_t)atoi(szValue + 1));
- break;
-
- case 'w':
- db_set_w(0, szSection, szName, (uint16_t)atoi(szValue + 1));
- break;
-
- case 'd':
- db_set_dw(0, szSection, szName, (uint32_t)atoi(szValue + 1));
- break;
-
- case 's':
- db_set_s(0, szSection, szName, szValue + 1);
- break;
- }
- return S_OK;
-}
-
-int IniParser::GetSkinFolder(IN const wchar_t * szFileName, OUT wchar_t * pszFolderName)
-{
- wchar_t *szBuff = mir_wstrdup(szFileName);
- wchar_t *pszPos = szBuff + mir_wstrlen(szBuff);
- while (pszPos > szBuff && *pszPos != '.') { pszPos--; }
- *pszPos = '\0';
- mir_wstrcpy(pszFolderName, szBuff);
-
- wchar_t custom_folder[MAX_PATH], cus[MAX_PATH];
- wchar_t *b3;
- mir_wstrncpy(custom_folder, pszFolderName, _countof(custom_folder));
- b3 = custom_folder + mir_wstrlen(custom_folder);
- while (b3 > custom_folder && *b3 != '\\') { b3--; }
- *b3 = '\0';
-
- GetPrivateProfileString(L"Skin_Description_Section", L"SkinFolder", L"", cus, _countof(custom_folder), szFileName);
- if (cus[0] != 0)
- mir_snwprintf(pszFolderName, MAX_PATH, L"%s\\%s", custom_folder, cus);
-
- mir_free(szBuff);
- PathToRelativeW(pszFolderName, pszFolderName);
- return 0;
-}
-
-void IniParser::_DoInit()
-{
- _isValid = false;
- _eType = IT_UNKNOWN;
- _szSection = nullptr;
- _hFile = nullptr;
- _hGlobalRes = nullptr;
- _dwSizeOfRes = 0;
- _pPosition = nullptr;
- _pLineCallBackProc = nullptr;
- _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, _countof(szLine), _hFile) != nullptr) {
- 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 + mir_strlen(pStart);
- while (pEnd > pStart && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n' || *pEnd == '\r'))
- pEnd--;
-
- len = pEnd - pStart;
- return pStart;
-}
-
-BOOL IniParser::_DoParseLine(char *szLine)
-{
- _nLine++;
- size_t len = mir_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 = nullptr;
- {
- char *tbuf = szLine + 1; // skip [
-
- char *ebuf = tbuf;
-
- while (*ebuf != ']' && *ebuf != '\0') ebuf++;
- if (*ebuf == '\0')
- return FALSE; // no close bracket
-
- uint32_t sectionLen = ebuf - tbuf + 1;
- _szSection = (char*)mir_alloc(sectionLen + 1);
- mir_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;
-
- size_t eqPlace = 0, len2 = mir_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
- rtrim(keyName);
- while (*keyValue) {
- if (!isspace(*keyValue))
- break;
- keyValue++;
- }
- rtrim(keyValue);
- _pLineCallBackProc(_szSection, keyName, keyValue, this);
- }
- return TRUE;
-}
-//////////////////////////////////////////////////////////////////////////
-// End of IniParser
-//////////////////////////////////////////////////////////////////////////
-
-HRESULT SkinEngineLoadModule()
-{
- ModernSkinButtonLoadModule();
- MainModernMaskList = (LISTMODERNMASK*)mir_calloc(sizeof(LISTMODERNMASK));
- //init variables
- g_SkinObjectList.dwObjLPAlocated = 0;
- g_SkinObjectList.dwObjLPReserved = 0;
- g_SkinObjectList.pObjects = nullptr;
- // 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 (auto &it : arEffectStack)
- mir_free(it);
- 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(nullptr, g_pCachedWindow->hScreenDC);
- mir_free_and_nil(g_pCachedWindow);
- }
- 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);
- 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);
-}
-
-struct DCBUFFER
-{
- HDC hdcOwnedBy;
- int nUsageID;
- int width;
- int height;
- void *pImage;
- HDC hDC;
- HBITMAP oldBitmap;
- HBITMAP hBitmap;
- uint32_t 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);
-mir_cs BufferListCS;
-
-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 = nullptr;
- 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(uint32_t));
- }
- pBuf->dwDestroyAfterTime = 0;
- return pBuf->hDC;
-}
-
-int ske_ReleaseBufferDC(HDC hDC, int keepTime)
-{
- uint32_t dwCurrentTime = GetTickCount();
-
- // Try to find DC in buffer list - set flag to be release after time;
- mir_cslock lck(BufferListCS);
- for (auto &it : BufferList.rev_iter()) {
- if (it) {
- if (hDC != nullptr && it->hDC == hDC) {
- it->dwDestroyAfterTime = dwCurrentTime + keepTime;
- break;
- }
-
- if ((it->dwDestroyAfterTime && it->dwDestroyAfterTime < dwCurrentTime) || keepTime == -1) {
- SelectObject(it->hDC, it->oldBitmap);
- DeleteObject(it->hBitmap);
- DeleteDC(it->hDC);
- mir_free(BufferList.removeItem(&it));
- }
- }
- }
- return 0;
-}
-
-BOOL ske_SetRgnOpaque(HDC memdc, HRGN hrgn, BOOL force)
-{
- if (g_CluiData.fDisableSkinEngine && !force) return TRUE;
- uint32_t rgnsz = GetRegionData(hrgn, 0, nullptr);
- RGNDATA *rdata = (RGNDATA *)mir_alloc(rgnsz);
- GetRegionData(hrgn, rgnsz, rdata);
- RECT *rect = (RECT *)rdata->Buffer;
- for (uint32_t 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;
- uint8_t *bits;
- BITMAP bmp;
-
- if (g_CluiData.fDisableSkinEngine && !force)
- return TRUE;
-
- HBITMAP hbmp = (HBITMAP)GetCurrentObject(memdc, OBJ_BITMAP);
- GetObject(hbmp, sizeof(bmp), &bmp);
-
- if (bmp.bmPlanes != 1)
- return FALSE;
-
- if (!bmp.bmBits) {
- f = 1;
- bits = (uint8_t*)mir_alloc(bmp.bmWidthBytes*bmp.bmHeight);
- GetBitmapBits(hbmp, bmp.bmWidthBytes*bmp.bmHeight, bits);
- }
- else
- bits = (uint8_t*)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;
-
- uint8_t *pLine = ((uint8_t *)bits) + (bmp.bmHeight - sy - 1) * bmp.bmWidthBytes + (sx << 2) + 3;
- for (int y = 0; y < (ey - sy); y++) {
- uint8_t *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);
- mir_free(bits);
- }
- // DeleteObject(hbmp);
- return 1;
-}
-
-static BOOL ske_SkinFillRectByGlyph(HDC hDest, HDC hSource, RECT *rFill, RECT *rGlyph, RECT *rClip, uint8_t mode, uint8_t drawMode)
-{
- BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
-
- //initializations
- if (mode == FM_STRETCH) {
- HDC mem2dc = nullptr;
- HBITMAP mem2bmp = nullptr, oldbmp = nullptr;
- 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)) {
- RECT wr;
- IntersectRect(&wr, rClip, rFill);
- if ((wr.bottom - wr.top)*(wr.right - wr.left) == 0) return 0;
- HDC mem2dc = CreateCompatibleDC(hDest);
- //SetStretchBltMode(mem2dc, HALFTONE);
- HBITMAP mem2bmp = ske_CreateDIB32(wr.right - wr.left, rGlyph->bottom - rGlyph->top);
- HBITMAP oldbmp = (HBITMAP)SelectObject(mem2dc, mem2bmp);
- if (!oldbmp)
- return 0;
-
- /// draw here
- {
- int y = 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 = (wr.top - rFill->top) % h;
- if (dy >= 0) {
- y = wr.top;
- int 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 {
- BLENDFUNCTION bf2 = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
- int dy = (wr.top - rFill->top) % h;
- if (dy >= 0) {
- y = wr.top;
- int 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, bf2);
- }
-
- y = wr.top + h - dy;
- while (y < wr.bottom - h) {
- ske_AlphaBlend(hDest, wr.left, y, w, h, mem2dc, 0, 0, w, h, bf2);
- y += h;
- }
- if (y <= wr.bottom)
- ske_AlphaBlend(hDest, wr.left, y, w, wr.bottom - y, mem2dc, 0, 0, w, wr.bottom - y, bf2);
- }
- }
- }
- 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) {
- RECT wr;
- 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;
- HDC mem2dc = CreateCompatibleDC(hDest);
-
- HBITMAP mem2bmp = ske_CreateDIB32(w, h);
- HBITMAP oldbmp = (HBITMAP)SelectObject(mem2dc, mem2bmp);
-
- if (!oldbmp)
- return 0;
- /// draw here
- {
- int x = 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 = (wr.left - rFill->left) % w;
- if (dx >= 0) {
- x = wr.left;
- int 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 = (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 bf2 = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
- int dx = (wr.left - rFill->left) % w;
- if (dx >= 0) {
- x = wr.left;
- int 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, bf2);
- }
- x = wr.left + w - dx;
- while (x < wr.right - w) {
- ske_AlphaBlend(hDest, x, wr.top, w, h, mem2dc, 0, 0, w, h, bf2);
- x += w;
- }
- if (x <= wr.right)
- ske_AlphaBlend(hDest, x, wr.top, wr.right - x, h, mem2dc, 0, 0, wr.right - x, h, bf2);
- }
- }
- }
- SelectObject(mem2dc, oldbmp);
- DeleteObject(mem2bmp);
- DeleteDC(mem2dc);
- }
- else if (mode == FM_TILE_BOTH && (rGlyph->right - rGlyph->left > 0) && (rGlyph->bottom - rGlyph->top > 0)) {
- int w = rGlyph->right - rGlyph->left;
- int x = 0;
- int h = rFill->bottom - rFill->top;
- RECT wr;
- IntersectRect(&wr, rClip, rFill);
- if ((wr.bottom - wr.top)*(wr.right - wr.left) == 0) return 0;
- HDC mem2dc = CreateCompatibleDC(hDest);
- HBITMAP mem2bmp = ske_CreateDIB32(w, wr.bottom - wr.top);
- h = wr.bottom - wr.top;
- HBITMAP oldbmp = (HBITMAP)SelectObject(mem2dc, mem2bmp);
-#ifdef _DEBUG
- if (!oldbmp)
- (nullptr, "Tile bitmap not selected", "ERROR", MB_OK);
-#endif
- /// draw here
- {
- //fill temp bitmap
- {
- int dy = (wr.top - rFill->top) % (rGlyph->bottom - rGlyph->top);
- int 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 = (wr.left - rFill->left) % w;
- if (dx >= 0) {
- x = wr.left;
- int 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 = (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 bf2 = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
- int dx = (wr.left - rFill->left) % w;
- if (dx >= 0) {
- x = wr.left;
- int 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, bf2);
- }
- x = wr.left + w - dx;
- while (x < wr.right - w) {
- ske_AlphaBlend(hDest, x, wr.top, w, h, mem2dc, 0, 0, w, h, bf2);
- x += w;
- }
- if (x <= wr.right)
- ske_AlphaBlend(hDest, x, wr.top, wr.right - x, h, mem2dc, 0, 0, wr.right - x, h, bf2);
- }
- }
- }
- SelectObject(mem2dc, oldbmp);
- DeleteObject(mem2bmp);
- DeleteDC(mem2dc);
- }
- return 1;
-
-}
-
-HBITMAP ske_CreateDIB32(int cx, int cy)
-{
- return ske_CreateDIB32Point(cx, cy, nullptr);
-}
-
-HBITMAP ske_CreateDIB32Point(int cx, int cy, void **bits)
-{
- if (cx < 0 || cy < 0)
- return nullptr;
-
- 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(nullptr,
- &RGB32BitsBITMAPINFO,
- DIB_RGB_COLORS,
- (void **)&ptPixels,
- nullptr, 0);
- if ((DirectBitmap == nullptr || ptPixels == nullptr) && cx != 0 && cy != 0) {
-#ifdef _DEBUG
- MessageBoxA(nullptr, "Object not allocated. Check GDI object count", "ERROR", MB_OK | MB_ICONERROR);
- DebugBreak();
-#endif
- ;
- }
- else memset(ptPixels, 0, cx*cy * 4);
- if (bits != nullptr) *bits = ptPixels;
- return DirectBitmap;
-}
-
-HRGN ske_CreateOpaqueRgn(uint8_t Level, bool Opaque)
-{
- if (!g_pCachedWindow)
- return nullptr;
-
- RGBQUAD *buf = (RGBQUAD *)g_pCachedWindow->hImageDIBByte;
- if (buf == nullptr)
- return nullptr;
-
- unsigned int cRect = 64;
- PRGNDATA pRgnData = (PRGNDATA)mir_alloc(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)mir_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)mir_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(nullptr, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData);
- mir_free(pRgnData);
- return hRgn;
-}
-
-static int ske_DrawSkinObject(SKINDRAWREQUEST *preq, GLYPHOBJECT *pobj)
-{
- HDC memdc = nullptr, glyphdc = nullptr;
- int k = 0;
- //BITMAP bmp = {0};
- HBITMAP membmp = nullptr, oldbmp = nullptr, oldglyph = nullptr;
- uint8_t 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 == nullptr) {
- 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);
- oldglyph = (HBITMAP)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);
- }
-
- // 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);
- }
- // 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);
- }
- // 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);
- }
-
- // 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);
- }
-
-
- // 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);
- }
- // 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);
- }
-
- // 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);
- }
- // 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);
- }
- }
-
- }
-
- if ((k > 0 || k == -1) && mode == 2) {
- {
- BLENDFUNCTION bf = { AC_SRC_OVER, 0, pobj->dwAlpha, uint8_t(pobj->bmBitsPixel == 32 && pobj->Style != ST_BRUSH ? AC_SRC_ALPHA : 0) };
- 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) {
- HFONT hOldFont;
- for (int 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 = (SKINFONT*)gl_plSkinFonts->items[j];
- if (sf->szFontID && !mir_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(SKINOBJECTDESCRIPTOR *lpDescr, SKINOBJECTSLIST *Skin)
-{
- SKINOBJECTSLIST *sk = (Skin ? Skin : &g_SkinObjectList);
- if (!mir_strcmpi(lpDescr->szObjectID, "_HEADER_"))
- return 0;
- //check if new object allready presents.
- for (uint32_t i = 0; i < sk->dwObjLPAlocated; i++)
- if (!mir_strcmp(sk->pObjects[i].szObjectID, lpDescr->szObjectID))
- return 0;
- // Realocated list to add space for new object
- if (sk->dwObjLPAlocated + 1 > sk->dwObjLPReserved) {
- 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 = nullptr;
- sk->pObjects[sk->dwObjLPAlocated].szObjectID = mir_strdup(lpDescr->szObjectID);
- // sk->Objects[sk->dwObjLPAlocated].szObjectName = mir_strdup(lpDescr->szObjectName);
- if (lpDescr->Data != nullptr) { //Copy defaults values
- switch (lpDescr->bType) {
- case OT_GLYPHOBJECT:
- {
- GLYPHOBJECT *gl = (GLYPHOBJECT *)lpDescr->Data;
- sk->pObjects[sk->dwObjLPAlocated].Data = mir_alloc(sizeof(GLYPHOBJECT));
- GLYPHOBJECT *obdat = (GLYPHOBJECT *)sk->pObjects[sk->dwObjLPAlocated].Data;
- memcpy(obdat, gl, sizeof(GLYPHOBJECT));
- if (gl->szFileName != nullptr) {
- obdat->szFileName = mir_strdup(gl->szFileName);
- replaceStr(gl->szFileName, nullptr);
- }
- else obdat->szFileName = nullptr;
-
- obdat->hGlyph = nullptr;
- break;
- }
- }
-
- }
- }
- sk->dwObjLPAlocated++;
- return 1;
-}
-
-static SKINOBJECTDESCRIPTOR* ske_FindObject(const char *szName, SKINOBJECTSLIST *Skin)
-{
- SKINOBJECTSLIST *sk = (Skin == nullptr) ? (&g_SkinObjectList) : Skin;
- return skin_FindObjectByRequest((char *)szName, sk->pMaskList);
-}
-
-static SKINOBJECTDESCRIPTOR* ske_FindObjectByMask(MODERNMASK *pModernMask, SKINOBJECTSLIST *Skin)
-{
- SKINOBJECTSLIST *sk = (Skin == nullptr) ? (&g_SkinObjectList) : Skin;
- return sk->pMaskList ? skin_FindObjectByMask(pModernMask, sk->pMaskList) : nullptr;
-}
-
-SKINOBJECTDESCRIPTOR* ske_FindObjectByName(const char *szName, uint8_t objType, SKINOBJECTSLIST *Skin)
-{
- SKINOBJECTSLIST *sk = (Skin == nullptr) ? (&g_SkinObjectList) : Skin;
- for (uint32_t 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 nullptr;
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Paint glyph
-// wParam - LPSKINDRAWREQUEST
-// lParam - possible direct pointer to modern mask
-//////////////////////////////////////////////////////////////////////////
-
-INT_PTR ske_Service_DrawGlyph(WPARAM wParam, LPARAM lParam)
-{
- auto *preq = (SKINDRAWREQUEST *)wParam;
- if (preq == nullptr)
- return -1;
-
- mir_cslock lck(cs_SkinChanging);
-
- SKINOBJECTDESCRIPTOR *pgl = (lParam ? ske_FindObjectByMask((MODERNMASK*)lParam, nullptr) : ske_FindObject(preq->szObjectID, nullptr));
- if (pgl == nullptr) return -1;
- if (pgl->Data == nullptr) return -1;
-
- GLYPHOBJECT *gl = (GLYPHOBJECT*)pgl->Data;
- int iStyle = gl->Style & 7;
- if (iStyle == ST_SKIP)
- return ST_SKIP;
-
- if (gl->hGlyph == nullptr && 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 = (uint8_t)bmp.bmBitsPixel;
- gl->bmHeight = bmp.bmHeight;
- gl->bmWidth = bmp.bmWidth;
- }
- else gl->hGlyph = (HBITMAP)-1; //invalid
- }
- }
- return ske_DrawSkinObject(preq, gl);
-}
-
-
-void ske_PreMultiplyChannels(HBITMAP hbmp, uint8_t Mult)
-{
- BITMAP bmp;
- BOOL flag = FALSE;
- uint8_t *pBitmapBits;
- uint32_t 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 == nullptr);
- if (flag) {
- pBitmapBits = (LPBYTE)mir_alloc(Len);
- GetBitmapBits(hbmp, Len, pBitmapBits);
- }
- else
- pBitmapBits = (uint8_t *)bmp.bmBits;
- for (y = 0; y < bh; ++y) {
- uint8_t *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);
- mir_free(pBitmapBits);
- }
- return;
-}
-
-int ske_GetFullFilename(wchar_t *buf, const wchar_t *file, wchar_t *skinfolder, BOOL madeAbsolute)
-{
- wchar_t *SkinPlace = db_get_wsa(0, SKIN, "SkinFolder");
- if (SkinPlace == nullptr)
- SkinPlace = mir_wstrdup(L"\\Skin\\default");
-
- wchar_t b2[MAX_PATH];
- if (file[0] != '\\' && file[1] != ':')
- mir_snwprintf(b2, L"%s\\%s", (skinfolder == nullptr) ? SkinPlace : ((INT_PTR)skinfolder != -1) ? skinfolder : L"", file);
- else
- mir_wstrncpy(b2, file, _countof(b2));
-
- if (madeAbsolute) {
- if (b2[0] == '\\' && b2[1] != '\\')
- PathToAbsoluteW(b2 + 1, buf);
- else
- PathToAbsoluteW(b2, buf);
- }
- else mir_wstrncpy(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, uint32_t fromSize, uint8_t *destBuf, uint32_t bufSize, BOOL RLE)
-{
- uint8_t *pos = destBuf;
- uint8_t *from = fromSize ? (uint8_t *)From : nullptr;
- FILE *fp = !fromSize ? (FILE *)From : nullptr;
- uint32_t destCount = 0;
- uint32_t fromCount = 0;
- if (!RLE) {
- while (((from && fromCount < fromSize) || (fp && fromCount < bufSize))
- && (destCount < bufSize)) {
- uint8_t r = from ? from[fromCount++] : (uint8_t)fgetc(fp);
- uint8_t g = from ? from[fromCount++] : (uint8_t)fgetc(fp);
- uint8_t b = from ? from[fromCount++] : (uint8_t)fgetc(fp);
- uint8_t a = from ? from[fromCount++] : (uint8_t)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 {
- uint8_t rgba[4];
- uint8_t packet_header;
- uint8_t *ptr = pos;
- uint8_t size;
- int i;
- while (ptr < pos + bufSize) {
- /* read first byte */
- packet_header = from ? from[fromCount] : (uint8_t)fgetc(fp);
- if (from) from++;
- size = 1 + (packet_header & 0x7f);
- if (packet_header & 0x80) {
- /* run-length packet */
- if (from) {
- *((uint32_t*)rgba) = *((uint32_t*)(from + fromCount));
- fromCount += 4;
- }
- else fread(rgba, sizeof(uint8_t), 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++] : (uint8_t)fgetc(fp);
- ptr[1] = from ? from[fromCount++] : (uint8_t)fgetc(fp);
- ptr[2] = from ? from[fromCount++] : (uint8_t)fgetc(fp);
- ptr[3] = from ? from[fromCount++] : (uint8_t)fgetc(fp);
- }
- }
- }
- }
- return TRUE;
-}
-
-static HBITMAP ske_LoadGlyphImage_TGA(const wchar_t *szFilename)
-{
- uint8_t *colormap = nullptr;
- int cx = 0, cy = 0;
- BOOL err = FALSE;
- tga_header_t header;
- if (!szFilename) return nullptr;
- if (!wildcmpiw(szFilename, L"*\\*%.tga")) {
- //Loading TGA image from file
- FILE *fp = _wfopen(szFilename, L"rb");
- if (!fp) {
- TRACEVAR("error: couldn't open \"%s\"!\n", szFilename);
- return nullptr;
- }
- /* 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 nullptr;
- }
-
- /*memory allocation */
- colormap = (uint8_t*)mir_alloc(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 */
- HRSRC hRSrc = FindResourceA(g_plugin.getInst(), MAKEINTRESOURCEA(IDR_TGA_DEFAULT_SKIN), "TGA");
- if (!hRSrc) return nullptr;
- HGLOBAL hRes = LoadResource(g_plugin.getInst(), hRSrc);
- if (!hRes) return nullptr;
- uint32_t size = SizeofResource(g_plugin.getInst(), hRSrc);
- uint8_t *mem = (uint8_t*)LockResource(hRes);
- if (size > sizeof(header)) {
- tga_header_t *tgahdr = (tga_header_t*)mem;
- if (tgahdr->pixel_depth == 32 && (tgahdr->image_type == 2 || tgahdr->image_type == 10)) {
- colormap = (uint8_t*)mir_alloc(tgahdr->width*tgahdr->height * 4);
- cx = tgahdr->width;
- cy = tgahdr->height;
- ske_ReadTGAImageData((void*)(mem + sizeof(tga_header_t) + tgahdr->id_lenght + tgahdr->cm_length), size - (sizeof(tga_header_t) + tgahdr->id_lenght + tgahdr->cm_length), colormap, cx*cy * 4, tgahdr->image_type == 10);
- }
- }
- FreeResource(hRes);
- }
-
- if (colormap == nullptr)
- return nullptr;
-
- // create dib section
- uint8_t *pt;
- HBITMAP hbmp = ske_CreateDIB32Point(cx, cy, (void**)&pt);
- if (hbmp)
- memcpy(pt, colormap, cx*cy * 4);
- mir_free(colormap);
- return hbmp;
-}
-
-static HBITMAP ske_LoadGlyphImageByDecoders(const wchar_t *tszFileName)
-{
- if (!wcschr(tszFileName, '%') && !PathFileExists(tszFileName))
- return nullptr;
-
- const wchar_t *ext = wcsrchr(tszFileName, '.');
- if (ext == nullptr)
- return nullptr;
-
- BITMAP bmpInfo;
- HBITMAP hBitmap;
- bool f = false;
-
- if (!mir_wstrcmpi(ext, L".tga")) {
- hBitmap = ske_LoadGlyphImage_TGA(tszFileName);
- f = true;
- }
- else hBitmap = Bitmap_Load(tszFileName);
-
- if (hBitmap == nullptr)
- return nullptr;
-
- GetObject(hBitmap, sizeof(BITMAP), &bmpInfo);
- if (bmpInfo.bmBitsPixel == 32)
- ske_PreMultiplyChannels(hBitmap, f);
- else {
- HDC dc32 = CreateCompatibleDC(nullptr);
- HDC dc24 = CreateCompatibleDC(nullptr);
- HBITMAP hBitmap32 = ske_CreateDIB32(bmpInfo.bmWidth, bmpInfo.bmHeight);
- HBITMAP obmp24 = (HBITMAP)SelectObject(dc24, hBitmap);
- 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_PreMultiplyChannels(hBitmap, 0);
- }
- return hBitmap;
-}
-
-static HBITMAP ske_skinLoadGlyphImage(const wchar_t *tszFileName)
-{
- if (!wildcmpiw(tszFileName, L"*.tga"))
- return GDIPlus_LoadGlyphImage(tszFileName);
-
- return ske_LoadGlyphImageByDecoders(tszFileName);
-}
-
-HBITMAP ske_LoadGlyphImage(const wchar_t *tszFileName)
-{
- // try to find image in loaded
- wchar_t szFile[MAX_PATH] = { 0 };
- ske_GetFullFilename(szFile, tszFileName, g_SkinObjectList.szSkinPlace, TRUE);
-
- mir_cslock lck(cs_SkinChanging);
-
- if (pLoadedImages) {
- for (uint32_t i = 0; i < dwLoadedImagesCount; i++) {
- if (!mir_wstrcmpi(pLoadedImages[i].szFileName, szFile)) {
- pLoadedImages[i].dwLoadedTimes++;
- return pLoadedImages[i].hGlyph;
- }
- }
- }
-
- // load new image
- HBITMAP hbmp = ske_skinLoadGlyphImage(szFile);
- if (hbmp == nullptr)
- return nullptr;
-
- // add to loaded list
- if (dwLoadedImagesCount + 1 > dwLoadedImagesAlocated) {
- pLoadedImages = (GLYPHIMAGE*)mir_realloc(pLoadedImages, sizeof(GLYPHIMAGE)*(dwLoadedImagesCount + 1));
- if (!pLoadedImages)
- return nullptr;
- dwLoadedImagesAlocated++;
- }
-
- pLoadedImages[dwLoadedImagesCount].dwLoadedTimes = 1;
- pLoadedImages[dwLoadedImagesCount].hGlyph = hbmp;
- pLoadedImages[dwLoadedImagesCount].szFileName = mir_wstrdup(szFile);
- dwLoadedImagesCount++;
- return hbmp;
-}
-
-int ske_UnloadGlyphImage(HBITMAP hbmp)
-{
- for (uint32_t i = 0; i < dwLoadedImagesCount && pLoadedImages; i++) {
- if (hbmp != pLoadedImages[i].hGlyph)
- continue;
-
- pLoadedImages[i].dwLoadedTimes--;
- if (pLoadedImages[i].dwLoadedTimes == 0) {
- LPGLYPHIMAGE gl = &(pLoadedImages[i]);
- replaceStrW(gl->szFileName, nullptr);
- 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)
-{
- 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);
- }
-
- replaceStrW(Skin->szSkinPlace, nullptr);
- if (Skin->pTextList) List_Destroy(Skin->pTextList);
- mir_free_and_nil(Skin->pTextList);
- ModernSkinButtonDeleteAll();
- if (Skin->dwObjLPAlocated == 0)
- return 0;
-
- for (uint32_t i = 0; i < Skin->dwObjLPAlocated; i++) {
- switch (Skin->pObjects[i].bType) {
- case OT_GLYPHOBJECT:
- GLYPHOBJECT *dt = (GLYPHOBJECT*)Skin->pObjects[i].Data;
- if (dt->hGlyph && dt->hGlyph != (HBITMAP)-1)
- ske_UnloadGlyphImage(dt->hGlyph);
- dt->hGlyph = nullptr;
- replaceStr(dt->szFileName, nullptr);
-
- if (dt->plTextList && dt->plTextList->realCount > 0) {
- for (int k = 0; k < dt->plTextList->realCount; k++) {
- GLYPHTEXT *gt = (GLYPHTEXT *)dt->plTextList->items[k];
- 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;
- }
- replaceStr(Skin->pObjects[i].szObjectID, nullptr);
- }
- mir_free_and_nil(Skin->pObjects);
- Skin->pTextList = nullptr;
- Skin->dwObjLPAlocated = 0;
- Skin->dwObjLPReserved = 0;
- return 0;
-}
-
-static void RegisterMaskByParce(const char *szSetting, char *szValue, SKINOBJECTSLIST *pSkin)
-{
- size_t i, val_len = mir_strlen(szValue);
-
- for (i = 0; i < val_len; i++)
- if (szValue[i] == ':')
- break;
-
- if (i < val_len) {
- char *Obj, *Mask;
- int res;
- uint32_t ID = atoi(szSetting + 1);
- Mask = szValue + i + 1;
- Obj = (char*)mir_alloc(i + 2);
- mir_strncpy(Obj, szValue, i + 1);
- Obj[i + 1] = '\0';
- res = AddStrModernMaskToList(ID, Mask, Obj, pSkin->pMaskList);
- 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);
- else return 0;
- return 1;
-}
-
-static int ske_enumdb_SkinObjectsProc(const char *szSetting, void *)
-{
- ptrA value(db_get_sa(0, SKIN, szSetting));
- ske_ProcessLoadindString(szSetting, value);
- return 0;
-}
-
-static int ske_SortTextGlyphObjectFunc(void *first, void *second)
-{
- GLYPHTEXT *p1 = *(GLYPHTEXT**)first, *p2 = *(GLYPHTEXT**)second;
- return mir_strcmp(p1->szGlyphTextID, p2->szGlyphTextID);
-}
-
-static void ske_LinkSkinObjects(SKINOBJECTSLIST *pObjectList)
-{
- // LINK Mask with objects
- for (uint32_t 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);
- replaceStr(mm->szObjectName, nullptr);
- mm->bObjectFound = TRUE;
- mm->pObject = pObject;
- }
-
- if (pObjectList->pTextList) {
- // LINK Text with objects
- for (int i = 0; i < pObjectList->pTextList->realCount; i++) {
- GLYPHTEXT *glText = (GLYPHTEXT *)pObjectList->pTextList->items[i];
- SKINOBJECTDESCRIPTOR *lpobj = ske_FindObjectByName(glText->szObjectName, OT_GLYPHOBJECT, pObjectList);
- replaceStr(glText->szObjectName, nullptr);
- GLYPHOBJECT *globj = nullptr;
- 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(GLYPHTEXT*), (int(*)(const void*, const void*))globj->plTextList->sortFunc);
- pObjectList->pTextList->items[i] = nullptr;
- }
- 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 *, SKINOBJECTSLIST *Skin)
-{
- if (Skin == nullptr) return 0;
- ske_UnloadSkin(Skin);
- g_CluiData.fDisableSkinEngine = db_get_b(0, "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;
- return 0;
- }
-
- // window borders
- g_CluiData.LeftClientMargin = (int)db_get_b(0, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT);
- g_CluiData.RightClientMargin = (int)db_get_b(0, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT);
- g_CluiData.TopClientMargin = (int)db_get_b(0, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT);
- g_CluiData.BottomClientMargin = (int)db_get_b(0, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT);
-
- Skin->pMaskList = (LISTMODERNMASK*)mir_alloc(sizeof(LISTMODERNMASK));
- memset(Skin->pMaskList, 0, sizeof(LISTMODERNMASK));
- Skin->szSkinPlace = db_get_wsa(0, SKIN, "SkinFolder");
- if (!Skin->szSkinPlace || (wcschr(Skin->szSkinPlace, '%') && !db_get_b(0, SKIN, "Modified", 0))) {
- BOOL bOnlyObjects = FALSE;
- if (Skin->szSkinPlace && wcschr(Skin->szSkinPlace, '%'))
- bOnlyObjects = TRUE;
- mir_free(Skin->szSkinPlace);
- Skin->szSkinPlace = mir_wstrdup(L"%Default%");
- ske_LoadSkinFromResource(bOnlyObjects);
- }
-
- // Load objects
- pCurrentSkin = Skin;
- db_enum_settings(0, ske_enumdb_SkinObjectsProc, SKIN);
-
- 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(0, "ModernSettings", "KeyColor", (uint32_t)SETTING_KEYCOLOR_DEFAULT);
-}
-
-static int ske_LoadSkinFromResource(BOOL bOnlyObjects)
-{
- IniParser parser(g_plugin.getInst(), MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF", bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
- if (parser.CheckOK()) {
- db_delete_module(0, "ModernSkin");
- db_set_s(0, SKIN, "SkinFolder", "%Default%");
- db_set_s(0, SKIN, "SkinFile", "%Default%");
- parser.Parse(IniParser::WriteStrToDb, 0);
- }
- return 0;
-}
-
-// Load data from ini file
-int ske_LoadSkinFromIniFile(wchar_t *szFileName, BOOL bOnlyObjects)
-{
- if (wcschr(szFileName, '%'))
- return ske_LoadSkinFromResource(bOnlyObjects);
-
- IniParser parser(szFileName, bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
- if (!parser.CheckOK())
- return 0;
-
- db_delete_module(0, "ModernSkin");
-
- wchar_t skinFolder[MAX_PATH], skinFile[MAX_PATH];
- IniParser::GetSkinFolder(szFileName, skinFolder);
- PathToRelativeW(szFileName, skinFile);
-
- db_set_ws(0, SKIN, "SkinFolder", skinFolder);
- db_set_ws(0, SKIN, "SkinFile", skinFile);
-
- parser.Parse(IniParser::WriteStrToDb, 1);
- return 0;
-}
-
-BOOL ske_TextOut(HDC hdc, int x, int y, LPCTSTR lpString, int nCount)
-{
- SIZE sz;
- GetTextExtentPoint32(hdc, lpString, nCount, &sz);
-
- 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)
-{
- 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;
-}
-
-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, uint8_t EffectID, uint32_t FirstColor, uint32_t SecondColor)
-{
- if (EffectID > MAXPREDEFINEDEFFECTS)
- return false;
-
- if (EffectID == -1)
- return ske_ResetTextEffect(hdc);
-
- EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc);
- if (effect == nullptr) {
- 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 == nullptr)
- 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(uint8_t *destPt, uint8_t *maskPt, uint32_t width, uint32_t height, MODERNEFFECT *effect)
-{
- sbyte *buf;
- sbyte *outbuf;
- sbyte *bufline, *buflineTop, *buflineMid;
- int sign = 0;
- uint8_t *maskline, *destline;
- uint8_t al, rl, gl, bl, ad, rd, gd, bd;
- int k = 0;
- uint32_t x, y;
- sbyte *matrix;
- uint8_t mcTopStart;
- uint8_t mcBottomEnd;
- uint8_t mcLeftStart;
- uint8_t mcRightEnd;
- uint8_t 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*)mir_alloc(width*height*sizeof(uint8_t));
- {
- 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 - ((uint8_t)(effect->EffectColor1 >> 24));
- rl = GetRValue(effect->EffectColor1);
- gl = GetGValue(effect->EffectColor1);
- bl = GetBValue(effect->EffectColor1);
- ad = 255 - ((uint8_t)(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++) {
- uint8_t a = (sbyte)(uint32_t)((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*)mir_alloc(width*height*sizeof(sbyte));
- memset(outbuf, 0, width*height*sizeof(sbyte));
- for (y = (uint32_t)minY; y < (uint32_t)maxY; y++) {
- int val;
- bufline = outbuf + y*width + minX;
- buflineMid = buf + y*width + minX;
- for (x = (uint32_t)minX; x < (uint32_t)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 = nullptr;
- if (as >= 0 && (uint32_t)as < height) buflineTopS = buflineMid + buflineStep;
-
- for (matrixHor = mcLeftStart; matrixHor < mcRightEnd; matrixHor++) {
- buflineTop = buflineTopS;
- int a = x + matrixHor - 2;
- if (buflineTop && a >= 0 && (uint32_t)a < width) buflineTop += matrixHor - 2;
- else buflineTop = nullptr;
- if (buflineTop)
- val += ((*buflineTop)*matrix[matrixVer * 5 + matrixHor]);
- }
- }
- val = (val + 1) >> 5;
- *bufline = (sbyte)((val>127) ? 127 : (val < -125) ? -125 : val);
- bufline++;
- buflineMid++;
- }
- }
- mir_free(buf);
- buf = outbuf;
- }
- {
- uint8_t 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;
- uint8_t 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;
- }
- }
- mir_free(buf);
- }
- return false;
-}
-
-static int ske_AlphaTextOut(HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, uint32_t ARGBcolor)
-{
- if (!(lpString && lpRect))
- return 0;
-
- // Step first fill fast calc correction tables:
- static bool _tables_empty = true;
- static uint8_t gammaTbl[256]; // Gamma correction table
- static uint16_t blueMulTbl[256]; // blue coefficient multiplication table
- static uint16_t greenMulTbl[256]; // green coefficient multiplication table
- static uint16_t redMulTbl[256]; // red coefficient multiplication table
- if (_tables_empty) {
- // fill tables
- double gammaCfPw = 1000 / (double)DBGetContactSettingRangedWord(0, "ModernData", "AlphaTextOutGamma", 700, 1, 5000);
- uint8_t blueCf = db_get_b(0, "ModernData", "AlphaTextOutBlueCorrection", 28);
- uint8_t redCf = db_get_b(0, "ModernData", "AlphaTextOutRed Correction", 77);
- uint8_t greenCf = db_get_b(0, "ModernData", "AlphaTextOutGreen Correction", 151);
-
- for (int i = 0; i < 256; i++) {
- gammaTbl[i] = (uint8_t)(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 = (int)mir_wstrlen(lpString);
-
- // retrieve destination bitmap bits
- HBITMAP hDestBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
- BITMAP bmpDest;
- GetObject(hDestBitmap, sizeof(BITMAP), &bmpDest);
-
- bool destHasNotDIB = (bmpDest.bmBits == nullptr);
- uint8_t *pDestBits;
- if (destHasNotDIB) {
- pDestBits = (uint8_t*)mir_alloc(bmpDest.bmHeight * bmpDest.bmWidthBytes);
- GetBitmapBits(hDestBitmap, bmpDest.bmHeight*bmpDest.bmWidthBytes, pDestBits);
- }
- else
- pDestBits = (uint8_t*)bmpDest.bmBits;
-
- // 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) {
- if (destHasNotDIB)
- mir_free(pDestBits);
- 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, nullptr, &textSize);
- else
- GetTextExtentExPoint(hOffscreenDC, lpString, nCount, 0, &visibleCharCount, nullptr, &textSize);
-
- // replace end of string by elipsis
- bNeedFreeWorkString = TRUE;
- lpWorkString = (wchar_t*)mir_alloc((visibleCharCount + 4) * sizeof(wchar_t));
-
- memcpy((void*)lpWorkString, lpString, visibleCharCount * sizeof(wchar_t));
- memcpy((void*)(lpWorkString + visibleCharCount), L"...", 4 * sizeof(wchar_t)); // 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
- uint8_t *bits = nullptr;
- HBITMAP hbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bits);
- if (bits != nullptr) {
- HBITMAP holdbmp = (HBITMAP)SelectObject(hOffscreenDC, hbmp);
-
- //Create buffer bitmap image for temp text
- uint8_t *bufbits = nullptr;
- HBITMAP bufbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bufbits);
- if (bufbits != nullptr) {
- 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;
-
- uint32_t width = textSize.cx;
- uint32_t heigh = textSize.cy;
-
- uint8_t *pDestScanLine, *pBufScanLine, *pix, *bufpix;
-
- uint8_t al = 255 - ((uint8_t)(ARGBcolor >> 24));
- uint8_t r = GetRValue(ARGBcolor);
- uint8_t g = GetGValue(ARGBcolor);
- uint8_t b = GetBValue(ARGBcolor);
-
- for (uint32_t y = 2; y < heigh - 2; y++) {
- int lineBytes = y * (width << 2);
-
- pDestScanLine = bits + lineBytes;
- pBufScanLine = bufbits + lineBytes;
-
- for (uint32_t x = 2; x < width - 2; x++) {
- pix = pDestScanLine + (x << 2);
- bufpix = pBufScanLine + (x << 2);
-
- // Monochromatic
- uint8_t bx = gammaTbl[bufpix[0]];
- uint8_t gx = gammaTbl[bufpix[1]];
- uint8_t rx = gammaTbl[bufpix[2]];
-
- if (al != 255) {
- bx *= al / 255;
- gx *= al / 255;
- rx *= al / 255;
- }
-
- uint8_t ax = (uint8_t)(((uint32_t)rx * 77 + (uint32_t)gx * 151 + (uint32_t)bx * 28 + 128) / 256);
- if (ax) {
- //Normalize components to gray
- uint8_t axx = 255 - ((r + g + b) >> 2); // Coefficient of grayance, more white font - more gray edges
- uint16_t 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] = (uint8_t)(ax + (uint8_t)(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)
- mir_free(pDestBits);
-
- if (bNeedFreeWorkString)
- mir_free((void*)lpWorkString);
-
- return 0;
-}
-
-static int ske_DrawTextWithEffectWorker(HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, FONTEFFECT *effect)
-{
- if (format & DT_CALCRECT)
- return DrawText(hdc, lpString, nCount, lpRect, format);
-
- if (format & DT_RTLREADING)
- SetTextAlign(hdc, TA_RTLREADING);
-
- uint32_t color = GetTextColor(hdc);
- RECT r = *lpRect;
- OffsetRect(&r, 1, 1);
- uint32_t 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)
-{
- DrawTextWithEffectParam *p = (DrawTextWithEffectParam *)wParam;
- 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)
-{
- 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);
-
- uint32_t form = format;
- uint32_t color = GetTextColor(hdc);
- return ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color);
-}
-
-HICON ske_ImageList_GetIcon(HIMAGELIST himl, int i)
-{
- IMAGEINFO imi = {};
- BITMAP bm = { 0 };
- if (i != -1) {
- ImageList_GetImageInfo(himl, i, &imi);
- GetObject(imi.hbmImage, sizeof(bm), &bm);
- // 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
- if (bm.bmBitsPixel == 32) {
- uint8_t *bits = (uint8_t*)bm.bmBits;
- if (!bits) {
- bits = (uint8_t*)mir_alloc(bm.bmWidthBytes*bm.bmHeight);
- GetBitmapBits(imi.hbmImage, bm.bmWidthBytes*bm.bmHeight, bits);
- }
-
- uint8_t *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
- uint32_t *c = ((uint32_t*)bcbits);
- for (x = 0; x < imi.rcImage.right - imi.rcImage.left; x++) {
- uint32_t val = *c;
- uint8_t a = (uint8_t)((val) >> 24);
- if (a != 0) {
- uint8_t r = (uint8_t)((val & 0xFF0000) >> 16);
- uint8_t g = (uint8_t)((val & 0xFF00) >> 8);
- uint8_t b = (uint8_t)(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);
- mir_free(bits);
- }
- }
- }
- return ImageList_GetIcon(himl, i, ILD_NORMAL);
-}
-
-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);
-
- uint8_t alpha;
- if (fStyle & ILD_BLEND25)
- alpha = 64;
- else if (fStyle & ILD_BLEND50)
- alpha = 128;
- else
- alpha = 255;
-
- HICON hIcon = ske_ImageList_GetIcon(himl, i);
- if (hIcon == nullptr)
- return FALSE;
-
- ske_DrawIconEx(hdcDst, x, y, hIcon, dx ? dx : GetSystemMetrics(SM_CXSMICON), dy ? dy : GetSystemMetrics(SM_CYSMICON), 0, nullptr, DI_NORMAL | (alpha << 24));
- DestroyIcon(hIcon);
- return TRUE;
-}
-
-static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, 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;
- uint8_t alpha = (uint8_t)((diFlags & 0xFF000000) >> 24);
-
- HBITMAP tBmp = nullptr;
- uint8_t *imbits, *imimagbits, *immaskbits;
- uint8_t *t1, *t2, *t3;
-
- //lockimagelist
- uint8_t hasmask = FALSE, no32bit = FALSE, noMirrorMask = FALSE, 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;
-
- BITMAP imbt;
- GetObject(ici.hbmColor, sizeof(BITMAP), &imbt);
- if (imbt.bmWidth*imbt.bmHeight == 0) {
- DeleteObject(ici.hbmColor);
- DeleteObject(ici.hbmMask);
- return 0;
- }
-
- BITMAP immaskbt;
- GetObject(ici.hbmMask, sizeof(BITMAP), &immaskbt);
- uint32_t cy = imbt.bmHeight;
-
- if (imbt.bmBitsPixel != 32) {
- no32bit = TRUE;
- HDC tempDC1 = CreateCompatibleDC(hdcDst);
- tBmp = ske_CreateDIB32(imbt.bmWidth, imbt.bmHeight);
- if (tBmp) {
- GetObject(tBmp, sizeof(BITMAP), &imbt);
- HBITMAP 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);
- }
-
- bool NoDIBImage = (imbt.bmBits == nullptr);
- if (NoDIBImage) {
- imimagbits = (uint8_t*)mir_alloc(cy*imbt.bmWidthBytes);
- GetBitmapBits(ici.hbmColor, cy*imbt.bmWidthBytes, (void*)imimagbits);
- }
- else imimagbits = (uint8_t*)imbt.bmBits;
-
- if (immaskbt.bmBits == nullptr) {
- immaskbits = (uint8_t*)mir_alloc(cy*immaskbt.bmWidthBytes);
- GetBitmapBits(ici.hbmMask, cy*immaskbt.bmWidthBytes, (void*)immaskbits);
- }
- else immaskbits = (uint8_t*)immaskbt.bmBits;
-
- HDC imDC = CreateCompatibleDC(hdcDst);
- uint32_t icy = imbt.bmHeight;
- uint32_t cx = imbt.bmWidth;
- HBITMAP imBmp = ske_CreateDIB32Point(cx, icy, (void**)&imbits);
- HBITMAP oldBmp = (HBITMAP)SelectObject(imDC, imBmp);
- if (imbits != nullptr && imimagbits != nullptr && immaskbits != nullptr) {
- int x, y;
- int mwb = immaskbt.bmWidthBytes;
- int mwb2 = imbt.bmWidthBytes;
- int bottom = icy;
- int right = cx;
- int top = 0;
- int 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++) {
- uint8_t mask = 0;
- uint8_t a = 0;
- uint32_t *src = (uint32_t*)(t1 + (x << 2));
- uint32_t *dest = (uint32_t*)(t2 + (x << 2));
- if (hasalpha && !hasmask)
- a = ((uint8_t*)src)[3];
- else {
- mask = ((1 << (7 - x % 8))&(*(t3 + (x >> 3)))) != 0;
- if (mask) {
- if (!hasalpha) {
- *dest = 0;
- continue;
- }
-
- if (((uint8_t*)src)[3]>0)
- a = ((uint8_t*)src)[3];
- else
- a = 0;
- }
- else if (hasalpha || hasmask)
- a = (((uint8_t*)src)[3] > 0 ? ((uint8_t*)src)[3] : 255);
- else if (!hasalpha && !hasmask)
- a = 255;
- else { *dest = 0; continue; }
- }
- if (a > 0) {
- ((uint8_t*)dest)[3] = a;
- ((uint8_t*)dest)[0] = ((uint8_t*)src)[0] * a / 255;
- ((uint8_t*)dest)[1] = ((uint8_t*)src)[1] * a / 255;
- ((uint8_t*)dest)[2] = ((uint8_t*)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 == nullptr) mir_free(immaskbits);
- if (imbt.bmBits == nullptr) mir_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, nullptr);
- CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, 0, 0);
- }
- else RedrawWindow(g_clistApi.hwndContactList, nullptr, nullptr, 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 nullptr to redraw all)
-// return 2 - already queued, data updated, 1-have been queued, 0 - failure
-
-static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM) // Immideately recall paint routines for frame and refresh image
-{
- if (MirandaLoading())
- return 0;
-
- RECT wnd;
- bool NoCancelPost = false;
- bool IsAnyQueued = false;
- if (!g_CluiData.mutexOnEdgeSizing)
- GetWindowRect(g_clistApi.hwndContactList, &wnd);
- else
- wnd = g_rcEdgeSizingRect;
-
- if (!g_CluiData.fLayered) {
- RedrawWindow((HWND)wParam, nullptr, nullptr, RDW_UPDATENOW | RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);
- return 0;
- }
-
- if (g_pCachedWindow == nullptr) 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
- FRAMEWND *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 = nullptr;
- }
- 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_bPostWasCanceled = true;
- }
- 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) : nullptr, FALSE);
-
- if (frm) {
- if (frm->PaintCallbackProc != nullptr) {
- 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, nullptr, RGN_COPY);
- }
- else CombineRgn(frm->UpdateRgn, frm->UpdateRgn, r2, RGN_OR);
- DeleteObject(r2);
- }
- }
- }
- else Sync(QueueAllFramesUpdating, true);
- }
- else Sync(QueueAllFramesUpdating, true);
-
- if (!flag_bUpdateQueued || g_bPostWasCanceled)
- if (PostMessage(g_clistApi.hwndContactList, UM_UPDATE, 0, 0)) {
- flag_bUpdateQueued = 1;
- g_bPostWasCanceled = false;
- }
- 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
- RECT rcPaint, wnd;
- RECT ru = { 0 };
- int w1, h1, x1, y1;
-
- CLUI_SizingGetWindowRect(g_clistApi.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;
- }
- }
-
- int w = rcPaint.right - rcPaint.left;
- int h = rcPaint.bottom - rcPaint.top;
- if (w <= 0 || h <= 0) {
- TRACE("Frame size smaller than 0\n");
- return 0;
- }
- int x = rcPaint.left;
- int y = rcPaint.top;
- HDC hdc = CreateCompatibleDC(g_pCachedWindow->hImageDC);
- HBITMAP n = ske_CreateDIB32(w, h);
- HBITMAP 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
- 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 {
- RECT r;
- GetClientRect(Frame->hWnd, &r);
- HRGN 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 = nullptr;
-
- 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, "Main,ID=ScrollBar,Frame=%S,Part=Back", Frame->name);
- SkinDrawGlyph(g_pCachedWindow->hImageDC, &rLine, &rLine, req);
- mir_snprintf(req, "Main,ID=ScrollBar,Frame=%S,Part=Thumb", Frame->name);
- SkinDrawGlyph(g_pCachedWindow->hImageDC, &rThumb, &rThumb, req);
- mir_snprintf(req, "Main,ID=ScrollBar, Frame=%S,Part=UpLineButton", Frame->name);
- SkinDrawGlyph(g_pCachedWindow->hImageDC, &rUpBtn, &rUpBtn, req);
- mir_snprintf(req, "Main,ID=ScrollBar,Frame=%S,Part=DownLineButton", Frame->name);
- 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 w = { 0 };
- if (g_CluiData.fDisableSkinEngine) {
- FillRect(destDC, BltClientRect, GetSysColorBrush(COLOR_3DFACE));
- return 0;
- }
- ske_ReCreateBackImage(FALSE, nullptr);
- if (BltClientRect) w = *BltClientRect;
- else GetClientRect(destHWND, &w);
- ptChildWnd.x = w.left;
- ptChildWnd.y = w.top;
- ClientToScreen(destHWND, &ptChildWnd);
- ClientToScreen(g_clistApi.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)
-{
- RECT wnd = { 0 };
- BOOL IsNewCache = 0;
- if (g_CluiData.fDisableSkinEngine) return 0;
- GetClientRect(g_clistApi.hwndContactList, &wnd);
- if (w) wnd = *w;
- //-- Check cached.
- if (g_pCachedWindow == nullptr) {
- //-- Create New Cache
- g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
- g_pCachedWindow->hScreenDC = GetDC(nullptr);
- 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 = nullptr, hb2 = nullptr;
- 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)) {
- HBITMAP 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(g_clistApi.hwndContactList, &w);
- if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, nullptr);
- if (g_pCachedWindow == nullptr)
- 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;
-}
-
-// Calling queued frame paint procs and refresh image
-int ske_ValidateFrameImageProc(RECT *r)
-{
- RECT wnd = { 0 };
- BOOL IsNewCache = 0;
- BOOL IsForceAllPainting = 0;
- if (r) wnd = *r;
- else GetWindowRect(g_clistApi.hwndContactList, &wnd);
- if (wnd.right - wnd.left == 0 || wnd.bottom - wnd.top == 0)
- return 0;
-
- g_mutex_bLockUpdating = 1;
-
- //-- Check cached.
- if (g_pCachedWindow == nullptr) {
- //-- Create New Cache
- g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
- g_pCachedWindow->hScreenDC = GetDC(nullptr);
- 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, true);
- }
- //-- 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();
- g_mutex_bLockUpdating = 0;
- if (!mutex_bLockUpdate)
- ske_UpdateWindowImageRect(&wnd);
-
- //-- Clear queue
- Sync(QueueAllFramesUpdating, false);
- flag_bUpdateQueued = 0;
- g_bPostWasCanceled = false;
- return 1;
-}
-
-int ske_UpdateWindowImage()
-{
- if (MirandaExiting())
- return 0;
-
- if (g_CluiData.fLayered) {
- RECT r;
- GetWindowRect(g_clistApi.hwndContactList, &r);
- return ske_UpdateWindowImageRect(&r);
- }
- else ske_ReCreateBackImage(FALSE, nullptr);
- 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, nullptr);
- if (g_pCachedWindow == nullptr) 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_bFullRepaint) {
- g_bFullRepaint = false;
- return ske_ValidateFrameImageProc(&wnd);
- }
- ske_JustUpdateWindowImageRect(&wnd);
- return 0;
-}
-
-void ske_ApplyTranslucency()
-{
- int IsTransparancy;
- HWND hwnd = g_clistApi.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), (uint8_t)g_CluiData.bCurrentAlpha, LWA_ALPHA);
- }
-
- AniAva_RedrawAllAvatars(FALSE);
- return;
-}
-
-int ske_JustUpdateWindowImage()
-{
- RECT r;
- if (!g_CluiData.fLayered) {
- ske_ApplyTranslucency();
- return 0;
- }
- GetWindowRect(g_clistApi.hwndContactList, &r);
- return ske_JustUpdateWindowImageRect(&r);
-}
-
-// Update window image
-int ske_JustUpdateWindowImageRect(RECT *rty)
-{
- if (!g_CluiData.fLayered) {
- ske_ApplyTranslucency();
- return 0;
- }
- if (!g_clistApi.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(g_clistApi.hwndContactList, GWL_EXSTYLE) & WS_EX_LAYERED))
- SetWindowLongPtr(g_clistApi.hwndContactList, GWL_EXSTYLE, GetWindowLongPtr(g_clistApi.hwndContactList, GWL_EXSTYLE) | WS_EX_LAYERED);
- Sync(SetAlpha, g_CluiData.bCurrentAlpha);
-
- BLENDFUNCTION bf = { AC_SRC_OVER, 0, g_CluiData.bCurrentAlpha, AC_SRC_ALPHA };
- UpdateLayeredWindow(g_clistApi.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(g_clistApi.hwndContactList, nullptr, 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 uint32_t ske_HexToARGB(char *Hex)
-{
- char buf[10] = { 0 };
- char buf2[11] = { 0 };
- mir_snprintf(buf, "%s\n", Hex);
- if (buf[1] == 'x' || buf[1] == 'X')
- mir_snprintf(buf2, "0x%s\n", buf + 2);
- else
- mir_snprintf(buf2, "0x%s\n", buf);
- buf2[10] = '\0';
-
- char *st;
- uint32_t AARRGGBB = strtoul(buf2, &st, 16);
- uint8_t alpha = (uint8_t)((AARRGGBB & 0xFF000000) >> 24);
- alpha = 255 - ((alpha == 0) ? 255 : alpha);
- AARRGGBB = (alpha << 24) + ((AARRGGBB & 0x00FF0000) >> 16) + ((AARRGGBB & 0x000000FF) << 16) + (AARRGGBB & 0x0000FF00);
- return AARRGGBB;
-}
-
-static wchar_t *ske_ReAppend(wchar_t *lfirst, wchar_t *lsecond, int len)
-{
- size_t l1 = lfirst ? mir_wstrlen(lfirst) : 0;
- size_t l2 = (len ? len : (mir_wstrlen(lsecond) + 1));
- wchar_t *buf = (wchar_t *)mir_alloc((l1 + l2 + 1)*sizeof(wchar_t));
- if (lfirst) memmove(buf, lfirst, l1*sizeof(wchar_t));
- memmove(buf + l1, lsecond, l2*sizeof(wchar_t));
- mir_free(lfirst);
- if (len) buf[l1 + l2] = '\0';
- return buf;
-}
-
-wchar_t* ske_ReplaceVar(wchar_t *var)
-{
- if (!var) return mir_wstrdup(L"");
- if (!mir_wstrcmpi(var, L"Profile")) {
- char buf[MAX_PATH] = { 0 };
- Profile_GetNameA(MAX_PATH, buf);
-
- char *p = strrchr(buf, '.');
- if (p) *p = 0;
-
- mir_free(var);
- return mir_a2u(buf);
- }
-
- mir_free(var);
- return mir_wstrdup(L"");
-}
-
-wchar_t *ske_ParseText(wchar_t *stzText)
-{
- size_t len = mir_wstrlen(stzText);
- wchar_t *result = nullptr;
- size_t stpos = 0, curpos = 0;
-
- while (curpos < len) {
- //1 find first %
- while (curpos < len && stzText[curpos] != (wchar_t)'%')
- curpos++;
- if (curpos < len) { //% found
- if (curpos - stpos > 0)
- result = ske_ReAppend(result, stzText + stpos, int(curpos - stpos));
- stpos = curpos + 1;
- curpos++;
- //3 find second %
- while (curpos < len && stzText[curpos] != (wchar_t)'%')
- curpos++;
- if (curpos >= len)
- break;
- if (curpos - stpos > 0) {
- wchar_t *var = (wchar_t *)mir_alloc((curpos - stpos + 1)*sizeof(wchar_t));
- memcpy(var, stzText + stpos, (curpos - stpos)*sizeof(wchar_t));
- var[curpos - stpos] = (wchar_t)'\0';
- var = ske_ReplaceVar(var);
- result = ske_ReAppend(result, var, 0);
- mir_free(var);
- }
- else result = ske_ReAppend(result, L"%", 0);
-
- curpos++;
- stpos = curpos;
- }
- else {
- if (curpos - stpos > 0)
- result = ske_ReAppend(result, stzText + stpos, int(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)
-{
- SKINFONT *sf = (SKINFONT*)mir_calloc(sizeof(SKINFONT));
- if (!sf)
- return;
-
- 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;
-
- char buf[255];
- strncpy_s(logfont.lfFaceName, GetParamN(szDefineString, buf, sizeof(buf), 0, ',', TRUE), _TRUNCATE);
- logfont.lfHeight = atoi(GetParamN(szDefineString, buf, sizeof(buf), 1, ',', TRUE));
- if (logfont.lfHeight < 0) {
- HDC hdc = CreateCompatibleDC(nullptr);
- 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, sf, gl_plSkinFonts->realCount);
- else
- mir_free(sf);
- }
- else mir_free(sf);
-}
-
-/*
- * ske_CheckHasAlfaChannel - checks if image has at least one uint8_t in alpha chennel
- * that is not a 0. (is image real 32 bit or just 24 bit)
- */
-static BOOL ske_CheckHasAlfaChannel(uint8_t *from, int widthByte, int height)
-{
- uint32_t *pt = (uint32_t*)from;
- for (int j = 0; j < height; j++) {
- uint8_t *add = (uint8_t*)pt + widthByte;
- while (pt < (uint32_t*)add) {
- if ((*pt & 0xFF000000) != 0)
- return TRUE;
- pt++;
- }
- pt = (uint32_t*)(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(uint8_t *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(uint8_t *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 uint32_t ske_Blend(uint32_t X1, uint32_t X2, uint8_t alpha)
-{
- uint8_t a1 = (uint8_t)(X1 >> 24);
- uint8_t a2 = (uint8_t)(((X2 >> 24)*alpha) >> 8);
- uint8_t r1 = (uint8_t)(X1 >> 16);
- uint8_t r2 = (uint8_t)(X2 >> 16);
- uint8_t g1 = (uint8_t)(X1 >> 8);
- uint8_t g2 = (uint8_t)(X2 >> 8);
- uint8_t b1 = (uint8_t)(X1);
- uint8_t b2 = (uint8_t)(X2);
-
- uint8_t a_1 = ~a1;
- uint8_t a_2 = ~a2;
- uint16_t am = (uint16_t)a1*a_2;
-
- /* it is possible to use >>8 instead of /255 but it is require additional
- * checking of alphavalues
- */
- uint16_t ar = a1 + (((uint16_t)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;
-
- uint16_t arm = ar * 255;
- uint16_t rr = (((uint16_t)r1*am + (uint16_t)r2*a2 * 255)) / arm;
- uint16_t gr = (((uint16_t)g1*am + (uint16_t)g2*a2 * 255)) / arm;
- uint16_t br = (((uint16_t)b1*am + (uint16_t)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, uint8_t alpha)
-{
- 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(nullptr);
-
- uint8_t *ptPixels;
- 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) {
- uint8_t *BottomBuffer, *TopBuffer, *BottomMaskBuffer, *TopMaskBuffer;
- uint8_t *bb, *tb, *bmb, *tmb;
- uint8_t *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 = (uint8_t*)bmp_bottom.bmBits;
- else {
- BottomBuffer = (uint8_t*)mir_alloc(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 = (uint8_t*)bmp_top.bmBits;
- else {
- TopBuffer = (uint8_t*)mir_alloc(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 = (uint8_t*)bmp_bottom_mask.bmBits;
- bmb = BottomMaskBuffer;
- }
- else {
- BottomMaskBuffer = (uint8_t*)mir_alloc(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 = (uint8_t*)bmp_top_mask.bmBits;
- tmb = TopMaskBuffer;
- }
- else {
- TopMaskBuffer = (uint8_t*)mir_alloc(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);
- uint32_t bottom_d = ((uint32_t*)bb)[x];
- uint32_t top_d = ((uint32_t*)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;
- }
- ((uint32_t*)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) mir_free(BottomBuffer);
- if (!bmp_top.bmBits) mir_free(TopBuffer);
- if (!bmp_bottom_mask.bmBits) mir_free(BottomMaskBuffer);
- if (!bmp_top_mask.bmBits) mir_free(TopMaskBuffer);
- }
- else {
- ske_DrawIconEx(tempDC, 0, 0, hBottom, 16, 16, 0, nullptr, DI_NORMAL);
- ske_DrawIconEx(tempDC, 0, 0, hTop, 16, 16, 0, nullptr, DI_NORMAL | (alpha << 24));
- }
-
- DeleteObject(iciBottom.hbmColor);
- DeleteObject(iciTop.hbmColor);
- DeleteObject(iciBottom.hbmMask);
- DeleteObject(iciTop.hbmMask);
-
- SelectObject(tempDC, oImage);
- DeleteDC(tempDC);
-
- uint8_t p[32] = { 0 };
- HBITMAP nMask = CreateBitmap(16, 16, 1, 1, (void*)&p);
- {
- HDC tempDC2 = CreateCompatibleDC(nullptr);
- HDC tempDC3 = CreateCompatibleDC(nullptr);
- 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, nullptr, DI_MASK);
- DrawIconEx(tempDC3, 0, 0, hTop, 16, 16, 0, nullptr, 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(mir_strlen(first)+mir_strlen(separator)+mir_strlen(last)+1); \
- if (destination) { \
- *destination = '\0'; \
- mir_strcat(destination,first); \
- mir_strcat(destination,separator); \
- mir_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);
-}
-
-uint8_t SkinDBGetContactSettingByte(MCONTACT hContact, const char *szSection, const char *szKey, uint8_t bDefault)
-{
- DBVARIANT dbv = { 0 };
- BOOL bSkinned = FALSE;
- if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
- if (dbv.type == DBVT_BYTE) {
- uint8_t retVal = dbv.bVal;
- db_free(&dbv);
- return retVal;
- }
- else {
- db_free(&dbv);
- if (!bSkinned)
- return db_get_b(hContact, szSection, szKey, bDefault);
- }
- }
- return bDefault;
-}
-
-uint16_t SkinDBGetContactSettingWord(MCONTACT hContact, const char *szSection, const char *szKey, uint16_t wDefault)
-{
- BOOL bSkinned = FALSE;
- DBVARIANT dbv = { 0 };
- if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
- if (dbv.type == DBVT_WORD) {
- uint16_t retVal = dbv.wVal;
- db_free(&dbv);
- return retVal;
- }
- db_free(&dbv);
- if (!bSkinned)
- return db_get_w(hContact, szSection, szKey, wDefault);
- }
- return wDefault;
-}
-
-uint32_t SkinDBGetContactSettingDword(MCONTACT hContact, const char *szSection, const char *szKey, uint32_t dwDefault)
-{
- DBVARIANT dbv = { 0 };
- BOOL bSkinned = FALSE;
- if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
- if (dbv.type == DBVT_DWORD) {
- uint32_t 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-23 Miranda NG team (https://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 "stdafx.h"
+
+#define _EFFECTENUM_FULL_H
+#include "modern_effectenum.h"
+#undef _EFFECTENUM_FULL_H
+
+#include "modern_sync.h"
+
+//Implementation
+
+#pragma pack(push, 1)
+/* tga header */
+struct tga_header_t
+{
+ uint8_t id_lenght; /* size of image id */
+ uint8_t colormap_type; /* 1 is has a colormap */
+ uint8_t image_type; /* compression type */
+
+ short cm_first_entry; /* colormap origin */
+ short cm_length; /* colormap length */
+ uint8_t cm_size; /* colormap size */
+
+ short x_origin; /* bottom left x coord origin */
+ short y_origin; /* bottom left y coord origin */
+
+ short width; /* picture width (in pixels) */
+ short height; /* picture height (in pixels) */
+
+ uint8_t pixel_depth; /* bits per pixel: 8, 16, 24 or 32 */
+ uint8_t image_descriptor; /* 24 bits = 0x00; 32 bits = 0x80 */
+};
+#pragma pack(pop)
+
+/* Global variables */
+
+SKINOBJECTSLIST g_SkinObjectList = { 0 };
+CURRWNDIMAGEDATA *g_pCachedWindow = nullptr;
+
+bool g_bPostWasCanceled = false;
+bool g_bFullRepaint = false;
+
+int g_mutex_bLockUpdating = 0;
+
+SortedList *gl_plGlyphTexts = nullptr;
+SortedList *gl_plSkinFonts = nullptr;
+
+/* Private module variables */
+
+static HANDLE hSkinLoadedEvent;
+
+static GLYPHIMAGE *pLoadedImages = nullptr;
+static uint32_t dwLoadedImagesCount = 0;
+static uint32_t 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 = nullptr;
+static char **pszSettingName = nullptr;
+static int nArrayLen = 0;
+
+static uint8_t pbGammaWeight[256] = { 0 };
+static uint8_t pbGammaWeightAdv[256] = { 0 };
+static BOOL bGammaWeightFilled = FALSE;
+
+static mir_cs cs_SkinChanging;
+
+static LISTMODERNMASK *MainModernMaskList = nullptr;
+
+/* Private module procedures */
+static BOOL ske_GetMaskBit(uint8_t *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, uint32_t ARGBcolor);
+static void ske_AddParseTextGlyphObject(char * szGlyphTextID, char * szDefineString, SKINOBJECTSLIST *Skin);
+static void ske_AddParseSkinFont(char * szFontID, char * szDefineString);
+static int ske_GetSkinFromDB(char * szSection, SKINOBJECTSLIST * Skin);
+static SKINOBJECTDESCRIPTOR* ske_FindObject(const char *szName, SKINOBJECTSLIST *Skin);
+static int ske_LoadSkinFromResource(BOOL bOnlyObjects);
+static void ske_PreMultiplyChannels(HBITMAP hbmp, uint8_t 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 = { 0xFF, { 0 }, 0, 0 };
+
+//////////////////////////////////////////////////////////////////////////
+// Ini file parser
+
+IniParser::IniParser(wchar_t * tcsFileName, uint8_t flags) : _Flags(flags)
+{
+ _DoInit();
+ if (!tcsFileName) return;
+
+ if (tcsFileName[0] == '%') {
+ //TODO: Add parser of resource filename here
+ _LoadResourceIni(g_plugin.getInst(), MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF");
+ return;
+ }
+
+ _hFile = _wfopen(tcsFileName, L"r");
+ if (_hFile != nullptr) {
+ _eType = IT_FILE;
+ _isValid = true;
+ }
+}
+
+IniParser::IniParser(HINSTANCE hInst, const char * resourceName, const char * resourceType, uint8_t flags) : _Flags(flags)
+{
+ _DoInit();
+ _LoadResourceIni(hInst, resourceName, resourceType);
+}
+
+IniParser::~IniParser()
+{
+ mir_free(_szSection);
+ if (_hFile) fclose(_hFile);
+ if (_hGlobalRes) {
+ UnlockResource(_hGlobalRes);
+ FreeResource(_hGlobalRes);
+ }
+
+ _szSection = nullptr;
+ _hGlobalRes = nullptr;
+ _hFile = nullptr;
+ _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(0, szSection, szName, (uint8_t)atoi(szValue + 1));
+ break;
+
+ case 'w':
+ db_set_w(0, szSection, szName, (uint16_t)atoi(szValue + 1));
+ break;
+
+ case 'd':
+ db_set_dw(0, szSection, szName, (uint32_t)atoi(szValue + 1));
+ break;
+
+ case 's':
+ db_set_s(0, szSection, szName, szValue + 1);
+ break;
+ }
+ return S_OK;
+}
+
+int IniParser::GetSkinFolder(IN const wchar_t * szFileName, OUT wchar_t * pszFolderName)
+{
+ wchar_t *szBuff = mir_wstrdup(szFileName);
+ wchar_t *pszPos = szBuff + mir_wstrlen(szBuff);
+ while (pszPos > szBuff && *pszPos != '.') { pszPos--; }
+ *pszPos = '\0';
+ mir_wstrcpy(pszFolderName, szBuff);
+
+ wchar_t custom_folder[MAX_PATH], cus[MAX_PATH];
+ wchar_t *b3;
+ mir_wstrncpy(custom_folder, pszFolderName, _countof(custom_folder));
+ b3 = custom_folder + mir_wstrlen(custom_folder);
+ while (b3 > custom_folder && *b3 != '\\') { b3--; }
+ *b3 = '\0';
+
+ GetPrivateProfileString(L"Skin_Description_Section", L"SkinFolder", L"", cus, _countof(custom_folder), szFileName);
+ if (cus[0] != 0)
+ mir_snwprintf(pszFolderName, MAX_PATH, L"%s\\%s", custom_folder, cus);
+
+ mir_free(szBuff);
+ PathToRelativeW(pszFolderName, pszFolderName);
+ return 0;
+}
+
+void IniParser::_DoInit()
+{
+ _isValid = false;
+ _eType = IT_UNKNOWN;
+ _szSection = nullptr;
+ _hFile = nullptr;
+ _hGlobalRes = nullptr;
+ _dwSizeOfRes = 0;
+ _pPosition = nullptr;
+ _pLineCallBackProc = nullptr;
+ _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, _countof(szLine), _hFile) != nullptr) {
+ 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 + mir_strlen(pStart);
+ while (pEnd > pStart && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\n' || *pEnd == '\r'))
+ pEnd--;
+
+ len = pEnd - pStart;
+ return pStart;
+}
+
+BOOL IniParser::_DoParseLine(char *szLine)
+{
+ _nLine++;
+ size_t len = mir_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 = nullptr;
+ {
+ char *tbuf = szLine + 1; // skip [
+
+ char *ebuf = tbuf;
+
+ while (*ebuf != ']' && *ebuf != '\0') ebuf++;
+ if (*ebuf == '\0')
+ return FALSE; // no close bracket
+
+ uint32_t sectionLen = ebuf - tbuf + 1;
+ _szSection = (char*)mir_alloc(sectionLen + 1);
+ mir_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;
+
+ size_t eqPlace = 0, len2 = mir_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
+ rtrim(keyName);
+ while (*keyValue) {
+ if (!isspace(*keyValue))
+ break;
+ keyValue++;
+ }
+ rtrim(keyValue);
+ _pLineCallBackProc(_szSection, keyName, keyValue, this);
+ }
+ return TRUE;
+}
+//////////////////////////////////////////////////////////////////////////
+// End of IniParser
+//////////////////////////////////////////////////////////////////////////
+
+HRESULT SkinEngineLoadModule()
+{
+ ModernSkinButtonLoadModule();
+ MainModernMaskList = (LISTMODERNMASK*)mir_calloc(sizeof(LISTMODERNMASK));
+ //init variables
+ g_SkinObjectList.dwObjLPAlocated = 0;
+ g_SkinObjectList.dwObjLPReserved = 0;
+ g_SkinObjectList.pObjects = nullptr;
+ // 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 (auto &it : arEffectStack)
+ mir_free(it);
+ 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(nullptr, g_pCachedWindow->hScreenDC);
+ mir_free_and_nil(g_pCachedWindow);
+ }
+ 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);
+ 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);
+}
+
+struct DCBUFFER
+{
+ HDC hdcOwnedBy;
+ int nUsageID;
+ int width;
+ int height;
+ void *pImage;
+ HDC hDC;
+ HBITMAP oldBitmap;
+ HBITMAP hBitmap;
+ uint32_t 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);
+mir_cs BufferListCS;
+
+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 = nullptr;
+ 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(uint32_t));
+ }
+ pBuf->dwDestroyAfterTime = 0;
+ return pBuf->hDC;
+}
+
+int ske_ReleaseBufferDC(HDC hDC, int keepTime)
+{
+ uint32_t dwCurrentTime = GetTickCount();
+
+ // Try to find DC in buffer list - set flag to be release after time;
+ mir_cslock lck(BufferListCS);
+ for (auto &it : BufferList.rev_iter()) {
+ if (it) {
+ if (hDC != nullptr && it->hDC == hDC) {
+ it->dwDestroyAfterTime = dwCurrentTime + keepTime;
+ break;
+ }
+
+ if ((it->dwDestroyAfterTime && it->dwDestroyAfterTime < dwCurrentTime) || keepTime == -1) {
+ SelectObject(it->hDC, it->oldBitmap);
+ DeleteObject(it->hBitmap);
+ DeleteDC(it->hDC);
+ mir_free(BufferList.removeItem(&it));
+ }
+ }
+ }
+ return 0;
+}
+
+BOOL ske_SetRgnOpaque(HDC memdc, HRGN hrgn, BOOL force)
+{
+ if (g_CluiData.fDisableSkinEngine && !force) return TRUE;
+ uint32_t rgnsz = GetRegionData(hrgn, 0, nullptr);
+ RGNDATA *rdata = (RGNDATA *)mir_alloc(rgnsz);
+ GetRegionData(hrgn, rgnsz, rdata);
+ RECT *rect = (RECT *)rdata->Buffer;
+ for (uint32_t 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;
+ uint8_t *bits;
+ BITMAP bmp;
+
+ if (g_CluiData.fDisableSkinEngine && !force)
+ return TRUE;
+
+ HBITMAP hbmp = (HBITMAP)GetCurrentObject(memdc, OBJ_BITMAP);
+ GetObject(hbmp, sizeof(bmp), &bmp);
+
+ if (bmp.bmPlanes != 1)
+ return FALSE;
+
+ if (!bmp.bmBits) {
+ f = 1;
+ bits = (uint8_t*)mir_alloc(bmp.bmWidthBytes*bmp.bmHeight);
+ GetBitmapBits(hbmp, bmp.bmWidthBytes*bmp.bmHeight, bits);
+ }
+ else
+ bits = (uint8_t*)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;
+
+ uint8_t *pLine = ((uint8_t *)bits) + (bmp.bmHeight - sy - 1) * bmp.bmWidthBytes + (sx << 2) + 3;
+ for (int y = 0; y < (ey - sy); y++) {
+ uint8_t *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);
+ mir_free(bits);
+ }
+ // DeleteObject(hbmp);
+ return 1;
+}
+
+static BOOL ske_SkinFillRectByGlyph(HDC hDest, HDC hSource, RECT *rFill, RECT *rGlyph, RECT *rClip, uint8_t mode, uint8_t drawMode)
+{
+ BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+
+ //initializations
+ if (mode == FM_STRETCH) {
+ HDC mem2dc = nullptr;
+ HBITMAP mem2bmp = nullptr, oldbmp = nullptr;
+ 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)) {
+ RECT wr;
+ IntersectRect(&wr, rClip, rFill);
+ if ((wr.bottom - wr.top)*(wr.right - wr.left) == 0) return 0;
+ HDC mem2dc = CreateCompatibleDC(hDest);
+ //SetStretchBltMode(mem2dc, HALFTONE);
+ HBITMAP mem2bmp = ske_CreateDIB32(wr.right - wr.left, rGlyph->bottom - rGlyph->top);
+ HBITMAP oldbmp = (HBITMAP)SelectObject(mem2dc, mem2bmp);
+ if (!oldbmp)
+ return 0;
+
+ /// draw here
+ {
+ int y = 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 = (wr.top - rFill->top) % h;
+ if (dy >= 0) {
+ y = wr.top;
+ int 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 {
+ BLENDFUNCTION bf2 = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ int dy = (wr.top - rFill->top) % h;
+ if (dy >= 0) {
+ y = wr.top;
+ int 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, bf2);
+ }
+
+ y = wr.top + h - dy;
+ while (y < wr.bottom - h) {
+ ske_AlphaBlend(hDest, wr.left, y, w, h, mem2dc, 0, 0, w, h, bf2);
+ y += h;
+ }
+ if (y <= wr.bottom)
+ ske_AlphaBlend(hDest, wr.left, y, w, wr.bottom - y, mem2dc, 0, 0, w, wr.bottom - y, bf2);
+ }
+ }
+ }
+ 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) {
+ RECT wr;
+ 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;
+ HDC mem2dc = CreateCompatibleDC(hDest);
+
+ HBITMAP mem2bmp = ske_CreateDIB32(w, h);
+ HBITMAP oldbmp = (HBITMAP)SelectObject(mem2dc, mem2bmp);
+
+ if (!oldbmp)
+ return 0;
+ /// draw here
+ {
+ int x = 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 = (wr.left - rFill->left) % w;
+ if (dx >= 0) {
+ x = wr.left;
+ int 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 = (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 bf2 = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ int dx = (wr.left - rFill->left) % w;
+ if (dx >= 0) {
+ x = wr.left;
+ int 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, bf2);
+ }
+ x = wr.left + w - dx;
+ while (x < wr.right - w) {
+ ske_AlphaBlend(hDest, x, wr.top, w, h, mem2dc, 0, 0, w, h, bf2);
+ x += w;
+ }
+ if (x <= wr.right)
+ ske_AlphaBlend(hDest, x, wr.top, wr.right - x, h, mem2dc, 0, 0, wr.right - x, h, bf2);
+ }
+ }
+ }
+ SelectObject(mem2dc, oldbmp);
+ DeleteObject(mem2bmp);
+ DeleteDC(mem2dc);
+ }
+ else if (mode == FM_TILE_BOTH && (rGlyph->right - rGlyph->left > 0) && (rGlyph->bottom - rGlyph->top > 0)) {
+ int w = rGlyph->right - rGlyph->left;
+ int x = 0;
+ int h = rFill->bottom - rFill->top;
+ RECT wr;
+ IntersectRect(&wr, rClip, rFill);
+ if ((wr.bottom - wr.top)*(wr.right - wr.left) == 0) return 0;
+ HDC mem2dc = CreateCompatibleDC(hDest);
+ HBITMAP mem2bmp = ske_CreateDIB32(w, wr.bottom - wr.top);
+ h = wr.bottom - wr.top;
+ HBITMAP oldbmp = (HBITMAP)SelectObject(mem2dc, mem2bmp);
+#ifdef _DEBUG
+ if (!oldbmp)
+ (nullptr, "Tile bitmap not selected", "ERROR", MB_OK);
+#endif
+ /// draw here
+ {
+ //fill temp bitmap
+ {
+ int dy = (wr.top - rFill->top) % (rGlyph->bottom - rGlyph->top);
+ int 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 = (wr.left - rFill->left) % w;
+ if (dx >= 0) {
+ x = wr.left;
+ int 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 = (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 bf2 = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ int dx = (wr.left - rFill->left) % w;
+ if (dx >= 0) {
+ x = wr.left;
+ int 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, bf2);
+ }
+ x = wr.left + w - dx;
+ while (x < wr.right - w) {
+ ske_AlphaBlend(hDest, x, wr.top, w, h, mem2dc, 0, 0, w, h, bf2);
+ x += w;
+ }
+ if (x <= wr.right)
+ ske_AlphaBlend(hDest, x, wr.top, wr.right - x, h, mem2dc, 0, 0, wr.right - x, h, bf2);
+ }
+ }
+ }
+ SelectObject(mem2dc, oldbmp);
+ DeleteObject(mem2bmp);
+ DeleteDC(mem2dc);
+ }
+ return 1;
+
+}
+
+HBITMAP ske_CreateDIB32(int cx, int cy)
+{
+ return ske_CreateDIB32Point(cx, cy, nullptr);
+}
+
+HBITMAP ske_CreateDIB32Point(int cx, int cy, void **bits)
+{
+ if (cx < 0 || cy < 0)
+ return nullptr;
+
+ 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(nullptr,
+ &RGB32BitsBITMAPINFO,
+ DIB_RGB_COLORS,
+ (void **)&ptPixels,
+ nullptr, 0);
+ if ((DirectBitmap == nullptr || ptPixels == nullptr) && cx != 0 && cy != 0) {
+#ifdef _DEBUG
+ MessageBoxA(nullptr, "Object not allocated. Check GDI object count", "ERROR", MB_OK | MB_ICONERROR);
+ DebugBreak();
+#endif
+ ;
+ }
+ else memset(ptPixels, 0, cx*cy * 4);
+ if (bits != nullptr) *bits = ptPixels;
+ return DirectBitmap;
+}
+
+HRGN ske_CreateOpaqueRgn(uint8_t Level, bool Opaque)
+{
+ if (!g_pCachedWindow)
+ return nullptr;
+
+ RGBQUAD *buf = (RGBQUAD *)g_pCachedWindow->hImageDIBByte;
+ if (buf == nullptr)
+ return nullptr;
+
+ unsigned int cRect = 64;
+ PRGNDATA pRgnData = (PRGNDATA)mir_alloc(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)mir_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)mir_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(nullptr, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData);
+ mir_free(pRgnData);
+ return hRgn;
+}
+
+static int ske_DrawSkinObject(SKINDRAWREQUEST *preq, GLYPHOBJECT *pobj)
+{
+ HDC memdc = nullptr, glyphdc = nullptr;
+ int k = 0;
+ //BITMAP bmp = {0};
+ HBITMAP membmp = nullptr, oldbmp = nullptr, oldglyph = nullptr;
+ uint8_t 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 == nullptr) {
+ 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);
+ oldglyph = (HBITMAP)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);
+ }
+
+ // 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);
+ }
+ // 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);
+ }
+ // 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);
+ }
+
+ // 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);
+ }
+
+
+ // 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);
+ }
+ // 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);
+ }
+
+ // 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);
+ }
+ // 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);
+ }
+ }
+
+ }
+
+ if ((k > 0 || k == -1) && mode == 2) {
+ {
+ BLENDFUNCTION bf = { AC_SRC_OVER, 0, pobj->dwAlpha, uint8_t(pobj->bmBitsPixel == 32 && pobj->Style != ST_BRUSH ? AC_SRC_ALPHA : 0) };
+ 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) {
+ HFONT hOldFont;
+ for (int 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 = (SKINFONT*)gl_plSkinFonts->items[j];
+ if (sf->szFontID && !mir_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(SKINOBJECTDESCRIPTOR *lpDescr, SKINOBJECTSLIST *Skin)
+{
+ SKINOBJECTSLIST *sk = (Skin ? Skin : &g_SkinObjectList);
+ if (!mir_strcmpi(lpDescr->szObjectID, "_HEADER_"))
+ return 0;
+ //check if new object allready presents.
+ for (uint32_t i = 0; i < sk->dwObjLPAlocated; i++)
+ if (!mir_strcmp(sk->pObjects[i].szObjectID, lpDescr->szObjectID))
+ return 0;
+ // Realocated list to add space for new object
+ if (sk->dwObjLPAlocated + 1 > sk->dwObjLPReserved) {
+ 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 = nullptr;
+ sk->pObjects[sk->dwObjLPAlocated].szObjectID = mir_strdup(lpDescr->szObjectID);
+ // sk->Objects[sk->dwObjLPAlocated].szObjectName = mir_strdup(lpDescr->szObjectName);
+ if (lpDescr->Data != nullptr) { //Copy defaults values
+ switch (lpDescr->bType) {
+ case OT_GLYPHOBJECT:
+ {
+ GLYPHOBJECT *gl = (GLYPHOBJECT *)lpDescr->Data;
+ sk->pObjects[sk->dwObjLPAlocated].Data = mir_alloc(sizeof(GLYPHOBJECT));
+ GLYPHOBJECT *obdat = (GLYPHOBJECT *)sk->pObjects[sk->dwObjLPAlocated].Data;
+ memcpy(obdat, gl, sizeof(GLYPHOBJECT));
+ if (gl->szFileName != nullptr) {
+ obdat->szFileName = mir_strdup(gl->szFileName);
+ replaceStr(gl->szFileName, nullptr);
+ }
+ else obdat->szFileName = nullptr;
+
+ obdat->hGlyph = nullptr;
+ break;
+ }
+ }
+
+ }
+ }
+ sk->dwObjLPAlocated++;
+ return 1;
+}
+
+static SKINOBJECTDESCRIPTOR* ske_FindObject(const char *szName, SKINOBJECTSLIST *Skin)
+{
+ SKINOBJECTSLIST *sk = (Skin == nullptr) ? (&g_SkinObjectList) : Skin;
+ return skin_FindObjectByRequest((char *)szName, sk->pMaskList);
+}
+
+static SKINOBJECTDESCRIPTOR* ske_FindObjectByMask(MODERNMASK *pModernMask, SKINOBJECTSLIST *Skin)
+{
+ SKINOBJECTSLIST *sk = (Skin == nullptr) ? (&g_SkinObjectList) : Skin;
+ return sk->pMaskList ? skin_FindObjectByMask(pModernMask, sk->pMaskList) : nullptr;
+}
+
+SKINOBJECTDESCRIPTOR* ske_FindObjectByName(const char *szName, uint8_t objType, SKINOBJECTSLIST *Skin)
+{
+ SKINOBJECTSLIST *sk = (Skin == nullptr) ? (&g_SkinObjectList) : Skin;
+ for (uint32_t 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 nullptr;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Paint glyph
+// wParam - LPSKINDRAWREQUEST
+// lParam - possible direct pointer to modern mask
+//////////////////////////////////////////////////////////////////////////
+
+INT_PTR ske_Service_DrawGlyph(WPARAM wParam, LPARAM lParam)
+{
+ auto *preq = (SKINDRAWREQUEST *)wParam;
+ if (preq == nullptr)
+ return -1;
+
+ mir_cslock lck(cs_SkinChanging);
+
+ SKINOBJECTDESCRIPTOR *pgl = (lParam ? ske_FindObjectByMask((MODERNMASK*)lParam, nullptr) : ske_FindObject(preq->szObjectID, nullptr));
+ if (pgl == nullptr) return -1;
+ if (pgl->Data == nullptr) return -1;
+
+ GLYPHOBJECT *gl = (GLYPHOBJECT*)pgl->Data;
+ int iStyle = gl->Style & 7;
+ if (iStyle == ST_SKIP)
+ return ST_SKIP;
+
+ if (gl->hGlyph == nullptr && 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 = (uint8_t)bmp.bmBitsPixel;
+ gl->bmHeight = bmp.bmHeight;
+ gl->bmWidth = bmp.bmWidth;
+ }
+ else gl->hGlyph = (HBITMAP)-1; //invalid
+ }
+ }
+ return ske_DrawSkinObject(preq, gl);
+}
+
+
+void ske_PreMultiplyChannels(HBITMAP hbmp, uint8_t Mult)
+{
+ BITMAP bmp;
+ BOOL flag = FALSE;
+ uint8_t *pBitmapBits;
+ uint32_t 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 == nullptr);
+ if (flag) {
+ pBitmapBits = (LPBYTE)mir_alloc(Len);
+ GetBitmapBits(hbmp, Len, pBitmapBits);
+ }
+ else
+ pBitmapBits = (uint8_t *)bmp.bmBits;
+ for (y = 0; y < bh; ++y) {
+ uint8_t *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);
+ mir_free(pBitmapBits);
+ }
+ return;
+}
+
+int ske_GetFullFilename(wchar_t *buf, const wchar_t *file, wchar_t *skinfolder, BOOL madeAbsolute)
+{
+ wchar_t *SkinPlace = db_get_wsa(0, SKIN, "SkinFolder");
+ if (SkinPlace == nullptr)
+ SkinPlace = mir_wstrdup(L"\\Skin\\default");
+
+ wchar_t b2[MAX_PATH];
+ if (file[0] != '\\' && file[1] != ':')
+ mir_snwprintf(b2, L"%s\\%s", (skinfolder == nullptr) ? SkinPlace : ((INT_PTR)skinfolder != -1) ? skinfolder : L"", file);
+ else
+ mir_wstrncpy(b2, file, _countof(b2));
+
+ if (madeAbsolute) {
+ if (b2[0] == '\\' && b2[1] != '\\')
+ PathToAbsoluteW(b2 + 1, buf);
+ else
+ PathToAbsoluteW(b2, buf);
+ }
+ else mir_wstrncpy(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, uint32_t fromSize, uint8_t *destBuf, uint32_t bufSize, BOOL RLE)
+{
+ uint8_t *pos = destBuf;
+ uint8_t *from = fromSize ? (uint8_t *)From : nullptr;
+ FILE *fp = !fromSize ? (FILE *)From : nullptr;
+ uint32_t destCount = 0;
+ uint32_t fromCount = 0;
+ if (!RLE) {
+ while (((from && fromCount < fromSize) || (fp && fromCount < bufSize))
+ && (destCount < bufSize)) {
+ uint8_t r = from ? from[fromCount++] : (uint8_t)fgetc(fp);
+ uint8_t g = from ? from[fromCount++] : (uint8_t)fgetc(fp);
+ uint8_t b = from ? from[fromCount++] : (uint8_t)fgetc(fp);
+ uint8_t a = from ? from[fromCount++] : (uint8_t)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 {
+ uint8_t rgba[4];
+ uint8_t packet_header;
+ uint8_t *ptr = pos;
+ uint8_t size;
+ int i;
+ while (ptr < pos + bufSize) {
+ /* read first byte */
+ packet_header = from ? from[fromCount] : (uint8_t)fgetc(fp);
+ if (from) from++;
+ size = 1 + (packet_header & 0x7f);
+ if (packet_header & 0x80) {
+ /* run-length packet */
+ if (from) {
+ *((uint32_t*)rgba) = *((uint32_t*)(from + fromCount));
+ fromCount += 4;
+ }
+ else fread(rgba, sizeof(uint8_t), 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++] : (uint8_t)fgetc(fp);
+ ptr[1] = from ? from[fromCount++] : (uint8_t)fgetc(fp);
+ ptr[2] = from ? from[fromCount++] : (uint8_t)fgetc(fp);
+ ptr[3] = from ? from[fromCount++] : (uint8_t)fgetc(fp);
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+static HBITMAP ske_LoadGlyphImage_TGA(const wchar_t *szFilename)
+{
+ uint8_t *colormap = nullptr;
+ int cx = 0, cy = 0;
+ BOOL err = FALSE;
+ tga_header_t header;
+ if (!szFilename) return nullptr;
+ if (!wildcmpiw(szFilename, L"*\\*%.tga")) {
+ //Loading TGA image from file
+ FILE *fp = _wfopen(szFilename, L"rb");
+ if (!fp) {
+ TRACEVAR("error: couldn't open \"%s\"!\n", szFilename);
+ return nullptr;
+ }
+ /* 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 nullptr;
+ }
+
+ /*memory allocation */
+ colormap = (uint8_t*)mir_alloc(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 */
+ HRSRC hRSrc = FindResourceA(g_plugin.getInst(), MAKEINTRESOURCEA(IDR_TGA_DEFAULT_SKIN), "TGA");
+ if (!hRSrc) return nullptr;
+ HGLOBAL hRes = LoadResource(g_plugin.getInst(), hRSrc);
+ if (!hRes) return nullptr;
+ uint32_t size = SizeofResource(g_plugin.getInst(), hRSrc);
+ uint8_t *mem = (uint8_t*)LockResource(hRes);
+ if (size > sizeof(header)) {
+ tga_header_t *tgahdr = (tga_header_t*)mem;
+ if (tgahdr->pixel_depth == 32 && (tgahdr->image_type == 2 || tgahdr->image_type == 10)) {
+ colormap = (uint8_t*)mir_alloc(tgahdr->width*tgahdr->height * 4);
+ cx = tgahdr->width;
+ cy = tgahdr->height;
+ ske_ReadTGAImageData((void*)(mem + sizeof(tga_header_t) + tgahdr->id_lenght + tgahdr->cm_length), size - (sizeof(tga_header_t) + tgahdr->id_lenght + tgahdr->cm_length), colormap, cx*cy * 4, tgahdr->image_type == 10);
+ }
+ }
+ FreeResource(hRes);
+ }
+
+ if (colormap == nullptr)
+ return nullptr;
+
+ // create dib section
+ uint8_t *pt;
+ HBITMAP hbmp = ske_CreateDIB32Point(cx, cy, (void**)&pt);
+ if (hbmp)
+ memcpy(pt, colormap, cx*cy * 4);
+ mir_free(colormap);
+ return hbmp;
+}
+
+static HBITMAP ske_LoadGlyphImageByDecoders(const wchar_t *tszFileName)
+{
+ if (!wcschr(tszFileName, '%') && !PathFileExists(tszFileName))
+ return nullptr;
+
+ const wchar_t *ext = wcsrchr(tszFileName, '.');
+ if (ext == nullptr)
+ return nullptr;
+
+ BITMAP bmpInfo;
+ HBITMAP hBitmap;
+ bool f = false;
+
+ if (!mir_wstrcmpi(ext, L".tga")) {
+ hBitmap = ske_LoadGlyphImage_TGA(tszFileName);
+ f = true;
+ }
+ else hBitmap = Bitmap_Load(tszFileName);
+
+ if (hBitmap == nullptr)
+ return nullptr;
+
+ GetObject(hBitmap, sizeof(BITMAP), &bmpInfo);
+ if (bmpInfo.bmBitsPixel == 32)
+ ske_PreMultiplyChannels(hBitmap, f);
+ else {
+ HDC dc32 = CreateCompatibleDC(nullptr);
+ HDC dc24 = CreateCompatibleDC(nullptr);
+ HBITMAP hBitmap32 = ske_CreateDIB32(bmpInfo.bmWidth, bmpInfo.bmHeight);
+ HBITMAP obmp24 = (HBITMAP)SelectObject(dc24, hBitmap);
+ 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_PreMultiplyChannels(hBitmap, 0);
+ }
+ return hBitmap;
+}
+
+static HBITMAP ske_skinLoadGlyphImage(const wchar_t *tszFileName)
+{
+ if (!wildcmpiw(tszFileName, L"*.tga"))
+ return GDIPlus_LoadGlyphImage(tszFileName);
+
+ return ske_LoadGlyphImageByDecoders(tszFileName);
+}
+
+HBITMAP ske_LoadGlyphImage(const wchar_t *tszFileName)
+{
+ // try to find image in loaded
+ wchar_t szFile[MAX_PATH] = { 0 };
+ ske_GetFullFilename(szFile, tszFileName, g_SkinObjectList.szSkinPlace, TRUE);
+
+ mir_cslock lck(cs_SkinChanging);
+
+ if (pLoadedImages) {
+ for (uint32_t i = 0; i < dwLoadedImagesCount; i++) {
+ if (!mir_wstrcmpi(pLoadedImages[i].szFileName, szFile)) {
+ pLoadedImages[i].dwLoadedTimes++;
+ return pLoadedImages[i].hGlyph;
+ }
+ }
+ }
+
+ // load new image
+ HBITMAP hbmp = ske_skinLoadGlyphImage(szFile);
+ if (hbmp == nullptr)
+ return nullptr;
+
+ // add to loaded list
+ if (dwLoadedImagesCount + 1 > dwLoadedImagesAlocated) {
+ pLoadedImages = (GLYPHIMAGE*)mir_realloc(pLoadedImages, sizeof(GLYPHIMAGE)*(dwLoadedImagesCount + 1));
+ if (!pLoadedImages)
+ return nullptr;
+ dwLoadedImagesAlocated++;
+ }
+
+ pLoadedImages[dwLoadedImagesCount].dwLoadedTimes = 1;
+ pLoadedImages[dwLoadedImagesCount].hGlyph = hbmp;
+ pLoadedImages[dwLoadedImagesCount].szFileName = mir_wstrdup(szFile);
+ dwLoadedImagesCount++;
+ return hbmp;
+}
+
+int ske_UnloadGlyphImage(HBITMAP hbmp)
+{
+ for (uint32_t i = 0; i < dwLoadedImagesCount && pLoadedImages; i++) {
+ if (hbmp != pLoadedImages[i].hGlyph)
+ continue;
+
+ pLoadedImages[i].dwLoadedTimes--;
+ if (pLoadedImages[i].dwLoadedTimes == 0) {
+ LPGLYPHIMAGE gl = &(pLoadedImages[i]);
+ replaceStrW(gl->szFileName, nullptr);
+ 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)
+{
+ 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);
+ }
+
+ replaceStrW(Skin->szSkinPlace, nullptr);
+ if (Skin->pTextList) List_Destroy(Skin->pTextList);
+ mir_free_and_nil(Skin->pTextList);
+ ModernSkinButtonDeleteAll();
+ if (Skin->dwObjLPAlocated == 0)
+ return 0;
+
+ for (uint32_t i = 0; i < Skin->dwObjLPAlocated; i++) {
+ switch (Skin->pObjects[i].bType) {
+ case OT_GLYPHOBJECT:
+ GLYPHOBJECT *dt = (GLYPHOBJECT*)Skin->pObjects[i].Data;
+ if (dt->hGlyph && dt->hGlyph != (HBITMAP)-1)
+ ske_UnloadGlyphImage(dt->hGlyph);
+ dt->hGlyph = nullptr;
+ replaceStr(dt->szFileName, nullptr);
+
+ if (dt->plTextList && dt->plTextList->realCount > 0) {
+ for (int k = 0; k < dt->plTextList->realCount; k++) {
+ GLYPHTEXT *gt = (GLYPHTEXT *)dt->plTextList->items[k];
+ 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;
+ }
+ replaceStr(Skin->pObjects[i].szObjectID, nullptr);
+ }
+ mir_free_and_nil(Skin->pObjects);
+ Skin->pTextList = nullptr;
+ Skin->dwObjLPAlocated = 0;
+ Skin->dwObjLPReserved = 0;
+ return 0;
+}
+
+static void RegisterMaskByParce(const char *szSetting, char *szValue, SKINOBJECTSLIST *pSkin)
+{
+ size_t i, val_len = mir_strlen(szValue);
+
+ for (i = 0; i < val_len; i++)
+ if (szValue[i] == ':')
+ break;
+
+ if (i < val_len) {
+ char *Obj, *Mask;
+ int res;
+ uint32_t ID = atoi(szSetting + 1);
+ Mask = szValue + i + 1;
+ Obj = (char*)mir_alloc(i + 2);
+ mir_strncpy(Obj, szValue, i + 1);
+ Obj[i + 1] = '\0';
+ res = AddStrModernMaskToList(ID, Mask, Obj, pSkin->pMaskList);
+ 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);
+ else return 0;
+ return 1;
+}
+
+static int ske_enumdb_SkinObjectsProc(const char *szSetting, void *)
+{
+ ptrA value(db_get_sa(0, SKIN, szSetting));
+ ske_ProcessLoadindString(szSetting, value);
+ return 0;
+}
+
+static int ske_SortTextGlyphObjectFunc(void *first, void *second)
+{
+ GLYPHTEXT *p1 = *(GLYPHTEXT**)first, *p2 = *(GLYPHTEXT**)second;
+ return mir_strcmp(p1->szGlyphTextID, p2->szGlyphTextID);
+}
+
+static void ske_LinkSkinObjects(SKINOBJECTSLIST *pObjectList)
+{
+ // LINK Mask with objects
+ for (uint32_t 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);
+ replaceStr(mm->szObjectName, nullptr);
+ mm->bObjectFound = TRUE;
+ mm->pObject = pObject;
+ }
+
+ if (pObjectList->pTextList) {
+ // LINK Text with objects
+ for (int i = 0; i < pObjectList->pTextList->realCount; i++) {
+ GLYPHTEXT *glText = (GLYPHTEXT *)pObjectList->pTextList->items[i];
+ SKINOBJECTDESCRIPTOR *lpobj = ske_FindObjectByName(glText->szObjectName, OT_GLYPHOBJECT, pObjectList);
+ replaceStr(glText->szObjectName, nullptr);
+ GLYPHOBJECT *globj = nullptr;
+ 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(GLYPHTEXT*), (int(*)(const void*, const void*))globj->plTextList->sortFunc);
+ pObjectList->pTextList->items[i] = nullptr;
+ }
+ 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 *, SKINOBJECTSLIST *Skin)
+{
+ if (Skin == nullptr) return 0;
+ ske_UnloadSkin(Skin);
+ g_CluiData.fDisableSkinEngine = db_get_b(0, "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;
+ return 0;
+ }
+
+ // window borders
+ g_CluiData.LeftClientMargin = (int)db_get_b(0, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT);
+ g_CluiData.RightClientMargin = (int)db_get_b(0, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT);
+ g_CluiData.TopClientMargin = (int)db_get_b(0, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT);
+ g_CluiData.BottomClientMargin = (int)db_get_b(0, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT);
+
+ Skin->pMaskList = (LISTMODERNMASK*)mir_alloc(sizeof(LISTMODERNMASK));
+ memset(Skin->pMaskList, 0, sizeof(LISTMODERNMASK));
+ Skin->szSkinPlace = db_get_wsa(0, SKIN, "SkinFolder");
+ if (!Skin->szSkinPlace || (wcschr(Skin->szSkinPlace, '%') && !db_get_b(0, SKIN, "Modified", 0))) {
+ BOOL bOnlyObjects = FALSE;
+ if (Skin->szSkinPlace && wcschr(Skin->szSkinPlace, '%'))
+ bOnlyObjects = TRUE;
+ mir_free(Skin->szSkinPlace);
+ Skin->szSkinPlace = mir_wstrdup(L"%Default%");
+ ske_LoadSkinFromResource(bOnlyObjects);
+ }
+
+ // Load objects
+ pCurrentSkin = Skin;
+ db_enum_settings(0, ske_enumdb_SkinObjectsProc, SKIN);
+
+ 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(0, "ModernSettings", "KeyColor", (uint32_t)SETTING_KEYCOLOR_DEFAULT);
+}
+
+static int ske_LoadSkinFromResource(BOOL bOnlyObjects)
+{
+ IniParser parser(g_plugin.getInst(), MAKEINTRESOURCEA(IDR_MSF_DEFAULT_SKIN), "MSF", bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
+ if (parser.CheckOK()) {
+ db_delete_module(0, "ModernSkin");
+ db_set_s(0, SKIN, "SkinFolder", "%Default%");
+ db_set_s(0, SKIN, "SkinFile", "%Default%");
+ parser.Parse(IniParser::WriteStrToDb, 0);
+ }
+ return 0;
+}
+
+// Load data from ini file
+int ske_LoadSkinFromIniFile(wchar_t *szFileName, BOOL bOnlyObjects)
+{
+ if (wcschr(szFileName, '%'))
+ return ske_LoadSkinFromResource(bOnlyObjects);
+
+ IniParser parser(szFileName, bOnlyObjects ? IniParser::FLAG_ONLY_OBJECTS : IniParser::FLAG_WITH_SETTINGS);
+ if (!parser.CheckOK())
+ return 0;
+
+ db_delete_module(0, "ModernSkin");
+
+ wchar_t skinFolder[MAX_PATH], skinFile[MAX_PATH];
+ IniParser::GetSkinFolder(szFileName, skinFolder);
+ PathToRelativeW(szFileName, skinFile);
+
+ db_set_ws(0, SKIN, "SkinFolder", skinFolder);
+ db_set_ws(0, SKIN, "SkinFile", skinFile);
+
+ parser.Parse(IniParser::WriteStrToDb, 1);
+ return 0;
+}
+
+BOOL ske_TextOut(HDC hdc, int x, int y, LPCTSTR lpString, int nCount)
+{
+ SIZE sz;
+ GetTextExtentPoint32(hdc, lpString, nCount, &sz);
+
+ 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)
+{
+ 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;
+}
+
+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, uint8_t EffectID, uint32_t FirstColor, uint32_t SecondColor)
+{
+ if (EffectID > MAXPREDEFINEDEFFECTS)
+ return false;
+
+ if (EffectID == -1)
+ return ske_ResetTextEffect(hdc);
+
+ EFFECTSSTACKITEM *effect = arEffectStack.find((EFFECTSSTACKITEM*)&hdc);
+ if (effect == nullptr) {
+ 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 == nullptr)
+ 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(uint8_t *destPt, uint8_t *maskPt, uint32_t width, uint32_t height, MODERNEFFECT *effect)
+{
+ sbyte *buf;
+ sbyte *outbuf;
+ sbyte *bufline, *buflineTop, *buflineMid;
+ int sign = 0;
+ uint8_t *maskline, *destline;
+ uint8_t al, rl, gl, bl, ad, rd, gd, bd;
+ int k = 0;
+ uint32_t x, y;
+ sbyte *matrix;
+ uint8_t mcTopStart;
+ uint8_t mcBottomEnd;
+ uint8_t mcLeftStart;
+ uint8_t mcRightEnd;
+ uint8_t 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*)mir_alloc(width*height*sizeof(uint8_t));
+ {
+ 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 - ((uint8_t)(effect->EffectColor1 >> 24));
+ rl = GetRValue(effect->EffectColor1);
+ gl = GetGValue(effect->EffectColor1);
+ bl = GetBValue(effect->EffectColor1);
+ ad = 255 - ((uint8_t)(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++) {
+ uint8_t a = (sbyte)(uint32_t)((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*)mir_alloc(width*height*sizeof(sbyte));
+ memset(outbuf, 0, width*height*sizeof(sbyte));
+ for (y = (uint32_t)minY; y < (uint32_t)maxY; y++) {
+ int val;
+ bufline = outbuf + y*width + minX;
+ buflineMid = buf + y*width + minX;
+ for (x = (uint32_t)minX; x < (uint32_t)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 = nullptr;
+ if (as >= 0 && (uint32_t)as < height) buflineTopS = buflineMid + buflineStep;
+
+ for (matrixHor = mcLeftStart; matrixHor < mcRightEnd; matrixHor++) {
+ buflineTop = buflineTopS;
+ int a = x + matrixHor - 2;
+ if (buflineTop && a >= 0 && (uint32_t)a < width) buflineTop += matrixHor - 2;
+ else buflineTop = nullptr;
+ if (buflineTop)
+ val += ((*buflineTop)*matrix[matrixVer * 5 + matrixHor]);
+ }
+ }
+ val = (val + 1) >> 5;
+ *bufline = (sbyte)((val>127) ? 127 : (val < -125) ? -125 : val);
+ bufline++;
+ buflineMid++;
+ }
+ }
+ mir_free(buf);
+ buf = outbuf;
+ }
+ {
+ uint8_t 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;
+ uint8_t 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;
+ }
+ }
+ mir_free(buf);
+ }
+ return false;
+}
+
+static int ske_AlphaTextOut(HDC hDC, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, uint32_t ARGBcolor)
+{
+ if (!(lpString && lpRect))
+ return 0;
+
+ // Step first fill fast calc correction tables:
+ static bool _tables_empty = true;
+ static uint8_t gammaTbl[256]; // Gamma correction table
+ static uint16_t blueMulTbl[256]; // blue coefficient multiplication table
+ static uint16_t greenMulTbl[256]; // green coefficient multiplication table
+ static uint16_t redMulTbl[256]; // red coefficient multiplication table
+ if (_tables_empty) {
+ // fill tables
+ double gammaCfPw = 1000 / (double)DBGetContactSettingRangedWord(0, "ModernData", "AlphaTextOutGamma", 700, 1, 5000);
+ uint8_t blueCf = db_get_b(0, "ModernData", "AlphaTextOutBlueCorrection", 28);
+ uint8_t redCf = db_get_b(0, "ModernData", "AlphaTextOutRed Correction", 77);
+ uint8_t greenCf = db_get_b(0, "ModernData", "AlphaTextOutGreen Correction", 151);
+
+ for (int i = 0; i < 256; i++) {
+ gammaTbl[i] = (uint8_t)(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 = (int)mir_wstrlen(lpString);
+
+ // retrieve destination bitmap bits
+ HBITMAP hDestBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
+ BITMAP bmpDest;
+ GetObject(hDestBitmap, sizeof(BITMAP), &bmpDest);
+
+ bool destHasNotDIB = (bmpDest.bmBits == nullptr);
+ uint8_t *pDestBits;
+ if (destHasNotDIB) {
+ pDestBits = (uint8_t*)mir_alloc(bmpDest.bmHeight * bmpDest.bmWidthBytes);
+ GetBitmapBits(hDestBitmap, bmpDest.bmHeight*bmpDest.bmWidthBytes, pDestBits);
+ }
+ else
+ pDestBits = (uint8_t*)bmpDest.bmBits;
+
+ // 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) {
+ if (destHasNotDIB)
+ mir_free(pDestBits);
+ 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, nullptr, &textSize);
+ else
+ GetTextExtentExPoint(hOffscreenDC, lpString, nCount, 0, &visibleCharCount, nullptr, &textSize);
+
+ // replace end of string by elipsis
+ bNeedFreeWorkString = TRUE;
+ lpWorkString = (wchar_t*)mir_alloc((visibleCharCount + 4) * sizeof(wchar_t));
+
+ memcpy((void*)lpWorkString, lpString, visibleCharCount * sizeof(wchar_t));
+ memcpy((void*)(lpWorkString + visibleCharCount), L"...", 4 * sizeof(wchar_t)); // 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
+ uint8_t *bits = nullptr;
+ HBITMAP hbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bits);
+ if (bits != nullptr) {
+ HBITMAP holdbmp = (HBITMAP)SelectObject(hOffscreenDC, hbmp);
+
+ //Create buffer bitmap image for temp text
+ uint8_t *bufbits = nullptr;
+ HBITMAP bufbmp = ske_CreateDIB32Point(textSize.cx, textSize.cy, (void**)&bufbits);
+ if (bufbits != nullptr) {
+ 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;
+
+ uint32_t width = textSize.cx;
+ uint32_t heigh = textSize.cy;
+
+ uint8_t *pDestScanLine, *pBufScanLine, *pix, *bufpix;
+
+ uint8_t al = 255 - ((uint8_t)(ARGBcolor >> 24));
+ uint8_t r = GetRValue(ARGBcolor);
+ uint8_t g = GetGValue(ARGBcolor);
+ uint8_t b = GetBValue(ARGBcolor);
+
+ for (uint32_t y = 2; y < heigh - 2; y++) {
+ int lineBytes = y * (width << 2);
+
+ pDestScanLine = bits + lineBytes;
+ pBufScanLine = bufbits + lineBytes;
+
+ for (uint32_t x = 2; x < width - 2; x++) {
+ pix = pDestScanLine + (x << 2);
+ bufpix = pBufScanLine + (x << 2);
+
+ // Monochromatic
+ uint8_t bx = gammaTbl[bufpix[0]];
+ uint8_t gx = gammaTbl[bufpix[1]];
+ uint8_t rx = gammaTbl[bufpix[2]];
+
+ if (al != 255) {
+ bx *= al / 255;
+ gx *= al / 255;
+ rx *= al / 255;
+ }
+
+ uint8_t ax = (uint8_t)(((uint32_t)rx * 77 + (uint32_t)gx * 151 + (uint32_t)bx * 28 + 128) / 256);
+ if (ax) {
+ //Normalize components to gray
+ uint8_t axx = 255 - ((r + g + b) >> 2); // Coefficient of grayance, more white font - more gray edges
+ uint16_t 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] = (uint8_t)(ax + (uint8_t)(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)
+ mir_free(pDestBits);
+
+ if (bNeedFreeWorkString)
+ mir_free((void*)lpWorkString);
+
+ return 0;
+}
+
+static int ske_DrawTextWithEffectWorker(HDC hdc, LPCTSTR lpString, int nCount, RECT *lpRect, UINT format, FONTEFFECT *effect)
+{
+ if (format & DT_CALCRECT)
+ return DrawText(hdc, lpString, nCount, lpRect, format);
+
+ if (format & DT_RTLREADING)
+ SetTextAlign(hdc, TA_RTLREADING);
+
+ uint32_t color = GetTextColor(hdc);
+ RECT r = *lpRect;
+ OffsetRect(&r, 1, 1);
+ uint32_t 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)
+{
+ DrawTextWithEffectParam *p = (DrawTextWithEffectParam *)wParam;
+ 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)
+{
+ 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);
+
+ uint32_t form = format;
+ uint32_t color = GetTextColor(hdc);
+ return ske_AlphaTextOut(hdc, lpString, nCount, lpRect, form, color);
+}
+
+HICON ske_ImageList_GetIcon(HIMAGELIST himl, int i)
+{
+ IMAGEINFO imi = {};
+ BITMAP bm = { 0 };
+ if (i != -1) {
+ ImageList_GetImageInfo(himl, i, &imi);
+ GetObject(imi.hbmImage, sizeof(bm), &bm);
+ // 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
+ if (bm.bmBitsPixel == 32) {
+ uint8_t *bits = (uint8_t*)bm.bmBits;
+ if (!bits) {
+ bits = (uint8_t*)mir_alloc(bm.bmWidthBytes*bm.bmHeight);
+ GetBitmapBits(imi.hbmImage, bm.bmWidthBytes*bm.bmHeight, bits);
+ }
+
+ uint8_t *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
+ uint32_t *c = ((uint32_t*)bcbits);
+ for (x = 0; x < imi.rcImage.right - imi.rcImage.left; x++) {
+ uint32_t val = *c;
+ uint8_t a = (uint8_t)((val) >> 24);
+ if (a != 0) {
+ uint8_t r = (uint8_t)((val & 0xFF0000) >> 16);
+ uint8_t g = (uint8_t)((val & 0xFF00) >> 8);
+ uint8_t b = (uint8_t)(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);
+ mir_free(bits);
+ }
+ }
+ }
+ return ImageList_GetIcon(himl, i, ILD_NORMAL);
+}
+
+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);
+
+ uint8_t alpha;
+ if (fStyle & ILD_BLEND25)
+ alpha = 64;
+ else if (fStyle & ILD_BLEND50)
+ alpha = 128;
+ else
+ alpha = 255;
+
+ HICON hIcon = ske_ImageList_GetIcon(himl, i);
+ if (hIcon == nullptr)
+ return FALSE;
+
+ ske_DrawIconEx(hdcDst, x, y, hIcon, dx ? dx : GetSystemMetrics(SM_CXSMICON), dy ? dy : GetSystemMetrics(SM_CYSMICON), 0, nullptr, DI_NORMAL | (alpha << 24));
+ DestroyIcon(hIcon);
+ return TRUE;
+}
+
+static INT_PTR ske_Service_DrawIconEx(WPARAM wParam, 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;
+ uint8_t alpha = (uint8_t)((diFlags & 0xFF000000) >> 24);
+
+ HBITMAP tBmp = nullptr;
+ uint8_t *imbits, *imimagbits, *immaskbits;
+ uint8_t *t1, *t2, *t3;
+
+ //lockimagelist
+ uint8_t hasmask = FALSE, no32bit = FALSE, noMirrorMask = FALSE, 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;
+
+ BITMAP imbt;
+ GetObject(ici.hbmColor, sizeof(BITMAP), &imbt);
+ if (imbt.bmWidth*imbt.bmHeight == 0) {
+ DeleteObject(ici.hbmColor);
+ DeleteObject(ici.hbmMask);
+ return 0;
+ }
+
+ BITMAP immaskbt;
+ GetObject(ici.hbmMask, sizeof(BITMAP), &immaskbt);
+ uint32_t cy = imbt.bmHeight;
+
+ if (imbt.bmBitsPixel != 32) {
+ no32bit = TRUE;
+ HDC tempDC1 = CreateCompatibleDC(hdcDst);
+ tBmp = ske_CreateDIB32(imbt.bmWidth, imbt.bmHeight);
+ if (tBmp) {
+ GetObject(tBmp, sizeof(BITMAP), &imbt);
+ HBITMAP 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);
+ }
+
+ bool NoDIBImage = (imbt.bmBits == nullptr);
+ if (NoDIBImage) {
+ imimagbits = (uint8_t*)mir_alloc(cy*imbt.bmWidthBytes);
+ GetBitmapBits(ici.hbmColor, cy*imbt.bmWidthBytes, (void*)imimagbits);
+ }
+ else imimagbits = (uint8_t*)imbt.bmBits;
+
+ if (immaskbt.bmBits == nullptr) {
+ immaskbits = (uint8_t*)mir_alloc(cy*immaskbt.bmWidthBytes);
+ GetBitmapBits(ici.hbmMask, cy*immaskbt.bmWidthBytes, (void*)immaskbits);
+ }
+ else immaskbits = (uint8_t*)immaskbt.bmBits;
+
+ HDC imDC = CreateCompatibleDC(hdcDst);
+ uint32_t icy = imbt.bmHeight;
+ uint32_t cx = imbt.bmWidth;
+ HBITMAP imBmp = ske_CreateDIB32Point(cx, icy, (void**)&imbits);
+ HBITMAP oldBmp = (HBITMAP)SelectObject(imDC, imBmp);
+ if (imbits != nullptr && imimagbits != nullptr && immaskbits != nullptr) {
+ int x, y;
+ int mwb = immaskbt.bmWidthBytes;
+ int mwb2 = imbt.bmWidthBytes;
+ int bottom = icy;
+ int right = cx;
+ int top = 0;
+ int 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++) {
+ uint8_t mask = 0;
+ uint8_t a = 0;
+ uint32_t *src = (uint32_t*)(t1 + (x << 2));
+ uint32_t *dest = (uint32_t*)(t2 + (x << 2));
+ if (hasalpha && !hasmask)
+ a = ((uint8_t*)src)[3];
+ else {
+ mask = ((1 << (7 - x % 8))&(*(t3 + (x >> 3)))) != 0;
+ if (mask) {
+ if (!hasalpha) {
+ *dest = 0;
+ continue;
+ }
+
+ if (((uint8_t*)src)[3]>0)
+ a = ((uint8_t*)src)[3];
+ else
+ a = 0;
+ }
+ else if (hasalpha || hasmask)
+ a = (((uint8_t*)src)[3] > 0 ? ((uint8_t*)src)[3] : 255);
+ else if (!hasalpha && !hasmask)
+ a = 255;
+ else { *dest = 0; continue; }
+ }
+ if (a > 0) {
+ ((uint8_t*)dest)[3] = a;
+ ((uint8_t*)dest)[0] = ((uint8_t*)src)[0] * a / 255;
+ ((uint8_t*)dest)[1] = ((uint8_t*)src)[1] * a / 255;
+ ((uint8_t*)dest)[2] = ((uint8_t*)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 == nullptr) mir_free(immaskbits);
+ if (imbt.bmBits == nullptr) mir_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, nullptr);
+ CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, 0, 0);
+ }
+ else RedrawWindow(g_clistApi.hwndContactList, nullptr, nullptr, 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 nullptr to redraw all)
+// return 2 - already queued, data updated, 1-have been queued, 0 - failure
+
+static INT_PTR ske_Service_UpdateFrameImage(WPARAM wParam, LPARAM) // Immideately recall paint routines for frame and refresh image
+{
+ if (MirandaLoading())
+ return 0;
+
+ RECT wnd;
+ bool NoCancelPost = false;
+ bool IsAnyQueued = false;
+ if (!g_CluiData.mutexOnEdgeSizing)
+ GetWindowRect(g_clistApi.hwndContactList, &wnd);
+ else
+ wnd = g_rcEdgeSizingRect;
+
+ if (!g_CluiData.fLayered) {
+ RedrawWindow((HWND)wParam, nullptr, nullptr, RDW_UPDATENOW | RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);
+ return 0;
+ }
+
+ if (g_pCachedWindow == nullptr) 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
+ FRAMEWND *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 = nullptr;
+ }
+ 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_bPostWasCanceled = true;
+ }
+ 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) : nullptr, FALSE);
+
+ if (frm) {
+ if (frm->PaintCallbackProc != nullptr) {
+ 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, nullptr, RGN_COPY);
+ }
+ else CombineRgn(frm->UpdateRgn, frm->UpdateRgn, r2, RGN_OR);
+ DeleteObject(r2);
+ }
+ }
+ }
+ else Sync(QueueAllFramesUpdating, true);
+ }
+ else Sync(QueueAllFramesUpdating, true);
+
+ if (!flag_bUpdateQueued || g_bPostWasCanceled)
+ if (PostMessage(g_clistApi.hwndContactList, UM_UPDATE, 0, 0)) {
+ flag_bUpdateQueued = 1;
+ g_bPostWasCanceled = false;
+ }
+ 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
+ RECT rcPaint, wnd;
+ RECT ru = { 0 };
+ int w1, h1, x1, y1;
+
+ CLUI_SizingGetWindowRect(g_clistApi.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;
+ }
+ }
+
+ int w = rcPaint.right - rcPaint.left;
+ int h = rcPaint.bottom - rcPaint.top;
+ if (w <= 0 || h <= 0) {
+ TRACE("Frame size smaller than 0\n");
+ return 0;
+ }
+ int x = rcPaint.left;
+ int y = rcPaint.top;
+ HDC hdc = CreateCompatibleDC(g_pCachedWindow->hImageDC);
+ HBITMAP n = ske_CreateDIB32(w, h);
+ HBITMAP 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
+ 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 {
+ RECT r;
+ GetClientRect(Frame->hWnd, &r);
+ HRGN 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 = nullptr;
+
+ 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, "Main,ID=ScrollBar,Frame=%S,Part=Back", Frame->name);
+ SkinDrawGlyph(g_pCachedWindow->hImageDC, &rLine, &rLine, req);
+ mir_snprintf(req, "Main,ID=ScrollBar,Frame=%S,Part=Thumb", Frame->name);
+ SkinDrawGlyph(g_pCachedWindow->hImageDC, &rThumb, &rThumb, req);
+ mir_snprintf(req, "Main,ID=ScrollBar, Frame=%S,Part=UpLineButton", Frame->name);
+ SkinDrawGlyph(g_pCachedWindow->hImageDC, &rUpBtn, &rUpBtn, req);
+ mir_snprintf(req, "Main,ID=ScrollBar,Frame=%S,Part=DownLineButton", Frame->name);
+ 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 w = { 0 };
+ if (g_CluiData.fDisableSkinEngine) {
+ FillRect(destDC, BltClientRect, GetSysColorBrush(COLOR_3DFACE));
+ return 0;
+ }
+ ske_ReCreateBackImage(FALSE, nullptr);
+ if (BltClientRect) w = *BltClientRect;
+ else GetClientRect(destHWND, &w);
+ ptChildWnd.x = w.left;
+ ptChildWnd.y = w.top;
+ ClientToScreen(destHWND, &ptChildWnd);
+ ClientToScreen(g_clistApi.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)
+{
+ RECT wnd = { 0 };
+ BOOL IsNewCache = 0;
+ if (g_CluiData.fDisableSkinEngine) return 0;
+ GetClientRect(g_clistApi.hwndContactList, &wnd);
+ if (w) wnd = *w;
+ //-- Check cached.
+ if (g_pCachedWindow == nullptr) {
+ //-- Create New Cache
+ g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
+ g_pCachedWindow->hScreenDC = GetDC(nullptr);
+ 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 = nullptr, hb2 = nullptr;
+ 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)) {
+ HBITMAP 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(g_clistApi.hwndContactList, &w);
+ if (!g_CluiData.fLayered) return ske_ReCreateBackImage(FALSE, nullptr);
+ if (g_pCachedWindow == nullptr)
+ 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;
+}
+
+// Calling queued frame paint procs and refresh image
+int ske_ValidateFrameImageProc(RECT *r)
+{
+ RECT wnd = { 0 };
+ BOOL IsNewCache = 0;
+ BOOL IsForceAllPainting = 0;
+ if (r) wnd = *r;
+ else GetWindowRect(g_clistApi.hwndContactList, &wnd);
+ if (wnd.right - wnd.left == 0 || wnd.bottom - wnd.top == 0)
+ return 0;
+
+ g_mutex_bLockUpdating = 1;
+
+ //-- Check cached.
+ if (g_pCachedWindow == nullptr) {
+ //-- Create New Cache
+ g_pCachedWindow = (CURRWNDIMAGEDATA*)mir_calloc(sizeof(CURRWNDIMAGEDATA));
+ g_pCachedWindow->hScreenDC = GetDC(nullptr);
+ 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, true);
+ }
+ //-- 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();
+ g_mutex_bLockUpdating = 0;
+ if (!mutex_bLockUpdate)
+ ske_UpdateWindowImageRect(&wnd);
+
+ //-- Clear queue
+ Sync(QueueAllFramesUpdating, false);
+ flag_bUpdateQueued = 0;
+ g_bPostWasCanceled = false;
+ return 1;
+}
+
+int ske_UpdateWindowImage()
+{
+ if (MirandaExiting())
+ return 0;
+
+ if (g_CluiData.fLayered) {
+ RECT r;
+ GetWindowRect(g_clistApi.hwndContactList, &r);
+ return ske_UpdateWindowImageRect(&r);
+ }
+ else ske_ReCreateBackImage(FALSE, nullptr);
+ 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, nullptr);
+ if (g_pCachedWindow == nullptr) 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_bFullRepaint) {
+ g_bFullRepaint = false;
+ return ske_ValidateFrameImageProc(&wnd);
+ }
+ ske_JustUpdateWindowImageRect(&wnd);
+ return 0;
+}
+
+void ske_ApplyTranslucency()
+{
+ int IsTransparancy;
+ HWND hwnd = g_clistApi.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), (uint8_t)g_CluiData.bCurrentAlpha, LWA_ALPHA);
+ }
+
+ AniAva_RedrawAllAvatars(FALSE);
+ return;
+}
+
+int ske_JustUpdateWindowImage()
+{
+ RECT r;
+ if (!g_CluiData.fLayered) {
+ ske_ApplyTranslucency();
+ return 0;
+ }
+ GetWindowRect(g_clistApi.hwndContactList, &r);
+ return ske_JustUpdateWindowImageRect(&r);
+}
+
+// Update window image
+int ske_JustUpdateWindowImageRect(RECT *rty)
+{
+ if (!g_CluiData.fLayered) {
+ ske_ApplyTranslucency();
+ return 0;
+ }
+ if (!g_clistApi.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(g_clistApi.hwndContactList, GWL_EXSTYLE) & WS_EX_LAYERED))
+ SetWindowLongPtr(g_clistApi.hwndContactList, GWL_EXSTYLE, GetWindowLongPtr(g_clistApi.hwndContactList, GWL_EXSTYLE) | WS_EX_LAYERED);
+ Sync(SetAlpha, g_CluiData.bCurrentAlpha);
+
+ BLENDFUNCTION bf = { AC_SRC_OVER, 0, g_CluiData.bCurrentAlpha, AC_SRC_ALPHA };
+ UpdateLayeredWindow(g_clistApi.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(g_clistApi.hwndContactList, nullptr, 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 uint32_t ske_HexToARGB(char *Hex)
+{
+ char buf[10] = { 0 };
+ char buf2[11] = { 0 };
+ mir_snprintf(buf, "%s\n", Hex);
+ if (buf[1] == 'x' || buf[1] == 'X')
+ mir_snprintf(buf2, "0x%s\n", buf + 2);
+ else
+ mir_snprintf(buf2, "0x%s\n", buf);
+ buf2[10] = '\0';
+
+ char *st;
+ uint32_t AARRGGBB = strtoul(buf2, &st, 16);
+ uint8_t alpha = (uint8_t)((AARRGGBB & 0xFF000000) >> 24);
+ alpha = 255 - ((alpha == 0) ? 255 : alpha);
+ AARRGGBB = (alpha << 24) + ((AARRGGBB & 0x00FF0000) >> 16) + ((AARRGGBB & 0x000000FF) << 16) + (AARRGGBB & 0x0000FF00);
+ return AARRGGBB;
+}
+
+static wchar_t *ske_ReAppend(wchar_t *lfirst, wchar_t *lsecond, int len)
+{
+ size_t l1 = lfirst ? mir_wstrlen(lfirst) : 0;
+ size_t l2 = (len ? len : (mir_wstrlen(lsecond) + 1));
+ wchar_t *buf = (wchar_t *)mir_alloc((l1 + l2 + 1)*sizeof(wchar_t));
+ if (lfirst) memmove(buf, lfirst, l1*sizeof(wchar_t));
+ memmove(buf + l1, lsecond, l2*sizeof(wchar_t));
+ mir_free(lfirst);
+ if (len) buf[l1 + l2] = '\0';
+ return buf;
+}
+
+wchar_t* ske_ReplaceVar(wchar_t *var)
+{
+ if (!var) return mir_wstrdup(L"");
+ if (!mir_wstrcmpi(var, L"Profile")) {
+ char buf[MAX_PATH] = { 0 };
+ Profile_GetNameA(MAX_PATH, buf);
+
+ char *p = strrchr(buf, '.');
+ if (p) *p = 0;
+
+ mir_free(var);
+ return mir_a2u(buf);
+ }
+
+ mir_free(var);
+ return mir_wstrdup(L"");
+}
+
+wchar_t *ske_ParseText(wchar_t *stzText)
+{
+ size_t len = mir_wstrlen(stzText);
+ wchar_t *result = nullptr;
+ size_t stpos = 0, curpos = 0;
+
+ while (curpos < len) {
+ //1 find first %
+ while (curpos < len && stzText[curpos] != (wchar_t)'%')
+ curpos++;
+ if (curpos < len) { //% found
+ if (curpos - stpos > 0)
+ result = ske_ReAppend(result, stzText + stpos, int(curpos - stpos));
+ stpos = curpos + 1;
+ curpos++;
+ //3 find second %
+ while (curpos < len && stzText[curpos] != (wchar_t)'%')
+ curpos++;
+ if (curpos >= len)
+ break;
+ if (curpos - stpos > 0) {
+ wchar_t *var = (wchar_t *)mir_alloc((curpos - stpos + 1)*sizeof(wchar_t));
+ memcpy(var, stzText + stpos, (curpos - stpos)*sizeof(wchar_t));
+ var[curpos - stpos] = (wchar_t)'\0';
+ var = ske_ReplaceVar(var);
+ result = ske_ReAppend(result, var, 0);
+ mir_free(var);
+ }
+ else result = ske_ReAppend(result, L"%", 0);
+
+ curpos++;
+ stpos = curpos;
+ }
+ else {
+ if (curpos - stpos > 0)
+ result = ske_ReAppend(result, stzText + stpos, int(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)
+{
+ SKINFONT *sf = (SKINFONT*)mir_calloc(sizeof(SKINFONT));
+ if (!sf)
+ return;
+
+ 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;
+
+ char buf[255];
+ strncpy_s(logfont.lfFaceName, GetParamN(szDefineString, buf, sizeof(buf), 0, ',', TRUE), _TRUNCATE);
+ logfont.lfHeight = atoi(GetParamN(szDefineString, buf, sizeof(buf), 1, ',', TRUE));
+ if (logfont.lfHeight < 0) {
+ HDC hdc = CreateCompatibleDC(nullptr);
+ 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, sf, gl_plSkinFonts->realCount);
+ else
+ mir_free(sf);
+ }
+ else mir_free(sf);
+}
+
+/*
+ * ske_CheckHasAlfaChannel - checks if image has at least one uint8_t in alpha chennel
+ * that is not a 0. (is image real 32 bit or just 24 bit)
+ */
+static BOOL ske_CheckHasAlfaChannel(uint8_t *from, int widthByte, int height)
+{
+ uint32_t *pt = (uint32_t*)from;
+ for (int j = 0; j < height; j++) {
+ uint8_t *add = (uint8_t*)pt + widthByte;
+ while (pt < (uint32_t*)add) {
+ if ((*pt & 0xFF000000) != 0)
+ return TRUE;
+ pt++;
+ }
+ pt = (uint32_t*)(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(uint8_t *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(uint8_t *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 uint32_t ske_Blend(uint32_t X1, uint32_t X2, uint8_t alpha)
+{
+ uint8_t a1 = (uint8_t)(X1 >> 24);
+ uint8_t a2 = (uint8_t)(((X2 >> 24)*alpha) >> 8);
+ uint8_t r1 = (uint8_t)(X1 >> 16);
+ uint8_t r2 = (uint8_t)(X2 >> 16);
+ uint8_t g1 = (uint8_t)(X1 >> 8);
+ uint8_t g2 = (uint8_t)(X2 >> 8);
+ uint8_t b1 = (uint8_t)(X1);
+ uint8_t b2 = (uint8_t)(X2);
+
+ uint8_t a_1 = ~a1;
+ uint8_t a_2 = ~a2;
+ uint16_t am = (uint16_t)a1*a_2;
+
+ /* it is possible to use >>8 instead of /255 but it is require additional
+ * checking of alphavalues
+ */
+ uint16_t ar = a1 + (((uint16_t)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;
+
+ uint16_t arm = ar * 255;
+ uint16_t rr = (((uint16_t)r1*am + (uint16_t)r2*a2 * 255)) / arm;
+ uint16_t gr = (((uint16_t)g1*am + (uint16_t)g2*a2 * 255)) / arm;
+ uint16_t br = (((uint16_t)b1*am + (uint16_t)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, uint8_t alpha)
+{
+ 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(nullptr);
+
+ uint8_t *ptPixels;
+ 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) {
+ uint8_t *BottomBuffer, *TopBuffer, *BottomMaskBuffer, *TopMaskBuffer;
+ uint8_t *bb, *tb, *bmb, *tmb;
+ uint8_t *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 = (uint8_t*)bmp_bottom.bmBits;
+ else {
+ BottomBuffer = (uint8_t*)mir_alloc(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 = (uint8_t*)bmp_top.bmBits;
+ else {
+ TopBuffer = (uint8_t*)mir_alloc(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 = (uint8_t*)bmp_bottom_mask.bmBits;
+ bmb = BottomMaskBuffer;
+ }
+ else {
+ BottomMaskBuffer = (uint8_t*)mir_alloc(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 = (uint8_t*)bmp_top_mask.bmBits;
+ tmb = TopMaskBuffer;
+ }
+ else {
+ TopMaskBuffer = (uint8_t*)mir_alloc(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);
+ uint32_t bottom_d = ((uint32_t*)bb)[x];
+ uint32_t top_d = ((uint32_t*)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;
+ }
+ ((uint32_t*)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) mir_free(BottomBuffer);
+ if (!bmp_top.bmBits) mir_free(TopBuffer);
+ if (!bmp_bottom_mask.bmBits) mir_free(BottomMaskBuffer);
+ if (!bmp_top_mask.bmBits) mir_free(TopMaskBuffer);
+ }
+ else {
+ ske_DrawIconEx(tempDC, 0, 0, hBottom, 16, 16, 0, nullptr, DI_NORMAL);
+ ske_DrawIconEx(tempDC, 0, 0, hTop, 16, 16, 0, nullptr, DI_NORMAL | (alpha << 24));
+ }
+
+ DeleteObject(iciBottom.hbmColor);
+ DeleteObject(iciTop.hbmColor);
+ DeleteObject(iciBottom.hbmMask);
+ DeleteObject(iciTop.hbmMask);
+
+ SelectObject(tempDC, oImage);
+ DeleteDC(tempDC);
+
+ uint8_t p[32] = { 0 };
+ HBITMAP nMask = CreateBitmap(16, 16, 1, 1, (void*)&p);
+ {
+ HDC tempDC2 = CreateCompatibleDC(nullptr);
+ HDC tempDC3 = CreateCompatibleDC(nullptr);
+ 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, nullptr, DI_MASK);
+ DrawIconEx(tempDC3, 0, 0, hTop, 16, 16, 0, nullptr, 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(mir_strlen(first)+mir_strlen(separator)+mir_strlen(last)+1); \
+ if (destination) { \
+ *destination = '\0'; \
+ mir_strcat(destination,first); \
+ mir_strcat(destination,separator); \
+ mir_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);
+}
+
+uint8_t SkinDBGetContactSettingByte(MCONTACT hContact, const char *szSection, const char *szKey, uint8_t bDefault)
+{
+ DBVARIANT dbv = { 0 };
+ BOOL bSkinned = FALSE;
+ if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
+ if (dbv.type == DBVT_BYTE) {
+ uint8_t retVal = dbv.bVal;
+ db_free(&dbv);
+ return retVal;
+ }
+ else {
+ db_free(&dbv);
+ if (!bSkinned)
+ return db_get_b(hContact, szSection, szKey, bDefault);
+ }
+ }
+ return bDefault;
+}
+
+uint16_t SkinDBGetContactSettingWord(MCONTACT hContact, const char *szSection, const char *szKey, uint16_t wDefault)
+{
+ BOOL bSkinned = FALSE;
+ DBVARIANT dbv = { 0 };
+ if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
+ if (dbv.type == DBVT_WORD) {
+ uint16_t retVal = dbv.wVal;
+ db_free(&dbv);
+ return retVal;
+ }
+ db_free(&dbv);
+ if (!bSkinned)
+ return db_get_w(hContact, szSection, szKey, wDefault);
+ }
+ return wDefault;
+}
+
+uint32_t SkinDBGetContactSettingDword(MCONTACT hContact, const char *szSection, const char *szKey, uint32_t dwDefault)
+{
+ DBVARIANT dbv = { 0 };
+ BOOL bSkinned = FALSE;
+ if (!SkinDBGetContactSetting(hContact, szSection, szKey, &dbv, &bSkinned)) {
+ if (dbv.type == DBVT_DWORD) {
+ uint32_t 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 5c18867fe2..c13f0c8bb8 100644
--- a/plugins/Clist_modern/src/modern_skinopt.cpp
+++ b/plugins/Clist_modern/src/modern_skinopt.cpp
@@ -1,546 +1,546 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
-Copyright (c) 2000-08 Miranda ICQ/IM project,
-all portions of this codebase are copyrighted to the people
-listed in contributors.txt.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or ( at your option ) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#include "stdafx.h"
-#include "modern_sync.h"
-
-/*******************************/
-// Main skin selection routine //
-/*******************************/
-#define MAX_NAME 100
-
-struct SkinListData
-{
- wchar_t Name[MAX_NAME];
- wchar_t File[MAX_PATH];
-};
-
-HBITMAP hPreviewBitmap = nullptr;
-HTREEITEM AddItemToTree(HWND hTree, wchar_t *itemName, void *data);
-HTREEITEM AddSkinToListFullName(HWND hwndDlg, wchar_t *fullName);
-HTREEITEM AddSkinToList(HWND hwndDlg, wchar_t *path, wchar_t *file);
-HTREEITEM FillAvailableSkinList(HWND hwndDlg);
-
-INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-
-int SkinOptInit(WPARAM wParam, LPARAM)
-{
- if (!g_CluiData.fDisableSkinEngine) {
- //Tabbed settings
- OPTIONSDIALOGPAGE odp = {};
- odp.position = -200000000;
- odp.pfnDlgProc = DlgSkinOpts;
- odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SKIN);
- odp.szGroup.w = LPGENW("Skins");
- odp.szTitle.w = LPGENW("Contact list");
- odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
- g_plugin.addOptions(wParam, &odp);
- }
- 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);
- SetDlgItemText(hwndDlg, IDC_SKINFOLDERLABEL, SkinsFolder);
- {
- HTREEITEM it = FillAvailableSkinList(hwndDlg);
- TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_TREE1), it);
- }
- return 0;
-
- case WM_COMMAND:
- 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:
- {
- HTREEITEM hti = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE1));
- if (hti == nullptr)
- return 0;
-
- TVITEM tvi = { 0 };
- tvi.hItem = hti;
- tvi.mask = TVIF_HANDLE | TVIF_PARAM;
- TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE1), &tvi);
- SkinListData *sd = (SkinListData*)(tvi.lParam);
- if (!sd)
- return 0;
-
- wchar_t Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
- if (!wcschr(sd->File, '%')) {
- GetPrivateProfileString(L"Skin_Description_Section", L"Author", TranslateT("( unknown )"), Author, _countof(Author), sd->File);
- GetPrivateProfileString(L"Skin_Description_Section", L"URL", L"", URL, _countof(URL), sd->File);
- GetPrivateProfileString(L"Skin_Description_Section", L"Contact", L"", Contact, _countof(Contact), sd->File);
- GetPrivateProfileString(L"Skin_Description_Section", L"Description", L"", Description, _countof(Description), sd->File);
- mir_snwprintf(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_snwprintf(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)"),
- L"JID: fyr@jabber.ru",
- L"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) {
- HTREEITEM hti = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE1));
- if (hti == nullptr)
- return 0;
-
- TVITEM tvi = { 0 };
- tvi.hItem = hti;
- tvi.mask = TVIF_HANDLE | TVIF_PARAM;
- TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE1), &tvi);
- SkinListData *sd = (SkinListData*)(tvi.lParam);
- if (!sd)
- return 0;
-
- ske_LoadSkinFromIniFile(sd->File, FALSE);
- ske_LoadSkinFromDB();
- Clist_Broadcast(INTM_RELOADOPTIONS, 0, 0);
- Sync(CLUIFrames_OnClistResize_mod, 0, 0);
- ske_RedrawCompleteWindow();
- Sync(CLUIFrames_OnClistResize_mod, 0, 0);
-
- RECT rc = {};
- GetWindowRect(g_clistApi.hwndContactList, &rc);
- Sync(CLUIFrames_OnMoving, g_clistApi.hwndContactList, &rc);
-
- if (g_hCLUIOptionsWnd) {
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT));
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT));
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT));
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT));
- }
- }
- break;
-
- case IDC_GETSKINS:
- if (HIWORD(wParam) == BN_CLICKED)
- Utils_OpenUrl("https://miranda-ng.org/tags/modern-contact-list/");
- 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
- HBRUSH hbr = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
- DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*)lParam;
- int mWidth = dis->rcItem.right - dis->rcItem.left;
- int 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 = {};
- GetObject(hPreviewBitmap, sizeof(bmp), &bmp);
-
- // GetSize
- float xScale = 1, yScale = 1;
- 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
- POINT imgPos = { 0 };
- 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 0:
- if (((LPNMHDR)lParam)->code == PSN_APPLY) {
- Clist_Broadcast(INTM_RELOADOPTIONS, 0, 0);
- NotifyEventHooks(g_CluiData.hEventBkgrChanged, 0, 0);
- Clist_Broadcast(INTM_INVALIDATE, 0, 0);
- RedrawWindow(GetParent(g_clistApi.hwndContactTree), nullptr, nullptr, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
- }
- break;
-
- case IDC_TREE1:
- NMTREEVIEW *nmtv = (NMTREEVIEW*)lParam;
- if (nmtv == nullptr)
- return 0;
-
- if (nmtv->hdr.code == TVN_SELCHANGED) {
- if (hPreviewBitmap) {
- ske_UnloadGlyphImage(hPreviewBitmap);
- hPreviewBitmap = nullptr;
- }
-
- if (nmtv->itemNew.lParam) {
- SkinListData *sd = (SkinListData*)nmtv->itemNew.lParam;
-
- wchar_t buf[MAX_PATH];
- PathToRelativeW(sd->File, buf);
- SetDlgItemText(hwndDlg, IDC_EDIT_SKIN_FILENAME, buf);
-
- wchar_t prfn[MAX_PATH] = { 0 }, imfn[MAX_PATH] = { 0 }, skinfolder[MAX_PATH] = { 0 };
- GetPrivateProfileString(L"Skin_Description_Section", L"Preview", L"", imfn, _countof(imfn), sd->File);
- IniParser::GetSkinFolder(sd->File, skinfolder);
- mir_snwprintf(prfn, L"%s\\%s", skinfolder, imfn);
- PathToAbsoluteW(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), nullptr, TRUE);
- else { // prepare text
- HTREEITEM hti = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE1));
- if (hti == nullptr)
- return 0;
-
- TVITEM tvi = { 0 };
- tvi.hItem = hti;
- tvi.mask = TVIF_HANDLE | TVIF_PARAM;
- TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE1), &tvi);
- SkinListData *sd2 = (SkinListData*)(tvi.lParam);
- if (!sd2)
- return 0;
-
- wchar_t Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
- if (!wcschr(sd2->File, '%')) {
- GetPrivateProfileString(L"Skin_Description_Section", L"Author", TranslateT("( unknown )"), Author, _countof(Author), sd2->File);
- GetPrivateProfileString(L"Skin_Description_Section", L"URL", L"", URL, _countof(URL), sd2->File);
- GetPrivateProfileString(L"Skin_Description_Section", L"Contact", L"", Contact, _countof(Contact), sd2->File);
- GetPrivateProfileString(L"Skin_Description_Section", L"Description", L"", Description, _countof(Description), sd2->File);
- mir_snwprintf(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"),
- sd2->Name, Description, Author, Contact, URL);
- }
- else {
- mir_snwprintf(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"),
- L"JID: fyr@jabber.ru",
- L"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_DELETEITEM) {
- mir_free_and_nil(nmtv->itemOld.lParam);
- return 0;
- }
- break;
- }
- }
- return 0;
-}
-
-int SearchSkinFiles(HWND hwndDlg, wchar_t *Folder)
-{
- wchar_t mask[MAX_PATH];
- mir_snwprintf(mask, L"%s\\*.msf", Folder);
-
- struct _wfinddata_t fd = {};
- intptr_t hFile = _wfindfirst(mask, &fd);
- if (hFile != -1) {
- do {
- AddSkinToList(hwndDlg, Folder, fd.name);
- } while (!_wfindnext(hFile, &fd));
- _findclose(hFile);
- }
-
- mir_snwprintf(mask, L"%s\\*", Folder);
- hFile = _wfindfirst(mask, &fd);
-
- do {
- if (fd.attrib & _A_SUBDIR && !(mir_wstrcmpi(fd.name, L".") == 0 || mir_wstrcmpi(fd.name, L"..") == 0)) { //Next level of subfolders
- wchar_t path[MAX_PATH];
- mir_snwprintf(path, L"%s\\%s", Folder, fd.name);
- SearchSkinFiles(hwndDlg, path);
- }
- } while (!_wfindnext(hFile, &fd));
-
- _findclose(hFile);
- return 0;
-}
-
-HTREEITEM FillAvailableSkinList(HWND hwndDlg)
-{
- TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_TREE1));
- AddSkinToList(hwndDlg, TranslateT("Default Skin"), L"%Default Skin%");
- int attrib = GetFileAttributes(SkinsFolder);
- if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY))
- SearchSkinFiles(hwndDlg, SkinsFolder);
-
- HTREEITEM res = (HTREEITEM)-1;
- wchar_t skinfull[MAX_PATH];
- ptrW skinfile(db_get_wsa(0, SKIN, "SkinFile"));
- if (skinfile) {
- PathToAbsoluteW(skinfile, skinfull);
- res = AddSkinToListFullName(hwndDlg, skinfull);
- }
-
- return res;
-}
-
-HTREEITEM AddSkinToListFullName(HWND hwndDlg, wchar_t *fullName)
-{
- wchar_t path[MAX_PATH] = {}, file[MAX_PATH] = {};
- mir_wstrncpy(path, fullName, _countof(path));
-
- wchar_t *buf = path + mir_wstrlen(path);
- while (buf > path) {
- if (*buf == '\\') {
- *buf = '\0';
- break;
- }
- buf--;
- }
- buf++;
- mir_wstrncpy(file, buf, _countof(file));
- return AddSkinToList(hwndDlg, path, file);
-}
-
-HTREEITEM AddSkinToList(HWND hwndDlg, wchar_t *path, wchar_t *file)
-{
- wchar_t fullName[MAX_PATH], defskinname[MAX_PATH];
- SkinListData *sd = (SkinListData*)mir_alloc(sizeof(SkinListData));
- if (!sd)
- return nullptr;
-
- if (!file || wcschr(file, '%')) {
- mir_snwprintf(sd->File, L"%%Default Skin%%");
- mir_snwprintf(sd->Name, TranslateT("%Default Skin%"));
- wcsncpy_s(fullName, TranslateT("Default Skin"), _TRUNCATE);
- }
- else {
- mir_snwprintf(fullName, L"%s\\%s", path, file);
- wcsncpy_s(defskinname, file, _TRUNCATE);
- wchar_t *p = wcsrchr(defskinname, '.'); if (p) *p = 0;
- GetPrivateProfileString(L"Skin_Description_Section", L"Name", defskinname, sd->Name, _countof(sd->Name), fullName);
- wcsncpy_s(sd->File, fullName, _TRUNCATE);
- }
- return AddItemToTree(GetDlgItem(hwndDlg, IDC_TREE1), sd->Name, sd);
-}
-
-HTREEITEM FindChild(HWND hTree, HTREEITEM Parent, wchar_t *Caption, void *data)
-{
- HTREEITEM tmp = nullptr;
- if (Parent)
- tmp = TreeView_GetChild(hTree, Parent);
- else
- tmp = TreeView_GetRoot(hTree);
-
- while (tmp) {
- TVITEM tvi;
- wchar_t buf[255];
- tvi.hItem = tmp;
- tvi.mask = TVIF_TEXT | TVIF_HANDLE;
- tvi.pszText = buf;
- tvi.cchTextMax = _countof(buf);
- TreeView_GetItem(hTree, &tvi);
- if (mir_wstrcmpi(Caption, tvi.pszText) == 0) {
- if (!data)
- return tmp;
-
- TVITEM tvi2 = { 0 };
- tvi2.hItem = tmp;
- tvi2.mask = TVIF_HANDLE | TVIF_PARAM;
- TreeView_GetItem(hTree, &tvi2);
- SkinListData *sd = (SkinListData*)tvi2.lParam;
- if (sd)
- if (!mir_wstrcmpi(sd->File, ((SkinListData*)data)->File))
- return tmp;
- }
- tmp = TreeView_GetNextSibling(hTree, tmp);
- }
- return tmp;
-}
-
-HTREEITEM AddItemToTree(HWND hTree, wchar_t *itemName, void *data)
-{
- HTREEITEM cItem = nullptr;
- // Insert item node
- cItem = FindChild(hTree, nullptr, itemName, data);
- if (!cItem) {
- TVINSERTSTRUCT tvis = {};
- 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, LPARAM)
-{
- ptrW skinfile(db_get_wsa(0, SKIN, "SkinFile"));
- if (skinfile) {
- wchar_t skinfull[MAX_PATH];
- PathToAbsoluteW(skinfile, skinfull);
- return (INT_PTR)mir_wstrdup(skinfull);
- }
-
- return 0;
-}
-
-INT_PTR SvcApplySkin(WPARAM, LPARAM lParam)
-{
- ske_LoadSkinFromIniFile((wchar_t*)lParam, FALSE);
- ske_LoadSkinFromDB();
- Clist_Broadcast(INTM_RELOADOPTIONS, 0, 0);
- Sync(CLUIFrames_OnClistResize_mod, 0, 0);
- ske_RedrawCompleteWindow();
- Sync(CLUIFrames_OnClistResize_mod, 0, 0);
-
- HWND hwnd = g_clistApi.hwndContactList;
- RECT rc = { 0 };
- GetWindowRect(hwnd, &rc);
- Sync(CLUIFrames_OnMoving, hwnd, &rc);
-
- g_bChangingMode = TRUE;
- CLUI_UpdateLayeredMode();
- CLUI_ChangeWindowMode();
- SendMessage(g_clistApi.hwndContactTree, WM_SIZE, 0, 0); //forces it to send a cln_listsizechanged
- CLUI_ReloadCLUIOptions();
- cliShowHide(true);
- g_bChangingMode = FALSE;
-
- if (g_hCLUIOptionsWnd) {
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT));
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT));
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT));
- SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT));
- }
- return 0;
-}
-
-INT_PTR SvcPreviewSkin(WPARAM wParam, LPARAM lParam)
-{
- DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*)wParam;
- RECT workRect = dis->rcItem;
- OffsetRect(&workRect, -workRect.left, -workRect.top);
-
- if (lParam) {
- wchar_t prfn[MAX_PATH] = { 0 };
- wchar_t imfn[MAX_PATH] = { 0 };
- wchar_t skinfolder[MAX_PATH] = { 0 };
- GetPrivateProfileString(L"Skin_Description_Section", L"Preview", L"", imfn, _countof(imfn), (LPCTSTR)lParam);
- IniParser::GetSkinFolder((LPCTSTR)lParam, skinfolder);
- mir_snwprintf(prfn, L"%s\\%s", skinfolder, imfn);
- PathToAbsoluteW(prfn, imfn);
-
- hPreviewBitmap = ske_LoadGlyphImage(imfn);
- if (hPreviewBitmap) {
- // variables
- BITMAP bmp = { 0 };
- GetObject(hPreviewBitmap, sizeof(BITMAP), &bmp);
-
- // GetSize
- float xScale = 1, yScale = 1;
- 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
- POINT imgPos = { 0 };
- 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-23 Miranda NG team (https://miranda-ng.org),
+Copyright (c) 2000-08 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or ( at your option ) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+#include "modern_sync.h"
+
+/*******************************/
+// Main skin selection routine //
+/*******************************/
+#define MAX_NAME 100
+
+struct SkinListData
+{
+ wchar_t Name[MAX_NAME];
+ wchar_t File[MAX_PATH];
+};
+
+HBITMAP hPreviewBitmap = nullptr;
+HTREEITEM AddItemToTree(HWND hTree, wchar_t *itemName, void *data);
+HTREEITEM AddSkinToListFullName(HWND hwndDlg, wchar_t *fullName);
+HTREEITEM AddSkinToList(HWND hwndDlg, wchar_t *path, wchar_t *file);
+HTREEITEM FillAvailableSkinList(HWND hwndDlg);
+
+INT_PTR CALLBACK DlgSkinOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+int SkinOptInit(WPARAM wParam, LPARAM)
+{
+ if (!g_CluiData.fDisableSkinEngine) {
+ //Tabbed settings
+ OPTIONSDIALOGPAGE odp = {};
+ odp.position = -200000000;
+ odp.pfnDlgProc = DlgSkinOpts;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SKIN);
+ odp.szGroup.w = LPGENW("Skins");
+ odp.szTitle.w = LPGENW("Contact list");
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+ g_plugin.addOptions(wParam, &odp);
+ }
+ 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);
+ SetDlgItemText(hwndDlg, IDC_SKINFOLDERLABEL, SkinsFolder);
+ {
+ HTREEITEM it = FillAvailableSkinList(hwndDlg);
+ TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_TREE1), it);
+ }
+ return 0;
+
+ case WM_COMMAND:
+ 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:
+ {
+ HTREEITEM hti = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE1));
+ if (hti == nullptr)
+ return 0;
+
+ TVITEM tvi = { 0 };
+ tvi.hItem = hti;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE1), &tvi);
+ SkinListData *sd = (SkinListData*)(tvi.lParam);
+ if (!sd)
+ return 0;
+
+ wchar_t Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
+ if (!wcschr(sd->File, '%')) {
+ GetPrivateProfileString(L"Skin_Description_Section", L"Author", TranslateT("( unknown )"), Author, _countof(Author), sd->File);
+ GetPrivateProfileString(L"Skin_Description_Section", L"URL", L"", URL, _countof(URL), sd->File);
+ GetPrivateProfileString(L"Skin_Description_Section", L"Contact", L"", Contact, _countof(Contact), sd->File);
+ GetPrivateProfileString(L"Skin_Description_Section", L"Description", L"", Description, _countof(Description), sd->File);
+ mir_snwprintf(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_snwprintf(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)"),
+ L"JID: fyr@jabber.ru",
+ L"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) {
+ HTREEITEM hti = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE1));
+ if (hti == nullptr)
+ return 0;
+
+ TVITEM tvi = { 0 };
+ tvi.hItem = hti;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE1), &tvi);
+ SkinListData *sd = (SkinListData*)(tvi.lParam);
+ if (!sd)
+ return 0;
+
+ ske_LoadSkinFromIniFile(sd->File, FALSE);
+ ske_LoadSkinFromDB();
+ Clist_Broadcast(INTM_RELOADOPTIONS, 0, 0);
+ Sync(CLUIFrames_OnClistResize_mod, 0, 0);
+ ske_RedrawCompleteWindow();
+ Sync(CLUIFrames_OnClistResize_mod, 0, 0);
+
+ RECT rc = {};
+ GetWindowRect(g_clistApi.hwndContactList, &rc);
+ Sync(CLUIFrames_OnMoving, g_clistApi.hwndContactList, &rc);
+
+ if (g_hCLUIOptionsWnd) {
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT));
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT));
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT));
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT));
+ }
+ }
+ break;
+
+ case IDC_GETSKINS:
+ if (HIWORD(wParam) == BN_CLICKED)
+ Utils_OpenUrl("https://miranda-ng.org/tags/modern-contact-list/");
+ 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
+ HBRUSH hbr = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*)lParam;
+ int mWidth = dis->rcItem.right - dis->rcItem.left;
+ int 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 = {};
+ GetObject(hPreviewBitmap, sizeof(bmp), &bmp);
+
+ // GetSize
+ float xScale = 1, yScale = 1;
+ 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
+ POINT imgPos = { 0 };
+ 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 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY) {
+ Clist_Broadcast(INTM_RELOADOPTIONS, 0, 0);
+ NotifyEventHooks(g_CluiData.hEventBkgrChanged, 0, 0);
+ Clist_Broadcast(INTM_INVALIDATE, 0, 0);
+ RedrawWindow(GetParent(g_clistApi.hwndContactTree), nullptr, nullptr, RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
+ }
+ break;
+
+ case IDC_TREE1:
+ NMTREEVIEW *nmtv = (NMTREEVIEW*)lParam;
+ if (nmtv == nullptr)
+ return 0;
+
+ if (nmtv->hdr.code == TVN_SELCHANGED) {
+ if (hPreviewBitmap) {
+ ske_UnloadGlyphImage(hPreviewBitmap);
+ hPreviewBitmap = nullptr;
+ }
+
+ if (nmtv->itemNew.lParam) {
+ SkinListData *sd = (SkinListData*)nmtv->itemNew.lParam;
+
+ wchar_t buf[MAX_PATH];
+ PathToRelativeW(sd->File, buf);
+ SetDlgItemText(hwndDlg, IDC_EDIT_SKIN_FILENAME, buf);
+
+ wchar_t prfn[MAX_PATH] = { 0 }, imfn[MAX_PATH] = { 0 }, skinfolder[MAX_PATH] = { 0 };
+ GetPrivateProfileString(L"Skin_Description_Section", L"Preview", L"", imfn, _countof(imfn), sd->File);
+ IniParser::GetSkinFolder(sd->File, skinfolder);
+ mir_snwprintf(prfn, L"%s\\%s", skinfolder, imfn);
+ PathToAbsoluteW(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), nullptr, TRUE);
+ else { // prepare text
+ HTREEITEM hti = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_TREE1));
+ if (hti == nullptr)
+ return 0;
+
+ TVITEM tvi = { 0 };
+ tvi.hItem = hti;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_TREE1), &tvi);
+ SkinListData *sd2 = (SkinListData*)(tvi.lParam);
+ if (!sd2)
+ return 0;
+
+ wchar_t Author[255], URL[MAX_PATH], Contact[255], Description[400], text[2000];
+ if (!wcschr(sd2->File, '%')) {
+ GetPrivateProfileString(L"Skin_Description_Section", L"Author", TranslateT("( unknown )"), Author, _countof(Author), sd2->File);
+ GetPrivateProfileString(L"Skin_Description_Section", L"URL", L"", URL, _countof(URL), sd2->File);
+ GetPrivateProfileString(L"Skin_Description_Section", L"Contact", L"", Contact, _countof(Contact), sd2->File);
+ GetPrivateProfileString(L"Skin_Description_Section", L"Description", L"", Description, _countof(Description), sd2->File);
+ mir_snwprintf(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"),
+ sd2->Name, Description, Author, Contact, URL);
+ }
+ else {
+ mir_snwprintf(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"),
+ L"JID: fyr@jabber.ru",
+ L"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_DELETEITEM) {
+ mir_free_and_nil(nmtv->itemOld.lParam);
+ return 0;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+int SearchSkinFiles(HWND hwndDlg, wchar_t *Folder)
+{
+ wchar_t mask[MAX_PATH];
+ mir_snwprintf(mask, L"%s\\*.msf", Folder);
+
+ struct _wfinddata_t fd = {};
+ intptr_t hFile = _wfindfirst(mask, &fd);
+ if (hFile != -1) {
+ do {
+ AddSkinToList(hwndDlg, Folder, fd.name);
+ } while (!_wfindnext(hFile, &fd));
+ _findclose(hFile);
+ }
+
+ mir_snwprintf(mask, L"%s\\*", Folder);
+ hFile = _wfindfirst(mask, &fd);
+
+ do {
+ if (fd.attrib & _A_SUBDIR && !(mir_wstrcmpi(fd.name, L".") == 0 || mir_wstrcmpi(fd.name, L"..") == 0)) { //Next level of subfolders
+ wchar_t path[MAX_PATH];
+ mir_snwprintf(path, L"%s\\%s", Folder, fd.name);
+ SearchSkinFiles(hwndDlg, path);
+ }
+ } while (!_wfindnext(hFile, &fd));
+
+ _findclose(hFile);
+ return 0;
+}
+
+HTREEITEM FillAvailableSkinList(HWND hwndDlg)
+{
+ TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_TREE1));
+ AddSkinToList(hwndDlg, TranslateT("Default Skin"), L"%Default Skin%");
+ int attrib = GetFileAttributes(SkinsFolder);
+ if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY))
+ SearchSkinFiles(hwndDlg, SkinsFolder);
+
+ HTREEITEM res = (HTREEITEM)-1;
+ wchar_t skinfull[MAX_PATH];
+ ptrW skinfile(db_get_wsa(0, SKIN, "SkinFile"));
+ if (skinfile) {
+ PathToAbsoluteW(skinfile, skinfull);
+ res = AddSkinToListFullName(hwndDlg, skinfull);
+ }
+
+ return res;
+}
+
+HTREEITEM AddSkinToListFullName(HWND hwndDlg, wchar_t *fullName)
+{
+ wchar_t path[MAX_PATH] = {}, file[MAX_PATH] = {};
+ mir_wstrncpy(path, fullName, _countof(path));
+
+ wchar_t *buf = path + mir_wstrlen(path);
+ while (buf > path) {
+ if (*buf == '\\') {
+ *buf = '\0';
+ break;
+ }
+ buf--;
+ }
+ buf++;
+ mir_wstrncpy(file, buf, _countof(file));
+ return AddSkinToList(hwndDlg, path, file);
+}
+
+HTREEITEM AddSkinToList(HWND hwndDlg, wchar_t *path, wchar_t *file)
+{
+ wchar_t fullName[MAX_PATH], defskinname[MAX_PATH];
+ SkinListData *sd = (SkinListData*)mir_alloc(sizeof(SkinListData));
+ if (!sd)
+ return nullptr;
+
+ if (!file || wcschr(file, '%')) {
+ mir_snwprintf(sd->File, L"%%Default Skin%%");
+ mir_snwprintf(sd->Name, TranslateT("%Default Skin%"));
+ wcsncpy_s(fullName, TranslateT("Default Skin"), _TRUNCATE);
+ }
+ else {
+ mir_snwprintf(fullName, L"%s\\%s", path, file);
+ wcsncpy_s(defskinname, file, _TRUNCATE);
+ wchar_t *p = wcsrchr(defskinname, '.'); if (p) *p = 0;
+ GetPrivateProfileString(L"Skin_Description_Section", L"Name", defskinname, sd->Name, _countof(sd->Name), fullName);
+ wcsncpy_s(sd->File, fullName, _TRUNCATE);
+ }
+ return AddItemToTree(GetDlgItem(hwndDlg, IDC_TREE1), sd->Name, sd);
+}
+
+HTREEITEM FindChild(HWND hTree, HTREEITEM Parent, wchar_t *Caption, void *data)
+{
+ HTREEITEM tmp = nullptr;
+ if (Parent)
+ tmp = TreeView_GetChild(hTree, Parent);
+ else
+ tmp = TreeView_GetRoot(hTree);
+
+ while (tmp) {
+ TVITEM tvi;
+ wchar_t buf[255];
+ tvi.hItem = tmp;
+ tvi.mask = TVIF_TEXT | TVIF_HANDLE;
+ tvi.pszText = buf;
+ tvi.cchTextMax = _countof(buf);
+ TreeView_GetItem(hTree, &tvi);
+ if (mir_wstrcmpi(Caption, tvi.pszText) == 0) {
+ if (!data)
+ return tmp;
+
+ TVITEM tvi2 = { 0 };
+ tvi2.hItem = tmp;
+ tvi2.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(hTree, &tvi2);
+ SkinListData *sd = (SkinListData*)tvi2.lParam;
+ if (sd)
+ if (!mir_wstrcmpi(sd->File, ((SkinListData*)data)->File))
+ return tmp;
+ }
+ tmp = TreeView_GetNextSibling(hTree, tmp);
+ }
+ return tmp;
+}
+
+HTREEITEM AddItemToTree(HWND hTree, wchar_t *itemName, void *data)
+{
+ HTREEITEM cItem = nullptr;
+ // Insert item node
+ cItem = FindChild(hTree, nullptr, itemName, data);
+ if (!cItem) {
+ TVINSERTSTRUCT tvis = {};
+ 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, LPARAM)
+{
+ ptrW skinfile(db_get_wsa(0, SKIN, "SkinFile"));
+ if (skinfile) {
+ wchar_t skinfull[MAX_PATH];
+ PathToAbsoluteW(skinfile, skinfull);
+ return (INT_PTR)mir_wstrdup(skinfull);
+ }
+
+ return 0;
+}
+
+INT_PTR SvcApplySkin(WPARAM, LPARAM lParam)
+{
+ ske_LoadSkinFromIniFile((wchar_t*)lParam, FALSE);
+ ske_LoadSkinFromDB();
+ Clist_Broadcast(INTM_RELOADOPTIONS, 0, 0);
+ Sync(CLUIFrames_OnClistResize_mod, 0, 0);
+ ske_RedrawCompleteWindow();
+ Sync(CLUIFrames_OnClistResize_mod, 0, 0);
+
+ HWND hwnd = g_clistApi.hwndContactList;
+ RECT rc = { 0 };
+ GetWindowRect(hwnd, &rc);
+ Sync(CLUIFrames_OnMoving, hwnd, &rc);
+
+ g_bChangingMode = TRUE;
+ CLUI_UpdateLayeredMode();
+ CLUI_ChangeWindowMode();
+ SendMessage(g_clistApi.hwndContactTree, WM_SIZE, 0, 0); //forces it to send a cln_listsizechanged
+ CLUI_ReloadCLUIOptions();
+ cliShowHide(true);
+ g_bChangingMode = FALSE;
+
+ if (g_hCLUIOptionsWnd) {
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_LEFTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "LeftClientMargin", SETTING_LEFTCLIENTMARIGN_DEFAULT));
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_RIGHTMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "RightClientMargin", SETTING_RIGHTCLIENTMARIGN_DEFAULT));
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_TOPMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "TopClientMargin", SETTING_TOPCLIENTMARIGN_DEFAULT));
+ SendDlgItemMessage(g_hCLUIOptionsWnd, IDC_BOTTOMMARGINSPIN, UDM_SETPOS, 0, db_get_b(0, "CLUI", "BottomClientMargin", SETTING_BOTTOMCLIENTMARIGN_DEFAULT));
+ }
+ return 0;
+}
+
+INT_PTR SvcPreviewSkin(WPARAM wParam, LPARAM lParam)
+{
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*)wParam;
+ RECT workRect = dis->rcItem;
+ OffsetRect(&workRect, -workRect.left, -workRect.top);
+
+ if (lParam) {
+ wchar_t prfn[MAX_PATH] = { 0 };
+ wchar_t imfn[MAX_PATH] = { 0 };
+ wchar_t skinfolder[MAX_PATH] = { 0 };
+ GetPrivateProfileString(L"Skin_Description_Section", L"Preview", L"", imfn, _countof(imfn), (LPCTSTR)lParam);
+ IniParser::GetSkinFolder((LPCTSTR)lParam, skinfolder);
+ mir_snwprintf(prfn, L"%s\\%s", skinfolder, imfn);
+ PathToAbsoluteW(prfn, imfn);
+
+ hPreviewBitmap = ske_LoadGlyphImage(imfn);
+ if (hPreviewBitmap) {
+ // variables
+ BITMAP bmp = { 0 };
+ GetObject(hPreviewBitmap, sizeof(BITMAP), &bmp);
+
+ // GetSize
+ float xScale = 1, yScale = 1;
+ 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
+ POINT imgPos = { 0 };
+ 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;
+}
diff --git a/plugins/Clist_modern/src/modern_skinselector.cpp b/plugins/Clist_modern/src/modern_skinselector.cpp
index e1a5a0633c..d68177c48b 100644
--- a/plugins/Clist_modern/src/modern_skinselector.cpp
+++ b/plugins/Clist_modern/src/modern_skinselector.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_skinselector.h b/plugins/Clist_modern/src/modern_skinselector.h
index a5e4ed6f94..c4ea040f4d 100644
--- a/plugins/Clist_modern/src/modern_skinselector.h
+++ b/plugins/Clist_modern/src/modern_skinselector.h
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_static_clui.h b/plugins/Clist_modern/src/modern_static_clui.h
index a13723f8c0..b416c3f001 100644
--- a/plugins/Clist_modern/src/modern_static_clui.h
+++ b/plugins/Clist_modern/src/modern_static_clui.h
@@ -1,114 +1,114 @@
-/*
-
-Miranda NG: the free IM client for Microsoft* Windows*
-
-Copyright (C) 2012-22 Miranda NG team (https://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.
-*/
-
-/************************************************************************/
-/** FILE CONTAINS HEADER PART FOR .../modernb/clui.c file **/
-/** **/
-/** !!! DO NOT INCLUDE IN TO OTHER FILES !!! **/
-/************************************************************************/
-
-/* Definitions */
-#pragma once
-
-#define TM_AUTOALPHA 1
-#define TM_DELAYEDSIZING 2
-#define TM_BRINGOUTTIMEOUT 3
-#define TM_BRINGINTIMEOUT 4
-#define TM_UPDATEBRINGTIMER 5
-#define TM_SMOTHALPHATRANSITION 20
-#define TM_WINDOWUPDATE 100
-#define TM_STATUSBARUPDATE 200
-
-#define MS_CLUI_SHOWMAINMENU "CList/ShowMainMenu"
-#define MS_CLUI_SHOWSTATUSMENU "CList/ShowStatusMenu"
-
-#define AC_SRC_NO_PREMULT_ALPHA 0x01
-#define AC_SRC_NO_ALPHA 0x02
-#define AC_DST_NO_PREMULT_ALPHA 0x10
-#define AC_DST_NO_ALPHA 0x20
-
-#define ANIMATION_STEP 40
-
-#define AEROGLASS_MINALPHA 24
-
-/* Declaration of prototypes in other modules */
-
-int ClcEnterDragToScroll(HWND hwnd, int Y);
-
-int CListMod_ContactListShutdownProc(WPARAM wParam, LPARAM lParam);
-int CListMod_HideWindow(HWND hwndContactList, int mode);
-
-int CLUIServices_LoadModule(void);
-INT_PTR CLUIServices_SortList(WPARAM wParam, LPARAM lParam);
-
-void Docking_GetMonitorRectFromWindow(HWND hWnd, RECT *rc);
-
-int EventArea_Create(HWND hCluiWnd);
-
-int ExtraImage_ExtraIDToColumnNum(int extra);
-
-int ModernSkinButtonLoadModule();
-int ModernSkinButton_ReposButtons(HWND parent, uint8_t draw, RECT *r);
-
-void ske_ApplyTranslucency();
-HBITMAP ske_CreateDIB32(int cx, int cy);
-HBITMAP ske_CreateDIB32Point(int cx, int cy, void ** bits);
-int ske_JustUpdateWindowImage();
-void ske_LoadSkinFromDB(void);
-int ske_RedrawCompleteWindow();
-int ske_UpdateWindowImage();
-int ske_ValidateFrameImageProc(RECT *r);
-
-HWND StatusBar_Create(HWND parent);
-
-int UnhookAll();
-
-/* Module function prototypes */
-
-int CLUI_IsInMainWindow(HWND hwnd);
-int CLUI_SizingOnBorder(POINT pt, int size);
-int CLUI_SmoothAlphaTransition(HWND hwnd, uint8_t GoalAlpha, BOOL wParam);
-int CLUI_TestCursorOnBorders();
-
-static int CLUI_SmoothAlphaThreadTransition();
-
-/* structs */
-
-struct CHECKFILLING
-{
- HDC hDC;
- RECT rcRect;
-};
-
-int CheckFramesPos(RECT *wr); //cluiframes.c
-int CLUIFrames_ApplyNewSizes(int mode); //cluiframes.c
-int CLUIFrames_GetTotalHeight(); //cluiframes.c
-int CLUIFrames_RepaintSubContainers(); //cluiframes.c
-int CLUIFramesGetMinHeight(); //cluiframes.c
-
-int SizeFramesByWindowRect(RECT *r, HDWP * PosBatch, int mode); //cluiframes.c
-
-int InitSkinHotKeys();
-BOOL amWakeThread();
-void CreateViewModeFrame();
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (C) 2012-23 Miranda NG team (https://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.
+*/
+
+/************************************************************************/
+/** FILE CONTAINS HEADER PART FOR .../modernb/clui.c file **/
+/** **/
+/** !!! DO NOT INCLUDE IN TO OTHER FILES !!! **/
+/************************************************************************/
+
+/* Definitions */
+#pragma once
+
+#define TM_AUTOALPHA 1
+#define TM_DELAYEDSIZING 2
+#define TM_BRINGOUTTIMEOUT 3
+#define TM_BRINGINTIMEOUT 4
+#define TM_UPDATEBRINGTIMER 5
+#define TM_SMOTHALPHATRANSITION 20
+#define TM_WINDOWUPDATE 100
+#define TM_STATUSBARUPDATE 200
+
+#define MS_CLUI_SHOWMAINMENU "CList/ShowMainMenu"
+#define MS_CLUI_SHOWSTATUSMENU "CList/ShowStatusMenu"
+
+#define AC_SRC_NO_PREMULT_ALPHA 0x01
+#define AC_SRC_NO_ALPHA 0x02
+#define AC_DST_NO_PREMULT_ALPHA 0x10
+#define AC_DST_NO_ALPHA 0x20
+
+#define ANIMATION_STEP 40
+
+#define AEROGLASS_MINALPHA 24
+
+/* Declaration of prototypes in other modules */
+
+int ClcEnterDragToScroll(HWND hwnd, int Y);
+
+int CListMod_ContactListShutdownProc(WPARAM wParam, LPARAM lParam);
+int CListMod_HideWindow(HWND hwndContactList, int mode);
+
+int CLUIServices_LoadModule(void);
+INT_PTR CLUIServices_SortList(WPARAM wParam, LPARAM lParam);
+
+void Docking_GetMonitorRectFromWindow(HWND hWnd, RECT *rc);
+
+int EventArea_Create(HWND hCluiWnd);
+
+int ExtraImage_ExtraIDToColumnNum(int extra);
+
+int ModernSkinButtonLoadModule();
+int ModernSkinButton_ReposButtons(HWND parent, uint8_t draw, RECT *r);
+
+void ske_ApplyTranslucency();
+HBITMAP ske_CreateDIB32(int cx, int cy);
+HBITMAP ske_CreateDIB32Point(int cx, int cy, void ** bits);
+int ske_JustUpdateWindowImage();
+void ske_LoadSkinFromDB(void);
+int ske_RedrawCompleteWindow();
+int ske_UpdateWindowImage();
+int ske_ValidateFrameImageProc(RECT *r);
+
+HWND StatusBar_Create(HWND parent);
+
+int UnhookAll();
+
+/* Module function prototypes */
+
+int CLUI_IsInMainWindow(HWND hwnd);
+int CLUI_SizingOnBorder(POINT pt, int size);
+int CLUI_SmoothAlphaTransition(HWND hwnd, uint8_t GoalAlpha, BOOL wParam);
+int CLUI_TestCursorOnBorders();
+
+static int CLUI_SmoothAlphaThreadTransition();
+
+/* structs */
+
+struct CHECKFILLING
+{
+ HDC hDC;
+ RECT rcRect;
+};
+
+int CheckFramesPos(RECT *wr); //cluiframes.c
+int CLUIFrames_ApplyNewSizes(int mode); //cluiframes.c
+int CLUIFrames_GetTotalHeight(); //cluiframes.c
+int CLUIFrames_RepaintSubContainers(); //cluiframes.c
+int CLUIFramesGetMinHeight(); //cluiframes.c
+
+int SizeFramesByWindowRect(RECT *r, HDWP * PosBatch, int mode); //cluiframes.c
+
+int InitSkinHotKeys();
+BOOL amWakeThread();
+void CreateViewModeFrame();
diff --git a/plugins/Clist_modern/src/modern_statusbar_options.cpp b/plugins/Clist_modern/src/modern_statusbar_options.cpp
index 1df676fafe..953920171e 100644
--- a/plugins/Clist_modern/src/modern_statusbar_options.cpp
+++ b/plugins/Clist_modern/src/modern_statusbar_options.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.
diff --git a/plugins/Clist_modern/src/modern_toolbar.cpp b/plugins/Clist_modern/src/modern_toolbar.cpp
index c6c7844c38..564cb31117 100644
--- a/plugins/Clist_modern/src/modern_toolbar.cpp
+++ b/plugins/Clist_modern/src/modern_toolbar.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org),
Copyright (c) 2000-08 Miranda ICQ/IM project,
Copyright 2007 Artem Shpynov
diff --git a/plugins/Clist_modern/src/modern_viewmodebar.cpp b/plugins/Clist_modern/src/modern_viewmodebar.cpp
index 5507206936..6e687e9407 100644
--- a/plugins/Clist_modern/src/modern_viewmodebar.cpp
+++ b/plugins/Clist_modern/src/modern_viewmodebar.cpp
@@ -2,7 +2,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org),
Copyright (c) 2000-03 Miranda ICQ/IM project,
all portions of this codebase are copyrighted to the people
listed in contributors.txt.
diff --git a/plugins/Clist_modern/src/stdafx.h b/plugins/Clist_modern/src/stdafx.h
index 814ee05d0b..683384d396 100644
--- a/plugins/Clist_modern/src/stdafx.h
+++ b/plugins/Clist_modern/src/stdafx.h
@@ -5,7 +5,7 @@
Miranda NG: the free IM client for Microsoft* Windows*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org),
+Copyright (C) 2012-23 Miranda NG team (https://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.