diff options
Diffstat (limited to 'src/modules/skin')
-rw-r--r-- | src/modules/skin/hotkeys.cpp | 1465 | ||||
-rw-r--r-- | src/modules/skin/skinicons.cpp | 489 | ||||
-rw-r--r-- | src/modules/skin/sounds.cpp | 469 |
3 files changed, 2423 insertions, 0 deletions
diff --git a/src/modules/skin/hotkeys.cpp b/src/modules/skin/hotkeys.cpp new file mode 100644 index 0000000000..cd87fda1a7 --- /dev/null +++ b/src/modules/skin/hotkeys.cpp @@ -0,0 +1,1465 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 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 "commonheaders.h"
+#include <m_hotkeys.h>
+
+#define DBMODULENAME "SkinHotKeys"
+#define WM_HOTKEYUNREGISTERED (WM_USER+721)
+
+typedef enum { HKT_GLOBAL, HKT_LOCAL, HKT_MANUAL, HKT_COUNT } THotkeyType;
+
+typedef struct _THotkeyItem THotkeyItem;
+struct _THotkeyItem
+{
+ THotkeyType type;
+ char *pszService, *pszName; // pszName is valid _only_ for "root" hotkeys
+ TCHAR *ptszSection, *ptszDescription;
+ TCHAR *ptszSection_tr, *ptszDescription_tr;
+ LPARAM lParam;
+ WORD DefHotkey, Hotkey;
+ bool Enabled;
+ ATOM idHotkey;
+
+ THotkeyItem *rootHotkey;
+ int nSubHotkeys;
+ bool allowSubHotkeys;
+
+ bool OptChanged, OptDeleted, OptNew;
+ WORD OptHotkey;
+ THotkeyType OptType;
+ bool OptEnabled;
+
+ bool UnregisterHotkey; // valid only during WM_APP message in options UI, used to remove unregistered hotkeys from options
+};
+
+static int sttCompareHotkeys(const THotkeyItem *p1, const THotkeyItem *p2)
+{
+ int res;
+ if ( res = lstrcmp( p1->ptszSection_tr, p2->ptszSection_tr ))
+ return res;
+ if ( res = lstrcmp( p1->ptszDescription_tr, p2->ptszDescription_tr ))
+ return res;
+ if (!p1->rootHotkey && p2->rootHotkey)
+ return -1;
+ if (p1->rootHotkey && !p2->rootHotkey)
+ return 1;
+ return 0;
+}
+
+static LIST<THotkeyItem> hotkeys( 10, sttCompareHotkeys );
+
+static void sttFreeHotkey(THotkeyItem *item);
+
+static BOOL bModuleInitialized = FALSE;
+static HWND g_hwndHotkeyHost = NULL;
+static HWND g_hwndOptions = NULL;
+static DWORD g_pid = 0;
+static int g_hotkeyCount = 0;
+static HANDLE hEvChanged = 0;
+
+static LRESULT CALLBACK sttHotkeyHostWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static TCHAR *sttHokeyVkToName(WORD vkKey);
+static void sttHotkeyEditCreate(HWND hwnd);
+static void sttHotkeyEditDestroy(HWND hwnd);
+static LRESULT CALLBACK sttHotkeyEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+static void sttRegisterHotkeys();
+static void sttUnregisterHotkeys();
+
+static INT_PTR svcHotkeySubclass(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyUnsubclass(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyRegister(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyUnregister(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyCheck(WPARAM wParam, LPARAM lParam);
+
+HHOOK hhkKeyboard = NULL;
+static LRESULT CALLBACK sttKeyboardProc(int code, WPARAM wParam, LPARAM lParam);
+
+static void sttWordToModAndVk(WORD w, BYTE *mod, BYTE *vk)
+{
+ *mod = 0;
+ if (HIBYTE(w) & HOTKEYF_CONTROL) *mod |= MOD_CONTROL;
+ if (HIBYTE(w) & HOTKEYF_SHIFT) *mod |= MOD_SHIFT;
+ if (HIBYTE(w) & HOTKEYF_ALT) *mod |= MOD_ALT;
+ if (HIBYTE(w) & HOTKEYF_EXT) *mod |= MOD_WIN;
+ *vk = LOBYTE(w);
+}
+
+static LRESULT CALLBACK sttHotkeyHostWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_HOTKEY ) {
+ int i;
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+ if (item->type != HKT_GLOBAL) continue;
+ if (!item->Enabled) continue;
+ if (item->pszService && (wParam == item->idHotkey)) {
+ CallService(item->pszService, 0, item->lParam);
+ break;
+ } }
+
+ return FALSE;
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK sttKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
+{
+ if (code == HC_ACTION && !(HIWORD(lParam) & KF_UP)) {
+ int i;
+ BYTE mod=0, vk=wParam;
+
+ if ( vk ) {
+ if (GetAsyncKeyState(VK_CONTROL)) mod |= MOD_CONTROL;
+ if (GetAsyncKeyState(VK_MENU)) mod |= MOD_ALT;
+ if (GetAsyncKeyState(VK_SHIFT)) mod |= MOD_SHIFT;
+ if (GetAsyncKeyState(VK_LWIN) || GetAsyncKeyState(VK_RWIN)) mod |= MOD_WIN;
+
+ for ( i = 0; i < hotkeys.getCount(); i++ ) {
+ THotkeyItem *item = hotkeys[i];
+ BYTE hkMod, hkVk;
+ if (item->type != HKT_LOCAL) continue;
+ sttWordToModAndVk(item->Hotkey, &hkMod, &hkVk);
+ if (!hkVk) continue;
+ if (!item->Enabled) continue;
+ if (item->pszService && (vk == hkVk) && (mod == hkMod)) {
+ CallService(item->pszService, 0, item->lParam);
+ return TRUE;
+ } } } }
+
+ return CallNextHookEx(hhkKeyboard, code, wParam, lParam);
+}
+
+static INT_PTR svcHotkeySubclass(WPARAM wParam, LPARAM)
+{
+ sttHotkeyEditCreate((HWND)wParam);
+ return 0;
+}
+
+static INT_PTR svcHotkeyUnsubclass(WPARAM wParam, LPARAM)
+{
+ sttHotkeyEditDestroy((HWND)wParam);
+ return 0;
+}
+
+static INT_PTR svcHotkeyRegister(WPARAM wParam, LPARAM lParam)
+{
+ HOTKEYDESC *desc = (HOTKEYDESC *)lParam;
+ if ( desc->cbSize != sizeof(HOTKEYDESC) && desc->cbSize != HOTKEYDESC_SIZE_V1 )
+ return 0;
+
+ THotkeyItem *item = ( THotkeyItem* )mir_alloc(sizeof(THotkeyItem));
+ #if defined( _UNICODE )
+ DWORD dwFlags = ( desc->cbSize >= sizeof(HOTKEYDESC)) ? desc->dwFlags : 0;
+ if ( dwFlags & HKD_UNICODE ) {
+ item->ptszSection = mir_tstrdup( desc->ptszSection );
+ item->ptszDescription = mir_tstrdup( desc->ptszDescription );
+ }
+ else {
+ item->ptszSection = mir_a2u( desc->pszSection );
+ item->ptszDescription = mir_a2u( desc->pszDescription );
+ }
+ #else
+ item->ptszSection = mir_tstrdup( desc->pszSection );
+ item->ptszDescription = mir_tstrdup( desc->pszDescription );
+ #endif
+ item->ptszSection_tr = TranslateTS(item->ptszSection);
+ item->ptszDescription_tr = TranslateTS(item->ptszDescription);
+ item->allowSubHotkeys = TRUE;
+ item->rootHotkey = NULL;
+ item->nSubHotkeys = 0;
+
+ if ( item->rootHotkey = hotkeys.find( item )) {
+ if (item->rootHotkey->allowSubHotkeys) {
+ char nameBuf[MAXMODULELABELLENGTH];
+ mir_snprintf(nameBuf, SIZEOF(nameBuf), "%s$%d", item->rootHotkey->pszName, item->rootHotkey->nSubHotkeys);
+ item->pszName = mir_strdup(nameBuf);
+ item->Enabled = TRUE;
+
+ item->rootHotkey->nSubHotkeys++;
+ }
+ else {
+ mir_free(item->ptszSection);
+ mir_free(item->ptszDescription);
+ mir_free(item);
+ return 0;
+ }
+ }
+ else {
+ item->pszName = mir_strdup(desc->pszName);
+ item->Enabled = !DBGetContactSettingByte(NULL, DBMODULENAME "Off", item->pszName, 0);
+ }
+
+ item->pszService = desc->pszService ? mir_strdup(desc->pszService) : 0;
+ item->DefHotkey = desc->DefHotKey & ~HKF_MIRANDA_LOCAL;
+ item->Hotkey = DBGetContactSettingWord(NULL, DBMODULENAME, item->pszName, item->DefHotkey);
+ item->type = item->pszService ?
+ ( THotkeyType )DBGetContactSettingByte(NULL, DBMODULENAME "Types", item->pszName,
+ (desc->DefHotKey & HKF_MIRANDA_LOCAL) ? HKT_LOCAL : HKT_GLOBAL) : HKT_MANUAL;
+ item->lParam = desc->lParam;
+
+ char buf[256];
+ mir_snprintf(buf, SIZEOF(buf), "mir_hotkey_%d_%d", g_pid, g_hotkeyCount++);
+ item->idHotkey = GlobalAddAtomA(buf);
+ if (item->type == HKT_GLOBAL) {
+ if (item->Enabled) {
+ BYTE mod, vk;
+ sttWordToModAndVk(item->Hotkey, &mod, &vk);
+ if (vk) RegisterHotKey(g_hwndHotkeyHost, item->idHotkey, mod, vk);
+ } }
+
+ hotkeys.insert( item );
+
+ if ( !item->rootHotkey ) {
+ /* try to load alternatives from db */
+ int count, i;
+ mir_snprintf(buf, SIZEOF(buf), "%s$count", item->pszName);
+ count = (int)DBGetContactSettingDword(NULL, DBMODULENAME, buf, -1);
+ for (i = 0; i < count; i++) {
+ mir_snprintf(buf, SIZEOF(buf), "%s$%d", item->pszName, i);
+ if (!DBGetContactSettingWord(NULL, DBMODULENAME, buf, 0))
+ continue;
+
+ svcHotkeyRegister(wParam, lParam);
+ }
+ item->allowSubHotkeys = count < 0;
+ }
+ else {
+ mir_free( item->pszName );
+ item->pszName = NULL;
+ }
+
+ return item->idHotkey;
+}
+
+static INT_PTR svcHotkeyUnregister(WPARAM, LPARAM lParam)
+{
+ int i;
+ char *pszName = (char *)lParam;
+ char pszNamePrefix[MAXMODULELABELLENGTH];
+ size_t cbNamePrefix;
+ mir_snprintf(pszNamePrefix, SIZEOF(pszNamePrefix), "%s$", pszName);
+ cbNamePrefix = strlen(pszNamePrefix);
+
+ for (i = 0; i < hotkeys.getCount(); ++i)
+ {
+ char *pszCurrentName = hotkeys[i]->rootHotkey ?
+ hotkeys[i]->rootHotkey->pszName :
+ hotkeys[i]->pszName;
+ if (!pszCurrentName) continue;
+
+ hotkeys[i]->UnregisterHotkey =
+ !lstrcmpA(pszCurrentName, pszName) ||
+ !strncmp(pszCurrentName, pszNamePrefix, cbNamePrefix);
+ }
+
+ if (g_hwndOptions)
+ SendMessage(g_hwndOptions, WM_HOTKEYUNREGISTERED, 0, 0);
+
+ for (i = 0; i < hotkeys.getCount(); ++i)
+ if (hotkeys[i]->UnregisterHotkey) {
+ sttFreeHotkey(hotkeys[i]);
+ List_Remove((SortedList *)&hotkeys, i);
+ --i;
+ }
+
+ return 0;
+}
+
+static INT_PTR svcHotkeyCheck(WPARAM wParam, LPARAM lParam)
+{
+ MSG *msg = (MSG *)wParam;
+ TCHAR *pszSection = mir_a2t((char *)lParam);
+
+ if ((msg->message == WM_KEYDOWN) || (msg->message == WM_SYSKEYDOWN)) {
+ int i;
+ BYTE mod=0, vk=msg->wParam;
+
+ if (vk) {
+ if (GetAsyncKeyState(VK_CONTROL)) mod |= MOD_CONTROL;
+ if (GetAsyncKeyState(VK_MENU)) mod |= MOD_ALT;
+ if (GetAsyncKeyState(VK_SHIFT)) mod |= MOD_SHIFT;
+ if (GetAsyncKeyState(VK_LWIN) || GetAsyncKeyState(VK_RWIN)) mod |= MOD_WIN;
+
+ for ( i = 0; i < hotkeys.getCount(); i++ ) {
+ THotkeyItem *item = hotkeys[i];
+ BYTE hkMod, hkVk;
+ if ((item->type != HKT_MANUAL) || lstrcmp(pszSection, item->ptszSection)) continue;
+ sttWordToModAndVk(item->Hotkey, &hkMod, &hkVk);
+ if (!hkVk) continue;
+ if (!item->Enabled) continue;
+ if ((vk == hkVk) && (mod == hkMod)) {
+ mir_free(pszSection);
+ return item->lParam;
+ } } } }
+
+ mir_free(pszSection);
+ return 0;
+}
+
+static void sttFreeHotkey(THotkeyItem *item)
+{
+ if ( item->type == HKT_GLOBAL && item->Enabled )
+ UnregisterHotKey(g_hwndHotkeyHost, item->idHotkey);
+ GlobalDeleteAtom(item->idHotkey);
+ mir_free(item->pszName);
+ mir_free(item->pszService);
+ mir_free(item->ptszDescription);
+ mir_free(item->ptszSection);
+ mir_free(item);
+}
+
+static void sttRegisterHotkeys()
+{
+ int i;
+ for ( i = 0; i < hotkeys.getCount(); i++ ) {
+ THotkeyItem *item = hotkeys[i];
+ UnregisterHotKey(g_hwndHotkeyHost, item->idHotkey);
+ if (item->type != HKT_GLOBAL) continue;
+ if (item->Enabled) {
+ BYTE mod, vk;
+ sttWordToModAndVk(item->Hotkey, &mod, &vk);
+ if (vk) RegisterHotKey(g_hwndHotkeyHost, item->idHotkey, mod, vk);
+} } }
+
+static void sttUnregisterHotkeys()
+{
+ int i;
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+ if ( item->type == HKT_GLOBAL && item->Enabled )
+ UnregisterHotKey(g_hwndHotkeyHost, item->idHotkey);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Hotkey control
+typedef struct
+{
+ WNDPROC oldWndProc;
+ BYTE shift;
+ BYTE key;
+}
+ THotkeyBoxData;
+
+static TCHAR *sttHokeyVkToName(WORD vkKey)
+{
+ static TCHAR buf[256] = {0};
+ DWORD code = MapVirtualKey(vkKey, 0) << 16;
+
+ switch (vkKey)
+ {
+ case 0:
+ case VK_CONTROL:
+ case VK_SHIFT:
+ case VK_MENU:
+ case VK_LWIN:
+ case VK_RWIN:
+ case VK_PAUSE:
+ case VK_CANCEL:
+ case VK_NUMLOCK:
+ case VK_CAPITAL:
+ case VK_SCROLL:
+ return _T("");
+
+ case VK_DIVIDE:
+ case VK_INSERT:
+ case VK_HOME:
+ case VK_PRIOR:
+ case VK_DELETE:
+ case VK_END:
+ case VK_NEXT:
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_UP:
+ case VK_DOWN:
+ code |= (1UL << 24);
+ }
+
+ GetKeyNameText(code, buf, 256);
+ return buf;
+}
+
+void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key)
+{
+ mir_sntprintf(buf, size, _T("%s%s%s%s%s"),
+ (shift & HOTKEYF_CONTROL) ? _T("Ctrl + ") : _T(""),
+ (shift & HOTKEYF_ALT) ? _T("Alt + ") : _T(""),
+ (shift & HOTKEYF_SHIFT) ? _T("Shift + ") : _T(""),
+ (shift & HOTKEYF_EXT) ? _T("Win + ") : _T(""),
+ sttHokeyVkToName(key));
+}
+
+WORD GetHotkeyValue(INT_PTR idHotkey)
+{
+ for (int i = 0; i < hotkeys.getCount(); i++)
+ if (hotkeys[i]->idHotkey == idHotkey)
+ return hotkeys[i]->Enabled ? hotkeys[i]->Hotkey : 0;
+
+ return 0;
+}
+
+static LRESULT CALLBACK sttHotkeyEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ THotkeyBoxData *data = (THotkeyBoxData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ BOOL bKeyDown = FALSE;
+ if (!data) return 0;
+
+ switch (msg) {
+ case HKM_GETHOTKEY:
+ return data->key ? MAKEWORD(data->key, data->shift) : 0;
+
+ case HKM_SETHOTKEY:
+ {
+ TCHAR buf[256] = {0};
+ data->key = (BYTE)LOWORD(wParam);
+ data->shift = (BYTE)HIWORD(wParam);
+ HotkeyToName(buf, SIZEOF(buf), data->shift, data->key);
+ SetWindowText(hwnd, buf);
+ return 0;
+ }
+
+ case WM_GETDLGCODE:
+ return DLGC_WANTALLKEYS;
+
+ case WM_KILLFOCUS:
+ break;
+
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ case WM_PASTE:
+ case WM_CONTEXTMENU:
+ return TRUE;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ bKeyDown = TRUE;
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ {
+ TCHAR buf[256] = {0};
+
+ BYTE shift = 0;
+ BYTE key = wParam;
+ TCHAR *name = sttHokeyVkToName(key);
+ if (!*name || !bKeyDown) key = 0;
+
+ if (GetAsyncKeyState(VK_CONTROL)) shift |= HOTKEYF_CONTROL;
+ if (GetAsyncKeyState(VK_MENU)) shift |= HOTKEYF_ALT;
+ if (GetAsyncKeyState(VK_SHIFT)) shift |= HOTKEYF_SHIFT;
+ if (GetAsyncKeyState(VK_LWIN) || GetAsyncKeyState(VK_RWIN)) shift |= HOTKEYF_EXT;
+
+ if (bKeyDown || !data->key) {
+ data->shift = shift;
+ data->key = key;
+ }
+
+ HotkeyToName(buf, SIZEOF(buf), data->shift, data->key);
+ SetWindowText(hwnd, buf);
+
+ if (bKeyDown && data->key)
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(GetWindowLongPtr(hwnd, GWL_ID), 0), (LPARAM)hwnd);
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ {
+ WNDPROC saveOldWndProc = data->oldWndProc;
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)data->oldWndProc);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ mir_free(data);
+ return CallWindowProc(saveOldWndProc, hwnd, msg, wParam, lParam);
+ } }
+
+ return CallWindowProc(data->oldWndProc, hwnd, msg, wParam, lParam);
+}
+
+static void sttHotkeyEditCreate(HWND hwnd)
+{
+ THotkeyBoxData *data = (THotkeyBoxData *)mir_alloc(sizeof(THotkeyBoxData));
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (ULONG_PTR)data);
+ data->oldWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (ULONG_PTR)sttHotkeyEditProc);
+}
+
+static void sttHotkeyEditDestroy(HWND hwnd)
+{
+ THotkeyBoxData *data = (THotkeyBoxData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (ULONG_PTR)data->oldWndProc);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ mir_free(data);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Options
+
+enum { COL_NAME, COL_TYPE, COL_KEY, COL_RESET, COL_ADDREMOVE };
+
+static void sttOptionsSetupItem(HWND hwndList, int idx, THotkeyItem *item)
+{
+ TCHAR buf[256];
+ LVITEM lvi = {0};
+ lvi.iItem = idx;
+
+ if ( !item->rootHotkey ) {
+ lvi.mask = LVIF_TEXT|LVIF_IMAGE;
+ lvi.iSubItem = COL_NAME;
+ lvi.pszText = item->ptszDescription_tr;
+ lvi.iImage = item->OptType;
+ ListView_SetItem(hwndList, &lvi);
+
+ ListView_SetCheckState(hwndList, lvi.iItem, item->Enabled);
+ }
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = COL_KEY;
+ HotkeyToName(buf, SIZEOF(buf), HIBYTE(item->OptHotkey), LOBYTE(item->OptHotkey));
+ lvi.pszText = buf;
+ ListView_SetItem(hwndList, &lvi);
+
+ if ( item->rootHotkey ) {
+ lvi.mask = LVIF_IMAGE;
+ lvi.iSubItem = COL_TYPE;
+ lvi.iImage = item->OptType;
+ ListView_SetItem(hwndList, &lvi);
+ }
+
+ lvi.mask = LVIF_IMAGE;
+ lvi.iSubItem = COL_RESET;
+ lvi.iImage = (item->Hotkey != item->OptHotkey) ? 5 : -1;
+ ListView_SetItem(hwndList, &lvi);
+
+ lvi.mask = LVIF_IMAGE|LVIF_TEXT;
+ lvi.iSubItem = COL_ADDREMOVE;
+ if (item->rootHotkey) {
+ lvi.iImage = 4;
+ lvi.pszText = TranslateT("Remove shortcut");
+ }
+ else {
+ lvi.iImage = 3;
+ lvi.pszText = TranslateT("Add another shortcut");
+ }
+ ListView_SetItem(hwndList, &lvi);
+}
+
+static void sttOptionsDeleteHotkey(HWND hwndList, int idx, THotkeyItem *item)
+{
+ item->OptDeleted = TRUE;
+ ListView_DeleteItem(hwndList, idx);
+ if (item->rootHotkey)
+ item->rootHotkey->OptChanged = TRUE;
+}
+
+static int CALLBACK sttOptionsSortList(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ TCHAR title1[256] = {0}, title2[256] = {0};
+ THotkeyItem *item1 = NULL, *item2 = NULL;
+ LVITEM lvi = {0};
+ int res;
+
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = lParam1;
+ lvi.pszText = title1;
+ lvi.cchTextMax = SIZEOF(title1);
+ if (ListView_GetItem((HWND)lParamSort, &lvi))
+ item1 = (THotkeyItem *)lvi.lParam;
+
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = lParam2;
+ lvi.pszText = title2;
+ lvi.cchTextMax = SIZEOF(title2);
+ if (ListView_GetItem((HWND)lParamSort, &lvi))
+ item2 = (THotkeyItem *)lvi.lParam;
+
+ if (!item1 && !item2)
+ return lstrcmp(title1, title2);
+
+ if (!item1) {
+ if (res = lstrcmp(title1, item2->ptszSection_tr))
+ return res;
+ return -1;
+ }
+
+ if (!item2) {
+ if (res = lstrcmp(item1->ptszSection_tr, title2))
+ return res;
+ return 1;
+ }
+ return sttCompareHotkeys(item1, item2);
+}
+
+static void sttOptionsAddHotkey(HWND hwndList, THotkeyItem *item)
+{
+ char buf[256];
+ LVITEM lvi = {0};
+
+ THotkeyItem *newItem = (THotkeyItem *)mir_alloc(sizeof(THotkeyItem));
+ newItem->pszName = NULL;
+ newItem->pszService = item->pszService ? mir_strdup(item->pszService) : NULL;
+ newItem->ptszSection = mir_tstrdup(item->ptszSection);
+ newItem->ptszDescription = mir_tstrdup(item->ptszDescription);
+ newItem->ptszSection_tr = item->ptszSection_tr;
+ newItem->ptszDescription_tr = item->ptszDescription_tr;
+ newItem->lParam = item->lParam;
+ mir_snprintf(buf, SIZEOF(buf), "mir_hotkey_%d_%d", g_pid, g_hotkeyCount++);
+ newItem->idHotkey = GlobalAddAtomA(buf);
+ newItem->rootHotkey = item;
+ newItem->Hotkey = newItem->DefHotkey = newItem->OptHotkey = 0;
+ newItem->type = newItem->OptType = item->OptType;
+ newItem->Enabled = newItem->OptEnabled = TRUE;
+ newItem->OptChanged = newItem->OptDeleted = FALSE;
+ newItem->OptNew = TRUE;
+
+ hotkeys.insert( newItem );
+
+ SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
+
+ lvi.mask |= LVIF_PARAM;
+ lvi.lParam = (LPARAM)newItem;
+ sttOptionsSetupItem(hwndList, ListView_InsertItem(hwndList, &lvi), newItem);
+ ListView_SortItemsEx(hwndList, sttOptionsSortList, (LPARAM)hwndList);
+
+ SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
+
+ item->OptChanged = TRUE;
+}
+
+static void sttOptionsSetChanged(THotkeyItem *item)
+{
+ item->OptChanged = TRUE;
+ if (item->rootHotkey)
+ item->rootHotkey->OptChanged = TRUE;
+}
+
+static void sttOptionsSaveItem(THotkeyItem *item)
+{
+ int i;
+ char buf[MAXMODULELABELLENGTH];
+
+ if (item->rootHotkey) return;
+ if (!item->OptChanged) return;
+
+ item->Hotkey = item->OptHotkey;
+ item->type = item->OptType;
+ item->Enabled = item->OptEnabled;
+
+ DBWriteContactSettingWord(NULL, DBMODULENAME, item->pszName, item->Hotkey);
+ DBWriteContactSettingByte(NULL, DBMODULENAME "Off", item->pszName, (BYTE)!item->Enabled);
+ if (item->type != HKT_MANUAL)
+ DBWriteContactSettingByte(NULL, DBMODULENAME "Types", item->pszName, (BYTE)item->type);
+
+ item->nSubHotkeys = 0;
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *subItem = hotkeys[i];
+ if (subItem->rootHotkey == item) {
+ subItem->Hotkey = subItem->OptHotkey;
+ subItem->type = subItem->OptType;
+
+ mir_snprintf(buf, SIZEOF(buf), "%s$%d", item->pszName, item->nSubHotkeys);
+ DBWriteContactSettingWord(NULL, DBMODULENAME, buf, subItem->Hotkey);
+ if (subItem->type != HKT_MANUAL)
+ DBWriteContactSettingByte(NULL, DBMODULENAME "Types", buf, (BYTE)subItem->type);
+
+ ++item->nSubHotkeys;
+ } }
+
+ mir_snprintf(buf, SIZEOF(buf), "%s$count", item->pszName);
+ DBWriteContactSettingDword(NULL, DBMODULENAME, buf, item->nSubHotkeys);
+}
+
+static void sttBuildHotkeyList(HWND hwndList, TCHAR *section)
+{
+ int i, nItems=0;
+ ListView_DeleteAllItems(hwndList);
+
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ LVITEM lvi = {0};
+ THotkeyItem *item = hotkeys[i];
+
+ if (item->OptDeleted) continue;
+ if (section && lstrcmp(section, item->ptszSection)) continue;
+
+ if ( !section && (!i || lstrcmp(item->ptszSection, ((THotkeyItem *)hotkeys[i-1])->ptszSection ))) {
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = nItems++;
+ lvi.iSubItem = 0;
+ lvi.lParam = 0;
+ lvi.pszText = item->ptszSection_tr;
+ ListView_InsertItem(hwndList, &lvi);
+ ListView_SetCheckState(hwndList, lvi.iItem, TRUE);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = item->ptszSection;
+ ListView_SetItem(hwndList, &lvi);
+
+ lvi.iSubItem = 0;
+ }
+
+ lvi.mask = LVIF_PARAM;
+ if (!section) {
+ lvi.mask |= LVIF_INDENT;
+ lvi.iIndent = 1;
+ }
+ lvi.iItem = nItems++;
+ lvi.lParam = (LPARAM)item;
+ ListView_InsertItem(hwndList, &lvi);
+ sttOptionsSetupItem(hwndList, nItems-1, item);
+ }
+}
+
+static void sttOptionsStartEdit(HWND hwndDlg, HWND hwndHotkey)
+{
+ LVITEM lvi;
+ THotkeyItem *item;
+ int iItem = ListView_GetNextItem(hwndHotkey, -1, LVNI_SELECTED);
+ if (iItem < 0) return;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = iItem;
+ ListView_GetItem(hwndHotkey, &lvi);
+
+ if (item = (THotkeyItem *)lvi.lParam) {
+ RECT rc;
+ ListView_GetSubItemRect(hwndHotkey, iItem, COL_KEY, LVIR_BOUNDS, &rc);
+ MapWindowPoints(hwndHotkey, hwndDlg, (LPPOINT)&rc, 2);
+ SendDlgItemMessage(hwndDlg, IDC_HOTKEY, HKM_SETHOTKEY, MAKELONG(LOBYTE(item->OptHotkey), HIBYTE(item->OptHotkey)), 0);
+
+ SetWindowPos(hwndHotkey, HWND_BOTTOM, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_HOTKEY), HWND_TOP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_HOTKEY), NULL, NULL, RDW_INVALIDATE);
+
+ SetFocus(GetDlgItem(hwndDlg, IDC_HOTKEY));
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_HOTKEY), NULL, NULL, RDW_INVALIDATE);
+ }
+}
+
+static void sttOptionsDrawTextChunk(HDC hdc, TCHAR *text, RECT *rc)
+{
+ SIZE sz;
+ DrawText(hdc, text, lstrlen(text), rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS);
+ GetTextExtentPoint32(hdc, text, lstrlen(text), &sz);
+ rc->left += sz.cx;
+}
+
+static INT_PTR CALLBACK sttOptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static BOOL initialized = FALSE;
+ static int colWidth = 0;
+ static WORD currentLanguage = 0;
+
+ HWND hwndHotkey = GetDlgItem(hwndDlg, IDC_LV_HOTKEYS);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ int i;
+ LVCOLUMN lvc;
+ RECT rc;
+ HIMAGELIST hIml;
+
+ initialized = FALSE;
+
+ TranslateDialogDefault(hwndDlg);
+
+ sttHotkeyEditCreate(GetDlgItem(hwndDlg, IDC_HOTKEY));
+
+ hIml = ImageList_Create(16, 16, ILC_MASK + (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16), 3, 1);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_WINDOWS);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_MIRANDA);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_WINDOW);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_ADDCONTACT);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_DELETE);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_UNDO);
+
+ // This is added to use for drawing operation only
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_GROUPOPEN);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_GROUPSHUT);
+
+ ListView_SetImageList(hwndHotkey, hIml, LVSIL_SMALL);
+
+ ListView_SetExtendedListViewStyle(hwndHotkey, LVS_EX_CHECKBOXES|LVS_EX_SUBITEMIMAGES|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER|LVS_EX_INFOTIP);
+
+ GetClientRect(hwndHotkey, &rc);
+ colWidth = rc.right - GetSystemMetrics(SM_CXHTHUMB) - 3*GetSystemMetrics(SM_CXSMICON) - 5;
+
+ lvc.mask = LVCF_WIDTH;
+ lvc.cx = colWidth * 2 / 3;
+ ListView_InsertColumn(hwndHotkey, COL_NAME, &lvc);
+ lvc.cx = GetSystemMetrics(SM_CXSMICON);
+ ListView_InsertColumn(hwndHotkey, COL_TYPE, &lvc);
+ lvc.cx = colWidth / 3;
+ ListView_InsertColumn(hwndHotkey, COL_KEY, &lvc);
+ lvc.cx = GetSystemMetrics(SM_CXSMICON);
+ ListView_InsertColumn(hwndHotkey, COL_RESET, &lvc);
+ lvc.cx = GetSystemMetrics(SM_CXSMICON);
+ ListView_InsertColumn(hwndHotkey, COL_ADDREMOVE, &lvc);
+
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+
+ item->OptChanged = FALSE;
+ item->OptDeleted = item->OptNew = FALSE;
+ item->OptEnabled = item->Enabled;
+ item->OptHotkey = item->Hotkey;
+ item->OptType = item->type;
+ }
+
+ currentLanguage = LOWORD(GetKeyboardLayout(0));
+ sttBuildHotkeyList(hwndHotkey, NULL);
+ SetTimer(hwndDlg, 1024, 1000, NULL);
+
+ initialized = TRUE;
+
+ { /* load group states */
+ int count = ListView_GetItemCount(hwndHotkey);
+ TCHAR buf[128];
+ LVITEM lvi = {0};
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ char *szSetting;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iSubItem = 0;
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (lvi.lParam) continue;
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ ListView_GetItem(hwndHotkey, &lvi);
+
+ szSetting = mir_t2a(lvi.pszText);
+
+ ListView_SetCheckState(hwndHotkey, lvi.iItem,
+ DBGetContactSettingByte(NULL, DBMODULENAME "UI", szSetting, TRUE));
+
+ mir_free(szSetting);
+ }
+ }
+
+ g_hwndOptions = hwndDlg;
+
+ break;
+ }
+
+ case WM_DESTROY:
+ {
+ int count = ListView_GetItemCount(hwndHotkey);
+ TCHAR buf[128];
+ LVITEM lvi = {0};
+
+ g_hwndOptions = NULL;
+
+ KillTimer(hwndDlg, 1024);
+
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ char *szSetting;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iSubItem = 0;
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (lvi.lParam) continue;
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ ListView_GetItem(hwndHotkey, &lvi);
+
+ szSetting = mir_t2a(lvi.pszText);
+
+ DBWriteContactSettingByte(NULL, DBMODULENAME "UI", szSetting,
+ (BYTE) ListView_GetCheckState(hwndHotkey, lvi.iItem));
+
+ mir_free(szSetting);
+ }
+ break;
+ }
+
+ case WM_TIMER:
+ {
+ WORD newLanguage;
+ int count;
+ LVITEM lvi = {0};
+
+ if (!initialized) break;
+
+ newLanguage = LOWORD(GetKeyboardLayout(0));
+ if (newLanguage == currentLanguage) break;
+
+ count = ListView_GetItemCount(hwndHotkey);
+ lvi.mask = LVIF_PARAM;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (!lvi.lParam) continue;
+
+ sttOptionsSetupItem(hwndHotkey, lvi.iItem, (THotkeyItem *)lvi.lParam);
+ }
+
+ currentLanguage = newLanguage;
+ break;
+ }
+
+ case WM_HOTKEYUNREGISTERED:
+ {
+ int count;
+ LVITEM lvi = {0};
+
+ count = ListView_GetItemCount(hwndHotkey);
+ lvi.mask = LVIF_PARAM;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (!lvi.lParam) continue;
+
+ if (((THotkeyItem *)lvi.lParam)->UnregisterHotkey) {
+ ListView_DeleteItem(hwndHotkey, lvi.iItem);
+ --lvi.iItem;
+ --count;
+ }
+ }
+ break;
+ }
+
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
+ RECT rc = lpdis->rcItem;
+ int prefix = 65;
+ int width = (lpdis->rcItem.right - lpdis->rcItem.left - prefix) / 3;
+ rc.left += 5;
+
+ HIMAGELIST hIml = ListView_GetImageList(hwndHotkey, LVSIL_SMALL);
+
+ if (lpdis->CtlID == IDC_CANVAS2) {
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Scope:"), &rc);
+
+ rc.left = prefix + width * 0;
+ ImageList_Draw(hIml, 0, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("System"), &rc);
+
+ rc.left = prefix + width * 1;
+ ImageList_Draw(hIml, 1, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Miranda"), &rc);
+
+ rc.left = prefix + width * 2;
+ ImageList_Draw(hIml, 2, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Window"), &rc);
+
+ return TRUE;
+ }
+
+ if (lpdis->CtlID == IDC_CANVAS) {
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Actions:"), &rc);
+ rc.left += 10;
+
+ rc.left = prefix + width * 0;
+ ImageList_Draw(hIml, 5, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Undo"), &rc);
+
+ rc.left = prefix + width * 1;
+ ImageList_Draw(hIml, 3, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Add binding"), &rc);
+
+ rc.left = prefix + width * 2;
+ ImageList_Draw(hIml, 4, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Remove"), &rc);
+
+ return TRUE;
+ }
+
+ break;
+ }
+
+ case WM_COMMAND:
+ if (( LOWORD( wParam ) == IDC_HOTKEY) && (( HIWORD( wParam ) == EN_KILLFOCUS) || (HIWORD(wParam) == 0 ))) {
+ LVITEM lvi;
+ THotkeyItem *item;
+ WORD wHotkey = (WORD)SendDlgItemMessage(hwndDlg, IDC_HOTKEY, HKM_GETHOTKEY, 0, 0);
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_HOTKEY), SW_HIDE);
+ SetFocus(hwndHotkey);
+ if ( !wHotkey || (wHotkey == VK_ESCAPE) || (HIWORD(wParam) != 0 ))
+ break;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ListView_GetNextItem(hwndHotkey, -1, LVNI_SELECTED);
+ if (lvi.iItem >= 0) {
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (item = (THotkeyItem *)lvi.lParam) {
+ item->OptHotkey = wHotkey;
+
+ sttOptionsSetupItem(hwndHotkey, lvi.iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } } }
+ break;
+
+ case WM_CONTEXTMENU:
+ if (GetWindowLongPtr((HWND)wParam, GWL_ID) == IDC_LV_HOTKEYS)
+ {
+ HWND hwndList = (HWND)wParam;
+ POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) };
+ LVITEM lvi = {0};
+ THotkeyItem *item = NULL;
+
+ lvi.iItem = ListView_GetNextItem(hwndHotkey, -1, LVNI_SELECTED);
+ if (lvi.iItem < 0) return FALSE;
+
+ lvi.mask = LVIF_PARAM;
+ ListView_GetItem(hwndList, &lvi);
+ if (!(item = (THotkeyItem *)lvi.lParam)) return FALSE;
+
+ if (( pt.x == -1 ) && ( pt.y == -1 )) {
+ RECT rc;
+ ListView_GetItemRect(hwndList, lvi.iItem, &rc, LVIR_LABEL);
+ pt.x = rc.left;
+ pt.y = rc.bottom;
+ ClientToScreen(hwndList, &pt);
+ }
+
+ {
+ enum { MI_CANCEL, MI_CHANGE, MI_SYSTEM, MI_LOCAL, MI_ADD, MI_REMOVE, MI_REVERT };
+
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE;
+ mii.fState = MFS_DEFAULT;
+
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_CHANGE, TranslateT("Modify"));
+ SetMenuItemInfo(hMenu, (UINT_PTR)MI_CHANGE, FALSE, &mii);
+ if (item->type != HKT_MANUAL) {
+ AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hMenu, MF_STRING|
+ ((item->OptType == HKT_GLOBAL) ? MF_CHECKED : 0),
+ (UINT_PTR)MI_SYSTEM, TranslateT("System scope"));
+ AppendMenu(hMenu, MF_STRING|
+ ((item->OptType == HKT_LOCAL) ? MF_CHECKED : 0),
+ (UINT_PTR)MI_LOCAL, TranslateT("Miranda scope"));
+ }
+ AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
+ if (!item->rootHotkey)
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_ADD, TranslateT("Add binding"));
+ else
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_REMOVE, TranslateT("Remove"));
+ if (item->Hotkey != item->OptHotkey) {
+ AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_REVERT, TranslateT("Undo"));
+ }
+
+ switch (TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) {
+ case MI_CHANGE:
+ sttOptionsStartEdit(hwndDlg, hwndHotkey);
+ break;
+ case MI_SYSTEM:
+ item->OptType = HKT_GLOBAL;
+ sttOptionsSetupItem(hwndList, lvi.iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case MI_LOCAL:
+ item->OptType = HKT_LOCAL;
+ sttOptionsSetupItem(hwndList, lvi.iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case MI_ADD:
+ initialized = FALSE;
+ sttOptionsAddHotkey(hwndList, item);
+ initialized = FALSE;
+ break;
+ case MI_REMOVE:
+ sttOptionsDeleteHotkey(hwndList, lvi.iItem, item);
+ break;
+ case MI_REVERT:
+ item->OptHotkey = item->Hotkey;
+ sttOptionsSetupItem(hwndList, lvi.iItem, item);
+ break;
+ }
+ DestroyMenu( hMenu );
+ }
+
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpnmhdr = (LPNMHDR)lParam;
+ switch (lpnmhdr->idFrom) {
+ case 0:
+ {
+ int i;
+
+ if (( lpnmhdr->code != PSN_APPLY) && (lpnmhdr->code != PSN_RESET ))
+ break;
+
+ sttUnregisterHotkeys();
+
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+ if (item->OptNew && item->OptDeleted ||
+ item->rootHotkey && !item->OptHotkey ||
+ (lpnmhdr->code == PSN_APPLY) && item->OptDeleted ||
+ (lpnmhdr->code == PSN_RESET) && item->OptNew)
+ {
+ sttFreeHotkey(item);
+ hotkeys.remove( i-- );
+ }
+ }
+
+ if (lpnmhdr->code == PSN_APPLY) {
+ LVITEM lvi = {0};
+ int count = ListView_GetItemCount(hwndHotkey);
+
+ for (i = 0; i < hotkeys.getCount(); i++)
+ sttOptionsSaveItem(hotkeys[i]);
+
+ lvi.mask = LVIF_IMAGE;
+ lvi.iSubItem = COL_RESET;
+ lvi.iImage = -1;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem)
+ ListView_SetItem(hwndHotkey, &lvi);
+ }
+
+ sttRegisterHotkeys();
+
+ NotifyEventHooks( hEvChanged, 0, 0 );
+ break;
+ }
+ case IDC_LV_HOTKEYS:
+ switch (lpnmhdr->code) {
+ case NM_CLICK:
+ {
+ THotkeyItem *item = NULL;
+ LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lParam;
+ LVHITTESTINFO lvhti = {0};
+ LVITEM lvi = {0};
+
+ lvi.mask = LVIF_PARAM|LVIF_IMAGE;
+ lvi.iItem = lpnmia->iItem;
+ ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi);
+ item = (THotkeyItem *)lvi.lParam;
+
+ lvhti.pt = lpnmia->ptAction;
+ lvhti.iItem = lpnmia->iItem;
+ lvhti.iSubItem = lpnmia->iSubItem;
+ ListView_HitTest(lpnmia->hdr.hwndFrom, &lvhti);
+
+ if (item &&
+ (!item->rootHotkey && (lpnmia->iSubItem == COL_NAME) && ((lvhti.flags & LVHT_ONITEM) == LVHT_ONITEMICON) ||
+ item->rootHotkey && (lpnmia->iSubItem == COL_TYPE)) &&
+ ((item->OptType == HKT_GLOBAL) || (item->OptType == HKT_LOCAL)))
+ {
+ item->OptType = (item->OptType == HKT_GLOBAL) ? HKT_LOCAL : HKT_GLOBAL;
+ sttOptionsSetupItem(lpnmia->hdr.hwndFrom, lpnmia->iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ else if (item && (lpnmia->iSubItem == COL_RESET)) {
+ item->OptHotkey = item->Hotkey;
+ sttOptionsSetupItem(lpnmia->hdr.hwndFrom, lpnmia->iItem, item);
+ }
+ else if (item && (lpnmia->iSubItem == COL_ADDREMOVE)) {
+ if (item->rootHotkey)
+ sttOptionsDeleteHotkey(lpnmia->hdr.hwndFrom, lpnmia->iItem, item);
+ else {
+ initialized = FALSE;
+ sttOptionsAddHotkey(lpnmia->hdr.hwndFrom, item);
+ initialized = TRUE;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ }
+ case LVN_KEYDOWN:
+ {
+ LPNMLVKEYDOWN param = (LPNMLVKEYDOWN)lParam;
+ if ((param->wVKey == VK_SUBTRACT) || (param->wVKey == VK_LEFT) ||
+ (param->wVKey == VK_ADD) || (param->wVKey == VK_RIGHT))
+ {
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ListView_GetNextItem(lpnmhdr->hwndFrom, -1, LVNI_SELECTED);
+ if (lvi.iItem < 0) break;
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+ if (lvi.lParam) break;
+
+ if ((param->wVKey == VK_ADD) || (param->wVKey == VK_RIGHT))
+ {
+ ListView_SetCheckState(lpnmhdr->hwndFrom, lvi.iItem, TRUE);
+ } else
+ // if ((param->wVKey == VK_SUBTRACT) || (param->wVKey == VK_LEFT))
+ {
+ ListView_SetCheckState(lpnmhdr->hwndFrom, lvi.iItem, FALSE);
+ }
+ }
+ else if (param->wVKey == VK_F2)
+ sttOptionsStartEdit(hwndDlg, hwndHotkey);
+
+ break;
+ }
+ case LVN_ITEMACTIVATE:
+ {
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ListView_GetNextItem(lpnmhdr->hwndFrom, -1, LVNI_SELECTED);
+ if (lvi.iItem < 0) break;
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+
+ if (lvi.lParam)
+ sttOptionsStartEdit(hwndDlg, hwndHotkey);
+ else
+ ListView_SetCheckState(lpnmhdr->hwndFrom, lvi.iItem, !ListView_GetCheckState(lpnmhdr->hwndFrom, lvi.iItem));
+ break;
+ }
+ case LVN_ITEMCHANGED:
+ {
+ LPNMLISTVIEW param = (LPNMLISTVIEW)lParam;
+ THotkeyItem *item = (THotkeyItem *)param->lParam;
+ if (!initialized || (param->uNewState>>12 == param->uOldState>>12))
+ break;
+
+ if (item && !item->rootHotkey) {
+ item->OptEnabled = ListView_GetCheckState(lpnmhdr->hwndFrom, param->iItem) ? 1 : 0;
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ else if (!item) {
+ TCHAR buf[256];
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_TEXT;
+ lvi.iItem = param->iItem;
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+
+ if (param->uNewState>>12 == 1) {
+ int count = ListView_GetItemCount(lpnmhdr->hwndFrom);
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_PARAM;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ THotkeyItem *item;
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+ item = (THotkeyItem *)lvi.lParam;
+ if (!item) continue;
+ if (!lstrcmp(item->ptszSection_tr, buf)) {
+ ListView_DeleteItem(lpnmhdr->hwndFrom, lvi.iItem);
+ --lvi.iItem;
+ --count;
+ } }
+ }
+ else if (param->uNewState>>12 == 2) {
+ int i, nItems = ListView_GetItemCount(lpnmhdr->hwndFrom);
+ initialized = FALSE;
+ for (i = 0; i < hotkeys.getCount(); ++i) {
+ LVITEM lvi = {0};
+ THotkeyItem *item = hotkeys[i];
+
+ if (item->OptDeleted) continue;
+ if (lstrcmp(buf, item->ptszSection_tr)) continue;
+
+ lvi.mask = LVIF_PARAM|LVIF_INDENT;
+ lvi.iIndent = 1;
+ lvi.iItem = nItems++;
+ lvi.lParam = (LPARAM)item;
+ ListView_InsertItem(lpnmhdr->hwndFrom, &lvi);
+ sttOptionsSetupItem(lpnmhdr->hwndFrom, nItems-1, item);
+ }
+ ListView_SortItemsEx(lpnmhdr->hwndFrom, sttOptionsSortList, (LPARAM)lpnmhdr->hwndFrom);
+ initialized = TRUE;
+ }
+ }
+ break;
+ }
+ case NM_CUSTOMDRAW:
+ {
+ NMLVCUSTOMDRAW *param = (NMLVCUSTOMDRAW *) lParam;
+ switch (param->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ case CDDS_ITEMPREPAINT:
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW );
+ return TRUE;
+
+ case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
+ {
+ THotkeyItem *item;
+ TCHAR buf[256];
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = param->nmcd.dwItemSpec;
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+ item = (THotkeyItem *)lvi.lParam;
+
+ if (!item) {
+ RECT rc;
+ HFONT hfnt;
+
+ ListView_GetSubItemRect(lpnmhdr->hwndFrom, param->nmcd.dwItemSpec, param->iSubItem, LVIR_BOUNDS, &rc);
+ FillRect(param->nmcd.hdc, &rc, GetSysColorBrush(param->nmcd.uItemState&CDIS_SELECTED ? COLOR_HIGHLIGHT : COLOR_WINDOW));
+ SetTextColor(param->nmcd.hdc, GetSysColor(param->nmcd.uItemState&CDIS_SELECTED ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
+
+ if (param->iSubItem == 0) {
+ rc.left += 3;
+ HIMAGELIST hIml = ListView_GetImageList(hwndHotkey, LVSIL_SMALL);
+ ImageList_Draw(hIml,
+ ListView_GetCheckState(hwndHotkey, lvi.iItem) ? 6 : 7,
+ param->nmcd.hdc, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 18;
+ hfnt = ( HFONT )SelectObject(param->nmcd.hdc, (HFONT)SendMessage(GetParent(hwndDlg), PSM_GETBOLDFONT, 0, 0));
+ DrawText(param->nmcd.hdc, buf, -1, &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER);
+ SelectObject(param->nmcd.hdc, hfnt);
+ }
+
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT );
+ return TRUE;
+ }
+
+ if (item->rootHotkey && (param->iSubItem == 0)) {
+ RECT rc;
+ ListView_GetSubItemRect(lpnmhdr->hwndFrom, param->nmcd.dwItemSpec, param->iSubItem, LVIR_BOUNDS, &rc);
+ FillRect(param->nmcd.hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT );
+ return TRUE;
+ }
+ break;
+ } }
+ break;
+ }
+ break;
+ } }
+ break;
+ } /* case WM_NOTIFY */
+ } /* switch */
+
+ return FALSE;
+}
+
+static int sttOptionsInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hMirandaInst;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+ odp.position = -180000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_HOTKEYS);
+ odp.ptszTitle = TranslateT("Hotkeys");
+ odp.ptszGroup = TranslateT("Customize");
+ odp.pfnDlgProc = sttOptionsDlgProc;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+ return 0;
+}
+
+static int sttModulesLoaded(WPARAM, LPARAM)
+{
+ HookEvent(ME_OPT_INITIALISE, sttOptionsInit);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Hotkey manager
+
+static const char* oldSettings[] = { "ShowHide", "ReadMsg", "NetSearch", "ShowOptions" };
+static const char* newSettings[] = { "ShowHide", "ReadMessage", "SearchInWeb", "ShowOptions" };
+
+int LoadSkinHotkeys(void)
+{
+ WNDCLASSEX wcl = {0};
+
+ bModuleInitialized = TRUE;
+
+ wcl.cbSize = sizeof(wcl);
+ wcl.lpfnWndProc = sttHotkeyHostWndProc;
+ wcl.style = 0;
+ wcl.cbClsExtra = 0;
+ wcl.cbWndExtra = 0;
+ wcl.hInstance = hMirandaInst;
+ wcl.hIcon = NULL;
+ wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
+ wcl.lpszMenuName = NULL;
+ wcl.lpszClassName = _T("MirandaHotkeyHostWnd");
+ wcl.hIconSm = NULL;
+ RegisterClassEx(&wcl);
+
+ g_pid = GetCurrentProcessId();
+
+ g_hwndHotkeyHost = CreateWindow(_T("MirandaHotkeyHostWnd"), NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hMirandaInst, NULL);
+ SetWindowPos(g_hwndHotkeyHost, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_HIDEWINDOW);
+
+ hhkKeyboard = SetWindowsHookEx(WH_KEYBOARD, sttKeyboardProc, NULL, GetCurrentThreadId());
+
+ hEvChanged = CreateHookableEvent(ME_HOTKEYS_CHANGED);
+
+ CreateServiceFunction(MS_HOTKEY_SUBCLASS, svcHotkeySubclass);
+ CreateServiceFunction(MS_HOTKEY_UNSUBCLASS, svcHotkeyUnsubclass);
+ CreateServiceFunction(MS_HOTKEY_REGISTER, svcHotkeyRegister);
+ CreateServiceFunction(MS_HOTKEY_UNREGISTER, svcHotkeyUnregister);
+ CreateServiceFunction(MS_HOTKEY_CHECK, svcHotkeyCheck);
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, sttModulesLoaded);
+ {
+ WORD key;
+ int i;
+ for ( i = 0; i < SIZEOF( oldSettings ); i++ ) {
+ char szSetting[ 100 ];
+ mir_snprintf( szSetting, SIZEOF(szSetting), "HK%s", oldSettings[i] );
+ if (( key = DBGetContactSettingWord( NULL, "Clist", szSetting, 0 ))) {
+ DBDeleteContactSetting( NULL, "Clist", szSetting );
+ DBWriteContactSettingWord( NULL, DBMODULENAME, newSettings[i], key );
+ }
+
+ mir_snprintf( szSetting, SIZEOF(szSetting), "HKEn%s", oldSettings[i] );
+ if (( key = DBGetContactSettingByte( NULL, "Clist", szSetting, 0 ))) {
+ DBDeleteContactSetting( NULL, "Clist", szSetting );
+ DBWriteContactSettingByte( NULL, DBMODULENAME "Off", newSettings[i], (BYTE)(key == 0) );
+ } } }
+
+ return 0;
+}
+
+void UnloadSkinHotkeys(void)
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ DestroyHookableEvent(hEvChanged);
+ UnhookWindowsHookEx(hhkKeyboard);
+ sttUnregisterHotkeys();
+ DestroyWindow(g_hwndHotkeyHost);
+ for ( i = 0; i < hotkeys.getCount(); i++ )
+ sttFreeHotkey(hotkeys[i]);
+ hotkeys.destroy();
+}
diff --git a/src/modules/skin/skinicons.cpp b/src/modules/skin/skinicons.cpp new file mode 100644 index 0000000000..9bfb0cf655 --- /dev/null +++ b/src/modules/skin/skinicons.cpp @@ -0,0 +1,489 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 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 "commonheaders.h"
+#include <io.h>
+
+struct StandardIconDescription
+{
+ int id;
+ const char* description;
+ int resource_id;
+ int pf2;
+ const char* section;
+};
+
+static const struct StandardIconDescription mainIcons[] =
+{
+ { SKINICON_OTHER_MIRANDA, LPGEN("Miranda IM"), -IDI_MIRANDA },
+ { SKINICON_EVENT_MESSAGE, LPGEN("Message"), -IDI_RECVMSG },
+ { SKINICON_EVENT_URL, LPGEN("URL"), -IDI_URL },
+ { SKINICON_EVENT_FILE, LPGEN("File"), -IDI_FILE },
+ { SKINICON_OTHER_USERONLINE, LPGEN("User Online"), -IDI_USERONLINE },
+ { SKINICON_OTHER_GROUPOPEN, LPGEN("Group (Open)"), -IDI_GROUPOPEN },
+ { SKINICON_OTHER_GROUPSHUT, LPGEN("Group (Closed)"), -IDI_GROUPSHUT },
+ { SKINICON_OTHER_CONNECTING, LPGEN("Connecting"), -IDI_LOAD },
+ { SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact"), -IDI_ADDCONTACT },
+ { SKINICON_OTHER_USERDETAILS, LPGEN("User Details"), -IDI_USERDETAILS },
+ { SKINICON_OTHER_HISTORY, LPGEN("History"), -IDI_HISTORY },
+ { SKINICON_OTHER_DOWNARROW, LPGEN("Down Arrow"), -IDI_DOWNARROW },
+ { SKINICON_OTHER_FINDUSER, LPGEN("Find User"), -IDI_FINDUSER },
+ { SKINICON_OTHER_OPTIONS, LPGEN("Options"), -IDI_OPTIONS },
+ { SKINICON_OTHER_SENDEMAIL, LPGEN("Send E-mail"), -IDI_SENDEMAIL },
+ { SKINICON_OTHER_DELETE, LPGEN("Delete"), -IDI_DELETE },
+ { SKINICON_OTHER_RENAME, LPGEN("Rename"), -IDI_RENAME },
+ { SKINICON_OTHER_SMS, LPGEN("SMS"), -IDI_SMS },
+ { SKINICON_OTHER_SEARCHALL, LPGEN("Search All"), -IDI_SEARCHALL },
+ { SKINICON_OTHER_TICK, LPGEN("Tick"), -IDI_TICK },
+ { SKINICON_OTHER_NOTICK, LPGEN("No Tick"), -IDI_NOTICK },
+ { SKINICON_OTHER_HELP, LPGEN("Help"), -IDI_HELP },
+ { SKINICON_OTHER_MIRANDAWEB, LPGEN("Miranda Website"), -IDI_MIRANDAWEBSITE },
+ { SKINICON_OTHER_TYPING, LPGEN("Typing"), -IDI_TYPING },
+ { SKINICON_OTHER_SMALLDOT, LPGEN("Small Dot"), -IDI_SMALLDOT },
+ { SKINICON_OTHER_FILLEDBLOB, LPGEN("Filled Blob"), -IDI_FILLEDBLOB },
+ { SKINICON_OTHER_EMPTYBLOB, LPGEN("Empty Blob"), -IDI_EMPTYBLOB },
+ { SKINICON_OTHER_UNICODE, LPGEN("Unicode plugin"), -IDI_UNICODE },
+ { SKINICON_OTHER_ANSI, LPGEN("ANSI plugin"), -IDI_ANSI },
+ { SKINICON_OTHER_LOADED, LPGEN("Running plugin"), -IDI_LOADED },
+ { SKINICON_OTHER_NOTLOADED, LPGEN("Unloaded plugin"), -IDI_NOTLOADED },
+ { SKINICON_OTHER_UNDO, LPGEN("Undo"), -IDI_UNDO },
+ { SKINICON_OTHER_WINDOW, LPGEN("Window"), -IDI_WINDOW },
+ { SKINICON_OTHER_WINDOWS, LPGEN("System"), -IDI_WINDOWS },
+ { SKINICON_OTHER_ACCMGR, LPGEN("Accounts"), -IDI_ACCMGR },
+ { SKINICON_OTHER_SHOWHIDE, LPGEN("ShowHide"), -IDI_SHOWHIDE },
+ { SKINICON_OTHER_EXIT, LPGEN("Exit"), -IDI_EXIT },
+ { SKINICON_OTHER_MAINMENU, LPGEN("Main Menu"), -IDI_MIRANDA },
+ { SKINICON_OTHER_STATUS, LPGEN("Status"), -IDI_ONLINE },
+ { SKINICON_CHAT_JOIN, LPGEN("Join chat"), -IDI_JOINCHAT },
+ { SKINICON_CHAT_LEAVE, LPGEN("Leave chat"), -IDI_LEAVECHAT },
+ { SKINICON_OTHER_GROUP, LPGEN("Move to Group"), -IDI_MOVETOGROUP },
+ { SKINICON_OTHER_ON, LPGEN("On"), -IDI_ON },
+ { SKINICON_OTHER_OFF, LPGEN("Off"), -IDI_OFF },
+ { SKINICON_OTHER_STATUS_LOCKED, LPGEN("Locked status"), -IDI_STATUS_LOCKED, 0, "Status Icons" },
+};
+
+HANDLE hMainIcons[SIZEOF(mainIcons)];
+
+static const struct StandardIconDescription statusIcons[] =
+{
+ { ID_STATUS_OFFLINE, LPGEN("Offline"), -IDI_OFFLINE, 0xFFFFFFFF },
+ { ID_STATUS_ONLINE, LPGEN("Online"), -IDI_ONLINE, PF2_ONLINE },
+ { ID_STATUS_AWAY, LPGEN("Away"), -IDI_AWAY, PF2_SHORTAWAY },
+ { ID_STATUS_NA, LPGEN("NA"), -IDI_NA, PF2_LONGAWAY },
+ { ID_STATUS_OCCUPIED, LPGEN("Occupied"), -IDI_OCCUPIED, PF2_LIGHTDND },
+ { ID_STATUS_DND, LPGEN("DND"), -IDI_DND, PF2_HEAVYDND },
+ { ID_STATUS_FREECHAT, LPGEN("Free for chat"), -IDI_FREE4CHAT, PF2_FREECHAT },
+ { ID_STATUS_INVISIBLE, LPGEN("Invisible"), -IDI_INVISIBLE, PF2_INVISIBLE },
+ { ID_STATUS_ONTHEPHONE, LPGEN("On the phone"), -IDI_ONTHEPHONE, PF2_ONTHEPHONE },
+ { ID_STATUS_OUTTOLUNCH, LPGEN("Out to lunch"), -IDI_OUTTOLUNCH, PF2_OUTTOLUNCH }
+};
+
+HANDLE hStatusIcons[SIZEOF(statusIcons)];
+
+const char* mainIconsFmt = "core_main_";
+const char* statusIconsFmt = "core_status_";
+const char* protoIconsFmt = LPGEN("%s Icons");
+
+#define PROTOCOLS_PREFIX "Status Icons/"
+#define GLOBAL_PROTO_NAME "*"
+
+
+
+
+// load small icon (shared) it's not need to be destroyed
+
+static HICON LoadSmallIconShared(HINSTANCE hInstance, LPCTSTR lpIconName)
+{
+ int cx = GetSystemMetrics(SM_CXSMICON);
+ return ( HICON )LoadImage( hInstance, lpIconName, IMAGE_ICON,cx, cx, LR_DEFAULTCOLOR | LR_SHARED );
+}
+
+// load small icon (not shared) it IS NEED to be destroyed
+static HICON LoadSmallIcon(HINSTANCE hInstance, LPCTSTR lpIconName)
+{
+ HICON hIcon = NULL; // icon handle
+ int index = -( int )lpIconName;
+ TCHAR filename[MAX_PATH] = {0};
+ GetModuleFileName( hInstance, filename, MAX_PATH );
+ ExtractIconEx( filename, index, NULL, &hIcon, 1 );
+ return hIcon;
+}
+
+// load small icon from hInstance
+HICON LoadIconEx(HINSTANCE hInstance, LPCTSTR lpIconName, BOOL bShared)
+{
+ HICON hResIcon = bShared ? LoadSmallIcon(hInstance,lpIconName) : LoadSmallIconShared(hInstance,lpIconName);
+ if ( !hResIcon ) { //Icon not found in hInstance lets try to load it from core
+ HINSTANCE hCoreInstance=hMirandaInst;
+ if ( hCoreInstance != hInstance )
+ hResIcon = bShared ? LoadSmallIcon(hCoreInstance,lpIconName) : LoadSmallIconShared(hCoreInstance,lpIconName);
+ }
+ return hResIcon;
+}
+
+int ImageList_AddIcon_NotShared(HIMAGELIST hIml, LPCTSTR szResource)
+{
+ HICON hTempIcon=LoadIconEx( hMirandaInst, szResource, 0);
+ int res = ImageList_AddIcon(hIml, hTempIcon);
+ Safe_DestroyIcon(hTempIcon);
+ return res;
+}
+
+int ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId)
+{
+ HICON hIcon = LoadSkinIcon( iconId );
+ int res = ImageList_AddIcon(hIml, hIcon);
+ IconLib_ReleaseIcon(hIcon,0);
+ return res;
+}
+
+int ImageList_AddIcon_ProtoIconLibLoaded(HIMAGELIST hIml, const char* szProto, int iconId)
+{
+ HICON hIcon = LoadSkinProtoIcon( szProto, iconId );
+ int res = ImageList_AddIcon(hIml, hIcon);
+ IconLib_ReleaseIcon(hIcon,0);
+ return res;
+}
+
+int ImageList_ReplaceIcon_NotShared(HIMAGELIST hIml, int iIndex, HINSTANCE hInstance, LPCTSTR szResource)
+{
+ HICON hTempIcon = LoadIconEx(hInstance, szResource, 0);
+ int res = ImageList_ReplaceIcon(hIml, iIndex, hTempIcon);
+ Safe_DestroyIcon(hTempIcon);
+ return res;
+}
+
+int ImageList_ReplaceIcon_IconLibLoaded(HIMAGELIST hIml, int nIndex, HICON hIcon)
+{
+ int res = ImageList_ReplaceIcon(hIml,nIndex, hIcon);
+ IconLib_ReleaseIcon(hIcon,0);
+ return res;
+}
+
+void Window_SetIcon_IcoLib(HWND hWnd, int iconId)
+{
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadSkinIcon( iconId, true ));
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadSkinIcon( iconId ));
+}
+
+void Window_SetProtoIcon_IcoLib(HWND hWnd, const char* szProto, int iconId)
+{
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadSkinProtoIcon( szProto, iconId, true ));
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadSkinProtoIcon( szProto, iconId ));
+}
+
+void Window_FreeIcon_IcoLib(HWND hWnd)
+{
+ IconLib_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_BIG, 0), NULL);
+ IconLib_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0), NULL);
+}
+
+void Button_SetIcon_IcoLib(HWND hwndDlg, int itemId, int iconId, const char* tooltip)
+{
+ HWND hWnd = GetDlgItem( hwndDlg, itemId );
+ SendMessage( hWnd, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadSkinIcon( iconId ));
+ SendMessage( hWnd, BUTTONSETASFLATBTN, 0, 0 );
+ SendMessage( hWnd, BUTTONADDTOOLTIP, (WPARAM)tooltip, 0);
+}
+
+void Button_FreeIcon_IcoLib(HWND hwndDlg, int itemId)
+{
+ HICON hIcon = ( HICON )SendDlgItemMessage(hwndDlg, itemId, BM_SETIMAGE, IMAGE_ICON, 0 );
+ IconLib_ReleaseIcon(hIcon,0);
+}
+
+//
+// wParam = szProto
+// lParam = status
+//
+HICON LoadSkinProtoIcon( const char* szProto, int status, bool big )
+{
+ int i, statusIndx = -1;
+ char iconName[MAX_PATH];
+ HICON hIcon;
+ DWORD caps2 = ( szProto == NULL ) ? ( DWORD )-1 : CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_2,0);
+
+ if ( status >= ID_STATUS_CONNECTING && status < ID_STATUS_CONNECTING+MAX_CONNECT_RETRIES ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%d", mainIconsFmt, 7 );
+ return IcoLib_GetIcon( iconName, big );
+ }
+
+ for ( i = 0; i < SIZEOF(statusIcons); i++ ) {
+ if ( statusIcons[i].id == status ) {
+ statusIndx = i;
+ break;
+ } }
+
+ if ( statusIndx == -1 )
+ return NULL;
+
+ if ( !szProto ) {
+ // Only return a protocol specific icon if there is only one protocol
+ // Otherwise return the global icon. This affects the global status menu mainly.
+ if ( accounts.getCount() == 1 ) {
+ HICON hIcon;
+
+ // format: core_status_%proto%statusindex
+ mir_snprintf(iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, statusIndx);
+
+ hIcon = IcoLib_GetIcon( iconName, big );
+ if ( hIcon )
+ return hIcon;
+ }
+
+ // format: core_status_%s%d
+ mir_snprintf(iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, GLOBAL_PROTO_NAME, statusIndx);
+ return IcoLib_GetIcon( iconName, big );
+ }
+
+ // format: core_status_%s%d
+ mir_snprintf(iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, statusIndx);
+ hIcon = IcoLib_GetIcon( iconName, big );
+ if ( hIcon == NULL && ( caps2 == 0 || ( caps2 & statusIcons[statusIndx].pf2 ))) {
+ PROTOACCOUNT* pa = Proto_GetAccount( szProto );
+ if ( pa ) {
+ TCHAR szPath[MAX_PATH], szFullPath[MAX_PATH], *str;
+ SKINICONDESC sid = { 0 };
+
+ //
+ // Queried protocol isn't in list, adding
+ //
+ TCHAR tszSection[MAX_PATH];
+ mir_sntprintf( tszSection, SIZEOF(tszSection), _T("%s%s"), _T(PROTOCOLS_PREFIX), pa->tszAccountName );
+ sid.ptszSection = tszSection;
+
+ sid.cbSize = sizeof(sid);
+ sid.flags = SIDF_ALL_TCHAR;
+
+ GetModuleFileName( hMirandaInst, szPath, MAX_PATH );
+ str = _tcsrchr( szPath, '\\' );
+ if ( str != NULL )
+ *str = 0;
+ mir_sntprintf( szFullPath, SIZEOF(szFullPath), _T("%s\\Icons\\proto_") _T(TCHAR_STR_PARAM) _T(".dll"), szPath, pa->szProtoName );
+ if ( GetFileAttributes( szFullPath ) != INVALID_FILE_ATTRIBUTES )
+ sid.ptszDefaultFile = szFullPath;
+ else {
+ mir_sntprintf( szFullPath, SIZEOF(szFullPath), _T("%s\\Plugins\\") _T(TCHAR_STR_PARAM) _T(".dll"), szPath, szProto );
+ if (( int )ExtractIconEx( szFullPath, statusIcons[i].resource_id, NULL, &hIcon, 1 ) > 0 ) {
+ DestroyIcon( hIcon );
+ sid.ptszDefaultFile = szFullPath;
+ hIcon = NULL;
+ }
+
+ if ( sid.pszDefaultFile == NULL ) {
+ if ( str != NULL )
+ *str = '\\';
+ sid.ptszDefaultFile = szPath;
+ } }
+
+ //
+ // Add global icons to list
+ //
+ {
+ int lowidx, highidx;
+ if ( caps2 == 0 )
+ lowidx = statusIndx, highidx = statusIndx+1;
+ else
+ lowidx = 0, highidx = SIZEOF(statusIcons);
+
+ for ( i = lowidx; i < highidx; i++ ) {
+ if ( caps2 == 0 || ( caps2 & statusIcons[i].pf2 )) {
+ // format: core_%s%d
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, i );
+ sid.pszName = iconName;
+ sid.ptszDescription = cli.pfnGetStatusModeDescription( statusIcons[i].id, 0 );
+ sid.iDefaultIndex = statusIcons[i].resource_id;
+ IcoLib_AddNewIcon( &sid );
+ } } } }
+
+ // format: core_status_%s%d
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, statusIndx );
+ hIcon = IcoLib_GetIcon( iconName, big );
+ if ( hIcon )
+ return hIcon;
+ }
+
+ if ( hIcon == NULL ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, GLOBAL_PROTO_NAME, statusIndx );
+ hIcon = IcoLib_GetIcon( iconName, big );
+ }
+
+ return hIcon;
+}
+
+HANDLE GetSkinIconHandle( int idx )
+{
+ int i;
+ for ( i = 0; i < SIZEOF(mainIcons); i++ )
+ if ( idx == mainIcons[i].id )
+ return hMainIcons[i];
+
+ return NULL;
+}
+
+HICON LoadSkinIcon( int idx, bool big )
+{
+ //
+ // Query for global status icons
+ //
+ if ( idx < SKINICON_EVENT_MESSAGE ) {
+ if ( idx >= SIZEOF( statusIcons ))
+ return NULL;
+
+ return LoadSkinProtoIcon( NULL, statusIcons[ idx ].id, big );
+ }
+
+ return IcoLib_GetIconByHandle( GetSkinIconHandle( idx ), big );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Initializes the icon skin module
+
+static void convertOneProtocol( char* moduleName, char* iconName )
+{
+ char* pm = moduleName + strlen( moduleName );
+ char* pi = iconName + strlen( iconName );
+ DBVARIANT dbv;
+ int i;
+
+ for ( i = 0; i < SIZEOF(statusIcons); i++ ) {
+ _itoa( statusIcons[i].id, pm, 10 );
+
+ if ( !DBGetContactSettingTString( NULL, "Icons", moduleName, &dbv ) ) {
+ _itoa( i, pi, 10 );
+
+ DBWriteContactSettingTString( NULL, "SkinIcons", iconName, dbv.ptszVal );
+ DBFreeVariant( &dbv );
+
+ DBDeleteContactSetting( NULL, "Icons", moduleName );
+} } }
+
+static INT_PTR sttLoadSkinIcon( WPARAM wParam, LPARAM lParam )
+{
+ switch (lParam)
+ {
+ case 0:
+ return (INT_PTR)LoadSkinIcon( wParam );
+
+ case 1:
+ return (INT_PTR)GetSkinIconHandle( wParam );
+
+ case 2:
+ return (INT_PTR)LoadSkinIcon( wParam, true );
+ }
+
+ return 0;
+}
+
+static INT_PTR sttLoadSkinProtoIcon( WPARAM wParam, LPARAM lParam )
+{
+ return (INT_PTR)LoadSkinProtoIcon( (char*)wParam, (int)lParam, false );
+}
+
+static INT_PTR sttLoadSkinProtoIconBig( WPARAM wParam, LPARAM lParam )
+{
+ return (INT_PTR)LoadSkinProtoIcon( (char*)wParam, (int)lParam, true );
+}
+
+int LoadSkinIcons(void)
+{
+ SKINICONDESC sid;
+ int i, j = 0;
+ char iconName[MAX_PATH], moduleName[MAX_PATH];
+ TCHAR modulePath[MAX_PATH];
+ DBVARIANT dbv;
+
+ //
+ // Perform "1st-time running import"
+
+ for ( i = 0; i < SIZEOF(mainIcons); i++ ) {
+ _itoa( mainIcons[i].id, moduleName, 10 );
+ if ( DBGetContactSettingTString( NULL, "Icons", moduleName, &dbv ))
+ break;
+
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%d", mainIconsFmt, i );
+
+ DBWriteContactSettingTString( NULL, "SkinIcons", iconName, dbv.ptszVal );
+ DBFreeVariant( &dbv );
+
+ DBDeleteContactSetting( NULL, "Icons", moduleName );
+ }
+
+ for ( ;; ) {
+ // get the next protocol name
+ moduleName[0] = 'p';
+ moduleName[1] = 0;
+ _itoa( j++, moduleName+1, 100 );
+ if ( DBGetContactSettingTString( NULL, "Icons", moduleName, &dbv ))
+ break;
+
+ DBDeleteContactSetting( NULL, "Icons", moduleName );
+
+ // make old skinicons' prefix
+ mir_snprintf( moduleName, SIZEOF(moduleName), TCHAR_STR_PARAM, dbv.ptszVal );
+ // make IcoLib's prefix
+ mir_snprintf( iconName, SIZEOF(iconName), "%s" TCHAR_STR_PARAM, statusIconsFmt, dbv.ptszVal );
+
+ convertOneProtocol( moduleName, iconName );
+ DBFreeVariant( &dbv );
+ }
+ moduleName[0] = 0;
+ strcpy(iconName, "core_status_" GLOBAL_PROTO_NAME);
+ convertOneProtocol( moduleName, iconName );
+
+ CreateServiceFunction( MS_SKIN_LOADICON, sttLoadSkinIcon );
+ CreateServiceFunction( MS_SKIN_LOADPROTOICON, sttLoadSkinProtoIcon );
+ CreateServiceFunction( MS_SKIN_LOADPROTOICONBIG, sttLoadSkinProtoIconBig );
+
+ ZeroMemory( &sid, sizeof(sid) );
+ sid.cbSize = sizeof(sid);
+ GetModuleFileName(NULL, modulePath, SIZEOF(modulePath));
+ sid.ptszDefaultFile = modulePath;
+ sid.flags = SIDF_PATH_TCHAR;
+ sid.pszName = iconName;
+
+ //
+ // Add main icons to list
+ //
+ for ( i = 0; i < SIZEOF(mainIcons); i++ ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%d", mainIconsFmt, i );
+ sid.pszSection = mainIcons[i].section == NULL ? "Main Icons" : (char*)mainIcons[i].section;
+ sid.pszDescription = (char*)mainIcons[i].description;
+ sid.iDefaultIndex = mainIcons[i].resource_id;
+ hMainIcons[i] = IcoLib_AddNewIcon( &sid );
+ }
+ //
+ // Add global icons to list
+ //
+ sid.pszSection = PROTOCOLS_PREFIX "Global";
+ //
+ // Asterisk is used, to avoid conflict with proto-plugins
+ // 'coz users can't rename it to name with '*'
+ for ( i = 0; i < SIZEOF(statusIcons); i++ ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, GLOBAL_PROTO_NAME, i );
+ sid.pszName = iconName;
+ sid.pszDescription = (char*)statusIcons[i].description;
+ sid.iDefaultIndex = statusIcons[i].resource_id;
+ hStatusIcons[i] = IcoLib_AddNewIcon( &sid );
+ }
+ return 0;
+}
diff --git a/src/modules/skin/sounds.cpp b/src/modules/skin/sounds.cpp new file mode 100644 index 0000000000..734c319ac9 --- /dev/null +++ b/src/modules/skin/sounds.cpp @@ -0,0 +1,469 @@ +/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 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 "commonheaders.h"
+
+struct SoundItem {
+ char* name;
+ TCHAR* section;
+ TCHAR* description;
+ char* tempFile;
+};
+
+static BOOL bModuleInitialized = FALSE;
+static struct SoundItem *soundList = NULL;
+static int soundCount;
+static HANDLE hPlayEvent = NULL;
+
+static INT_PTR ServiceSkinAddNewSound(WPARAM, LPARAM lParam)
+{
+ SKINSOUNDDESCEX *ssd = ( SKINSOUNDDESCEX* )lParam;
+ switch( ssd->cbSize ) {
+ case sizeof( SKINSOUNDDESCEX ):
+ case SKINSOUNDDESC_SIZE_V1:
+ case SKINSOUNDDESC_SIZE_V2:
+ break;
+
+ default:
+ return 1;
+ }
+
+ if ( ssd->pszName == NULL || ssd->pszDescription == NULL)
+ return 1;
+
+ DBVARIANT dbv;
+ DWORD dwFlags = ( ssd->cbSize == sizeof(SKINSOUNDDESCEX)) ? ssd->dwFlags : 0;
+
+ soundList=(struct SoundItem*)mir_realloc(soundList,sizeof(struct SoundItem)*(soundCount+1));
+ SoundItem* item = &soundList[soundCount++];
+ item->name = mir_strdup( ssd->pszName );
+ item->tempFile = NULL;
+ #if defined( _UNICODE )
+ TCHAR* ptszDefaultFile;
+ if ( dwFlags & SSDF_UNICODE ) {
+ item->description = mir_tstrdup( TranslateTS( ssd->ptszDescription ));
+ item->section = mir_tstrdup( TranslateTS( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->ptszSection : _T("Other")));
+ ptszDefaultFile = mir_tstrdup( ssd->ptszDefaultFile );
+ }
+ else {
+ item->description = LangPackPcharToTchar( ssd->pszDescription );
+ item->section = LangPackPcharToTchar( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->pszSection : "Other" );
+ ptszDefaultFile = mir_a2t( ssd->pszDefaultFile );
+ }
+
+ if ( ptszDefaultFile ) {
+ if ( DBGetContactSettingString(NULL, "SkinSounds", item->name, &dbv))
+ DBWriteContactSettingTString(NULL, "SkinSounds", item->name, ptszDefaultFile);
+ else
+ DBFreeVariant(&dbv);
+ mir_free( ptszDefaultFile );
+ }
+ #else
+ item->description = mir_tstrdup( TranslateTS( ssd->pszDescription ));
+ item->section = mir_tstrdup( TranslateTS( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->pszSection : "Other" ));
+ if ( ssd->pszDefaultFile ) {
+ if ( DBGetContactSettingString(NULL, "SkinSounds", item->name, &dbv))
+ DBWriteContactSettingString(NULL, "SkinSounds", item->name, ssd->pszDefaultFile);
+ else
+ DBFreeVariant(&dbv);
+ }
+ #endif
+ return 0;
+}
+
+static int SkinPlaySoundDefault(WPARAM wParam, LPARAM lParam)
+{
+ char * pszFile = (char *) lParam;
+ if ( pszFile && (DBGetContactSettingByte(NULL,"Skin","UseSound",0) || (int)wParam==1))
+ PlaySoundA(pszFile, NULL, SND_ASYNC | SND_FILENAME | SND_NOWAIT);
+
+ return 0;
+}
+
+static INT_PTR ServiceSkinPlaySound(WPARAM, LPARAM lParam)
+{
+ char* pszSoundName = ( char* )lParam;
+ int j;
+
+ for (j=0; j<soundCount; j++) {
+ if ( pszSoundName && strcmp( soundList[j].name, pszSoundName ) == 0) {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", pszSoundName, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSettingString(NULL, "SkinSounds", pszSoundName, &dbv)==0) {
+ char szFull[MAX_PATH];
+
+ pathToAbsolute(dbv.pszVal, szFull, NULL);
+ NotifyEventHooks(hPlayEvent, 0, (LPARAM)szFull);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while( tvi.hItem != NULL ) {
+ TreeView_GetItem( hwndTree, &tvi );
+ if ( !_tcsicmp( str, name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+#define DM_REBUILD_STREE (WM_USER+1)
+#define DM_HIDEPANE (WM_USER+2)
+#define DM_SHOWPANE (WM_USER+3)
+#define DM_CHECKENABLED (WM_USER+4)
+INT_PTR CALLBACK DlgProcSoundOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hwndTree = NULL;
+ switch (msg) {
+ case WM_DESTROY:
+ ImageList_Destroy(TreeView_GetImageList(hwndTree, TVSIL_STATE));
+ break;
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ hwndTree = GetDlgItem(hwndDlg, IDC_SOUNDTREE);
+ SetWindowLongPtr(hwndTree,GWL_STYLE,GetWindowLongPtr(hwndTree,GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES);
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ SendMessage(hwndDlg, DM_REBUILD_STREE, 0, 0);
+ TreeView_SetItemState(hwndTree, 0, TVIS_SELECTED, TVIS_SELECTED);
+ CheckDlgButton(hwndDlg, IDC_ENABLESOUNDS, DBGetContactSettingByte(NULL, "Skin", "UseSound", 0));
+ SendMessage(hwndDlg, DM_CHECKENABLED, 0, 0);
+ return TRUE;
+
+ case DM_REBUILD_STREE:
+ TreeView_SelectItem(hwndTree, NULL);
+ ShowWindow(hwndTree, SW_HIDE);
+ TreeView_DeleteAllItems(hwndTree);
+ {
+ TVINSERTSTRUCT tvis;
+ int i;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for( i=0; i < soundCount; i++ ) {
+ tvis.item.stateMask = TVIS_EXPANDED;
+ tvis.item.state = TVIS_EXPANDED;
+ tvis.hParent = FindNamedTreeItemAtRoot( hwndTree, soundList[i].section );
+ if ( tvis.hParent == NULL ) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = soundList[i].section;
+ tvis.hParent = tvis.item.hItem = TreeView_InsertItem( hwndTree, &tvis );
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(0);
+ TreeView_SetItem( hwndTree, &tvis.item );
+ }
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(!DBGetContactSettingByte(NULL,"SkinSoundsOff",soundList[i].name,0)?2:1);
+ tvis.item.lParam = i;
+ tvis.item.pszText = soundList[i].description;
+ TreeView_InsertItem( hwndTree, &tvis );
+ } }
+ { TVITEM tvi;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if ( tvi.lParam == -1 )
+ TreeView_SetItemState(hwndTree, tvi.hItem, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK);
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+
+ ShowWindow(hwndTree, SW_SHOW);
+ break;
+
+ case DM_HIDEPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_HIDE);
+ break;
+
+ case DM_SHOWPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_SHOW);
+ break;
+
+ case DM_CHECKENABLED:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SOUNDTREE), IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS));
+ if (!IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS))
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ else if (TreeView_GetSelection(hwndTree)&&TreeView_GetParent(hwndTree, TreeView_GetSelection(hwndTree)))
+ SendMessage(hwndDlg, DM_SHOWPANE, 0, 0);
+ break;
+
+ case WM_COMMAND:
+ if ( LOWORD(wParam) == IDC_ENABLESOUNDS )
+ SendMessage(hwndDlg, DM_CHECKENABLED, 0, 0);
+
+ if ( LOWORD(wParam) == IDC_PREVIEW ) {
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ if (soundList[tvi.lParam].tempFile)
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)soundList[tvi.lParam].tempFile);
+ else {
+ DBVARIANT dbv;
+ if(!DBGetContactSettingString(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ char szPathFull[MAX_PATH];
+
+ pathToAbsolute(dbv.pszVal, szPathFull, NULL);
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)szPathFull);
+ DBFreeVariant(&dbv);
+ } }
+ break;
+ }
+ if ( LOWORD( wParam ) == IDC_CHANGE ) {
+ char str[MAX_PATH] = "", strFull[MAX_PATH], strdir[MAX_PATH]="", filter[MAX_PATH];
+ OPENFILENAMEA ofn;
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ if (soundList[tvi.lParam].tempFile)
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile);
+ else {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", soundList[tvi.lParam].name, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSettingString(NULL, "SkinSounds", soundList[tvi.lParam].name, &dbv)==0) {
+ pathToAbsolute(dbv.pszVal, strdir, NULL);
+ DBFreeVariant(&dbv);
+ } } }
+
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile?soundList[tvi.lParam].tempFile:"");
+ pathToAbsolute(strFull, strdir, NULL);
+ ZeroMemory(&ofn, sizeof(ofn));
+ mir_snprintf(filter, SIZEOF(filter), "%s (*.wav; *.mp3; *.ogg; *.flac)%c*.WAV; *.MP3; *.OGG; *.FLAC%c%s (*)%c*%c", Translate("Sound Files"), 0, 0, Translate("All Files"), 0, 0);
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = GetParent(hwndDlg);
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = filter;
+ { char* slash = strrchr(strdir, '\\');
+ if (slash) {
+ *slash = 0;
+ ofn.lpstrInitialDir = strdir;
+ }
+ }
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_LONGNAMES|OFN_NOCHANGEDIR;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "wav";
+ if(!GetOpenFileNameA(&ofn)) break;
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)str, (LPARAM)strFull);
+ soundList[tvi.lParam].tempFile = mir_strdup(strFull);
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, strFull);
+ }
+ if(LOWORD(wParam)==IDC_GETMORE) {
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=5");
+ break;
+ }
+ if(LOWORD(wParam)==IDC_LOCATION) {
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY)
+ {
+ int i;
+
+ DBWriteContactSettingByte(NULL, "Skin", "UseSound", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS));
+ for ( i=0; i < soundCount; i++ )
+ if ( soundList[i].tempFile )
+ DBWriteContactSettingString(NULL,"SkinSounds",soundList[i].name,soundList[i].tempFile);
+ {
+ TVITEM tvi,tvic;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if ( tvi.lParam == -1 ) {
+ tvic.hItem = TreeView_GetChild(hwndTree, tvi.hItem);
+ while ( tvic.hItem != NULL ) {
+ tvic.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvic);
+ if ((( tvic.state & TVIS_STATEIMAGEMASK ) >> 12 == 2 )) {
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = "SkinSoundsOff";
+ cgs.szSetting = soundList[tvic.lParam].name;
+ CallService(MS_DB_CONTACT_DELETESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cgs);
+ }
+ else DBWriteContactSettingByte(NULL,"SkinSoundsOff",soundList[tvic.lParam].name,1);
+ tvic.hItem=TreeView_GetNextSibling(hwndTree,tvic.hItem);
+ } }
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+ return TRUE;
+ }
+ break;
+ case IDC_SOUNDTREE:
+ switch(((NMHDR*)lParam)->code) {
+ case TVN_SELCHANGEDA:
+ {
+ NMTREEVIEW *pnmtv = (NMTREEVIEW*)lParam;
+ TVITEM tvi = pnmtv->itemNew;
+
+ if (tvi.lParam==-1) {
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ }
+ else {
+ TCHAR buf[256];
+ DBVARIANT dbv;
+
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s: %s"), soundList[tvi.lParam].section, soundList[tvi.lParam].description);
+ SetDlgItemText(hwndDlg, IDC_NAMEVAL, buf);
+ if (soundList[tvi.lParam].tempFile)
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, soundList[tvi.lParam].tempFile);
+ else if(!DBGetContactSettingString(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else SetDlgItemText(hwndDlg, IDC_LOCATION, TranslateT("<not specified>"));
+ SendMessage(hwndDlg, DM_SHOWPANE, 0, 0);
+ }
+ }
+ break;
+ case TVN_KEYDOWN:
+ {
+ NMTVKEYDOWN* ptkd = (NMTVKEYDOWN*)lParam;
+
+ if (ptkd&&ptkd->wVKey==VK_SPACE&&TreeView_GetSelection(ptkd->hdr.hwndFrom))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case NM_CLICK:
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt);
+ if(TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom,&hti))
+ if (hti.flags&TVHT_ONITEM)
+ if(hti.flags&TVHT_ONITEMSTATEICON)
+ if (TreeView_GetParent(hwndTree, hti.hItem)!=NULL)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ } }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static UINT iconsExpertOnlyControls[]={IDC_IMPORT};
+
+static int SkinOptionsInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -200000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SOUND);
+ odp.pszGroup = LPGEN("Customize");
+ odp.pszTitle = LPGEN("Sounds");
+ odp.pfnDlgProc = DlgProcSoundOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int SkinSystemModulesLoaded(WPARAM, LPARAM)
+{
+ HookEvent(ME_OPT_INITIALISE,SkinOptionsInit);
+ return 0;
+}
+
+int LoadSkinSounds(void)
+{
+ bModuleInitialized = TRUE;
+
+ soundList=NULL;
+ soundCount=0;
+ CreateServiceFunction(MS_SKIN_ADDNEWSOUND,ServiceSkinAddNewSound);
+ CreateServiceFunction(MS_SKIN_PLAYSOUND,ServiceSkinPlaySound);
+ HookEvent(ME_SYSTEM_MODULESLOADED,SkinSystemModulesLoaded);
+ hPlayEvent=CreateHookableEvent(ME_SKIN_PLAYINGSOUND);
+ SetHookDefaultForHookableEvent(hPlayEvent, SkinPlaySoundDefault);
+ return 0;
+}
+
+void UnloadSkinSounds(void)
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ for(i=0;i<soundCount;i++) {
+ mir_free(soundList[i].name);
+ mir_free(soundList[i].section);
+ mir_free(soundList[i].description);
+ if (soundList[i].tempFile) mir_free(soundList[i].tempFile);
+ }
+ if(soundCount) mir_free(soundList);
+}
|