From 8007a659cd115857a71947cf6d309ab8e96895dc Mon Sep 17 00:00:00 2001 From: mataes2007 Date: Wed, 4 May 2011 19:04:57 +0000 Subject: added FavContacts git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@65 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- FavContacts/src/main.cpp | 1453 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1453 insertions(+) create mode 100644 FavContacts/src/main.cpp (limited to 'FavContacts/src/main.cpp') diff --git a/FavContacts/src/main.cpp b/FavContacts/src/main.cpp new file mode 100644 index 0000000..b6d7486 --- /dev/null +++ b/FavContacts/src/main.cpp @@ -0,0 +1,1453 @@ +/* +Favourite Contacts for Miranda IM + +Copyright 2007 Victor Pavlychko + +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 "headers.h" + +DWORD g_mirandaVersion; +PLUGINLINK* pluginLink = NULL; +HINSTANCE g_hInst; + +struct LIST_INTERFACE li; +struct MM_INTERFACE mmi; +struct UTF8_INTERFACE utfi; + +// {AC8B66B3-AFE1-4475-BABA-49783BA39A66} +#define MIID_FAVCONTACTS { 0xac8b66b3, 0xafe1, 0x4475, { 0xba, 0xba, 0x49, 0x78, 0x3b, 0xa3, 0x9a, 0x66 } } + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + "Favourite Contacts", + PLUGIN_MAKE_VERSION(0, 0, 0, 6), + "Favourite contacts menu", + "code by Victor Pavlychko, icons by Angeli-Ka", + "nullbie@gmail.com", + "Copyright 2007-2009 Victor Pavlychko", + "http://nullbie.miranda.im/", + UNICODE_AWARE, + 0, // replace internal version (if any) +#ifdef _UNICODE + // {CE2C0401-F9E0-40d7-8E95-1A4197D7AB04} + { 0xce2c0401, 0xf9e0, 0x40d7, { 0x8e, 0x95, 0x1a, 0x41, 0x97, 0xd7, 0xab, 0x4 } } +#else + // {DE1D765C-9DC2-4679-8633-EDAD492C8479} + { 0xde1d765c, 0x9dc2, 0x4679, { 0x86, 0x33, 0xed, 0xad, 0x49, 0x2c, 0x84, 0x79 } } +#endif +}; + +#define MS_FAVCONTACTS_SHOWMENU "FavContacts/ShowMenu" +#define MS_FAVCONTACTS_SHOWMENU_CENTERED "FavContacts/ShowMenuCentered" +#define MS_FAVCONTACTS_OPEN_CONTACT "FavContacts/OpenContact" + +HWND g_hwndMenuHost = NULL; +static LRESULT CALLBACK MenuHostWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +static BOOL CALLBACK OptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static void sttLoadOptions(); +static void sttSaveOptions(); + +int sttShowMenu(bool centered); + +INT_PTR svcOpenContact(WPARAM wParam, LPARAM lParam); + +INT_PTR svcShowMenu(WPARAM wParam, LPARAM lParam); +INT_PTR svcShowMenuCentered(WPARAM wParam, LPARAM lParam); +int ProcessSrmmEvent(WPARAM wParam, LPARAM lParam); +int ProcessSrmmIconClick(WPARAM wParam, LPARAM lParam); + +int g_icoFavourite=0, g_icoRegular=0; +float g_widthMultiplier = 0; +int g_maxItemWidth = 0; + +CContactCache *g_contactCache = NULL; +TCHAR g_filter[1024] = {0}; + +Options g_Options = {0}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + g_hInst = hinstDLL; + return TRUE; +} + +bool CoreCheck() +{ + char version[1024], exepath[1024]; + GetModuleFileNameA(GetModuleHandle(NULL), exepath, sizeof(exepath)); + CallService(MS_SYSTEM_GETVERSIONTEXT, sizeof(version), (LPARAM)version); + _strlwr(exepath); _strlwr(version); + if (!strstr(strrchr(exepath, '\\'), "miranda") || + strstr(version, "coffee") || + (*version && (!strncmp(version, "1.", 2) || strstr(version, " 1."))) || + (g_mirandaVersion >= PLUGIN_MAKE_VERSION(1,0,0,0))) + { + MessageBoxA(0, + Translate( + "Favourite Contacts plugin was designed to be used with Miranda IM only.\n" + "For use with any other application, please contact author.\n" + ), + "Favourite Contacts Error", + MB_ICONSTOP|MB_OK); + return false; + } + return true; +} + +extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion) +{ + g_mirandaVersion = mirandaVersion; + return &pluginInfo; +} + +extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfo(DWORD mirandaVersion) +{ + g_mirandaVersion = mirandaVersion; + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID *MirandaPluginInterfaces(void) +{ + static const MUUID interfaces[] = { MIID_FAVCONTACTS, MIID_LAST }; + return interfaces; +} + +static __forceinline COLORREF sttShadeColor(COLORREF clLine1, COLORREF clBack) +{ + return RGB( + (GetRValue(clLine1) * 66UL + GetRValue(clBack) * 34UL) / 100, + (GetGValue(clLine1) * 66UL + GetGValue(clBack) * 34UL) / 100, + (GetBValue(clLine1) * 66UL + GetBValue(clBack) * 34UL) / 100 + ); +} + +HANDLE hhkProcessTBLoaded = NULL; +int ProcessTBLoaded(WPARAM wParam, LPARAM lParam) +{ + TBButton button = {0}; + button.cbSize = sizeof(button); + button.pszButtonID = "FavContacts/ShowMenu"; + button.pszTooltipUp = button.pszTooltipUp = + button.pszButtonName = "Favourite Contacts"; + button.pszServiceName = MS_FAVCONTACTS_SHOWMENU; + button.defPos = 200; + button.tbbFlags = TBBF_SHOWTOOLTIP|TBBF_VISIBLE; + button.hSecondaryIconHandle = button.hPrimaryIconHandle = (HANDLE)g_icoFavourite; + CallService(MS_TB_ADDBUTTON, 0, (LPARAM)&button); + + return 0; +} + +int ProcessReloadFonts(WPARAM wParam, LPARAM lParam) +{ + if (g_Options.hfntName) DeleteObject(g_Options.hfntName); + if (g_Options.hfntSecond) DeleteObject(g_Options.hfntSecond); + + LOGFONT lf = {0}; + FontIDT fontid = {0}; + fontid.cbSize = sizeof(fontid); + lstrcpy(fontid.group, _T("Favourite Contacts")); + + lstrcpy(fontid.name, _T("Contact name")); + g_Options.clLine1 = CallService(MS_FONT_GETT, (WPARAM)&fontid, (LPARAM)&lf); + g_Options.hfntName = CreateFontIndirect(&lf); + + lstrcpy(fontid.name, _T("Second line")); + g_Options.clLine2 = CallService(MS_FONT_GETT, (WPARAM)&fontid, (LPARAM)&lf); + g_Options.hfntSecond = CreateFontIndirect(&lf); + + lstrcpy(fontid.name, _T("Selected contact name (color)")); + g_Options.clLine1Sel = CallService(MS_FONT_GETT, (WPARAM)&fontid, (LPARAM)&lf); + + lstrcpy(fontid.name, _T("Selected second line (color)")); + g_Options.clLine2Sel = CallService(MS_FONT_GETT, (WPARAM)&fontid, (LPARAM)&lf); + + ColourIDT colourid = {0}; + colourid.cbSize = sizeof(colourid); + lstrcpy(colourid.group, _T("Favourite Contacts")); + + lstrcpy(colourid.name, _T("Background")); + g_Options.clBack = CallService(MS_COLOUR_GETT, (WPARAM)&colourid, (LPARAM)&lf); + + lstrcpy(colourid.name, _T("Selected background")); + g_Options.clBackSel = CallService(MS_COLOUR_GETT, (WPARAM)&colourid, (LPARAM)&lf); + + return 0; +} + +int ProcessModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + if (ServiceExists(MS_MSG_ADDICON)) + { + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = "FavContacts"; + sid.szTooltip = Translate("Favourite Contacts"); + sid.hIcon = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, g_icoFavourite); + sid.hIconDisabled = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, g_icoRegular); + CallService(MS_MSG_ADDICON, 0, (LPARAM)&sid); + + HookEvent(ME_MSG_ICONPRESSED, ProcessSrmmIconClick); + HookEvent(ME_MSG_WINDOWEVENT, ProcessSrmmEvent); + } + + if (true /* ServiceExists(MS_FONT_REGISTERT) */) + { + //LOGFONT lf; + //GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); + + FontIDT fontid = {0}; + fontid.cbSize = sizeof(fontid); + lstrcpy(fontid.group, _T("Favourite Contacts")); + lstrcpyA(fontid.dbSettingsGroup, "FavContacts"); + lstrcpy(fontid.backgroundGroup, _T("Favourite Contacts")); + fontid.flags = FIDF_DEFAULTVALID; + fontid.deffontsettings.charset = DEFAULT_CHARSET; + fontid.deffontsettings.size = -11; + lstrcpy(fontid.deffontsettings.szFace, _T("MS Shell Dlg")); + fontid.deffontsettings.style = 0; + + lstrcpy(fontid.backgroundName, _T("Background")); + + lstrcpy(fontid.name, _T("Contact name")); + lstrcpyA(fontid.prefix, "fntName"); + fontid.deffontsettings.colour = GetSysColor(COLOR_MENUTEXT); + fontid.deffontsettings.style = DBFONTF_BOLD; + CallService(MS_FONT_REGISTERT, (WPARAM)&fontid, 0); + + lstrcpy(fontid.name, _T("Second line")); + lstrcpyA(fontid.prefix, "fntSecond"); + fontid.deffontsettings.colour = sttShadeColor(GetSysColor(COLOR_MENUTEXT), GetSysColor(COLOR_MENU)); + fontid.deffontsettings.style = 0; + CallService(MS_FONT_REGISTERT, (WPARAM)&fontid, 0); + + lstrcpy(fontid.backgroundName, _T("Selected background")); + + lstrcpy(fontid.name, _T("Selected contact name (color)")); + lstrcpyA(fontid.prefix, "fntNameSel"); + fontid.deffontsettings.colour = GetSysColor(COLOR_HIGHLIGHTTEXT); + fontid.deffontsettings.style = DBFONTF_BOLD; + CallService(MS_FONT_REGISTERT, (WPARAM)&fontid, 0); + + lstrcpy(fontid.name, _T("Selected second line (color)")); + lstrcpyA(fontid.prefix, "fntSecondSel"); + fontid.deffontsettings.colour = sttShadeColor(GetSysColor(COLOR_HIGHLIGHTTEXT), GetSysColor(COLOR_HIGHLIGHT)); + fontid.deffontsettings.style = 0; + CallService(MS_FONT_REGISTERT, (WPARAM)&fontid, 0); + + ColourIDT colourid = {0}; + colourid.cbSize = sizeof(colourid); + lstrcpy(colourid.group, _T("Favourite Contacts")); + lstrcpyA(colourid.dbSettingsGroup, "FavContacts"); + + lstrcpy(colourid.name, _T("Background")); + lstrcpyA(colourid.setting, "BackColour"); + colourid.defcolour = GetSysColor(COLOR_MENU); + CallService(MS_COLOUR_REGISTERT, (WPARAM)&colourid, 0); + + lstrcpy(colourid.name, _T("Selected background")); + lstrcpyA(colourid.setting, "SelectedColour"); + colourid.defcolour = GetSysColor(COLOR_HIGHLIGHT); + CallService(MS_COLOUR_REGISTERT, (WPARAM)&colourid, 0); + + HookEvent(ME_FONT_RELOAD, ProcessReloadFonts); + HookEvent(ME_COLOUR_RELOAD, ProcessReloadFonts); + ProcessReloadFonts(0, 0); + } + + if (ServiceExists(MS_HOTKEY_REGISTER)) + { + HOTKEYDESC hotkey = {0}; + hotkey.cbSize = sizeof(hotkey); + hotkey.pszName = "FavContacts/ShowMenu"; + hotkey.pszDescription = "Show favourite contacts"; + hotkey.pszSection = "Contacts"; + hotkey.pszService = MS_FAVCONTACTS_SHOWMENU_CENTERED; + hotkey.DefHotKey = MAKEWORD('Q', HOTKEYF_EXT); + CallService(MS_HOTKEY_REGISTER, 0, (LPARAM)&hotkey); + } + + if (ServiceExists(MS_AV_GETAVATARBITMAP)) + { + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + for ( ; hContact; hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + if (DBGetContactSettingByte(hContact, "FavContacts", "IsFavourite", 0)) + CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); + } + + if (!hhkProcessTBLoaded) hhkProcessTBLoaded = HookEvent(ME_TB_MODULELOADED, ProcessTBLoaded); + + return 0; +} + +int ProcessOptInitialise(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof(odp); + odp.position = 100000000; + odp.hInstance = g_hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); + odp.ptszGroup = TranslateT("Contact List"); + odp.ptszTitle = TranslateT("Favourites"); + odp.groupPosition = 910000000; + odp.flags = ODPF_BOLDGROUPS|ODPF_TCHAR; + odp.pfnDlgProc = OptionsDlgProc; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + return 0; +} + +extern "C" __declspec(dllexport) int Load(PLUGINLINK * link) +{ + pluginLink = link; + + if (!CoreCheck()) return 1; + + mir_getLI(&li); + mir_getMMI(&mmi); + mir_getUTFI(&utfi); + + g_contactCache = new CContactCache; + + WNDCLASSEX wcl = {0}; + wcl.cbSize = sizeof(wcl); + wcl.lpfnWndProc = MenuHostWndProc; + wcl.style = 0; + wcl.cbClsExtra = 0; + wcl.cbWndExtra = 0; + wcl.hInstance = g_hInst; + wcl.hIcon = NULL; + wcl.hCursor = LoadCursor(NULL, IDC_ARROW); + wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); + wcl.lpszMenuName = NULL; + wcl.lpszClassName = _T("FavContactsMenuHostWnd"); + wcl.hIconSm = NULL; + RegisterClassEx(&wcl); + + g_hwndMenuHost = CreateWindow(_T("FavContactsMenuHostWnd"), NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, g_hInst, NULL); + SetWindowPos(g_hwndMenuHost, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_HIDEWINDOW); + + sttLoadOptions(); + + CreateServiceFunction(MS_FAVCONTACTS_SHOWMENU, svcShowMenu); + CreateServiceFunction(MS_FAVCONTACTS_SHOWMENU_CENTERED, svcShowMenuCentered); + CreateServiceFunction(MS_FAVCONTACTS_OPEN_CONTACT, svcOpenContact); + + HookEvent(ME_OPT_INITIALISE, ProcessOptInitialise); + HookEvent(ME_SYSTEM_MODULESLOADED, ProcessModulesLoaded); + hhkProcessTBLoaded = HookEvent(ME_TB_MODULELOADED, ProcessTBLoaded); + + if (true /*ServiceExists(MS_SKIN2_ADDICON)*/) + { + TCHAR buf[MAX_PATH]; + GetModuleFileName(g_hInst, buf, SIZEOF(buf)); + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(sid); + sid.ptszSection = _T("Favourites"); + sid.ptszDefaultFile = buf; + sid.cx = sid.cy = 16; + sid.flags = SIDF_ALL_TCHAR; + + sid.pszName = "favcontacts_favourite"; + sid.ptszDescription = _T("Favourite Contact"); + sid.iDefaultIndex = -IDI_FAVOURITE; + g_icoFavourite = CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + + sid.pszName = "favcontacts_regular"; + sid.ptszDescription = _T("Regular Contact"); + sid.iDefaultIndex = -IDI_REGULAR; + g_icoRegular = CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } + + LoadHttpApi(); + +#ifdef _DEBUG + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.flags = CMIF_ICONFROMICOLIB; + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_OPTIONS); + mi.position = 1900000000; + mi.pszName = LPGEN("&Favourite Contacts..."); + mi.pszService = MS_FAVCONTACTS_SHOWMENU; + CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi ); +#endif + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + UnloadHttpApi(); + if (g_hwndMenuHost) DestroyWindow(g_hwndMenuHost); + if (g_Options.hfntName) DeleteObject(g_Options.hfntName); + if (g_Options.hfntSecond) DeleteObject(g_Options.hfntSecond); + delete g_contactCache; + return 0; +} + +static void sttLoadOptions() +{ + g_Options.bSecondLine = DBGetContactSettingByte(NULL, "FavContacts", "SecondLine", 1); + g_Options.bAvatars = DBGetContactSettingByte(NULL, "FavContacts", "Avatars", 1); + g_Options.bAvatarBorder = DBGetContactSettingByte(NULL, "FavContacts", "AvatarBorder", 0); + g_Options.wAvatarRadius = DBGetContactSettingWord(NULL, "FavContacts", "AvatarRadius", 3); + g_Options.bNoTransparentBorder = DBGetContactSettingByte(NULL, "FavContacts", "NoTransparentBorder", + !DBGetContactSettingByte(NULL, "FavContacts", "AvatarBorderTransparent", 1)); + g_Options.bSysColors = DBGetContactSettingByte(NULL, "FavContacts", "SysColors", 0); + g_Options.bCenterHotkey = DBGetContactSettingByte(NULL, "FavContacts", "CenterHotkey", 1); + g_Options.bUseGroups = DBGetContactSettingByte(NULL, "FavContacts", "UseGroups", 0); + g_Options.bUseColumns = DBGetContactSettingByte(NULL, "FavContacts", "UseColumns", 1); + g_Options.bRightAvatars = DBGetContactSettingByte(NULL, "FavContacts", "RightAvatars", 0); + g_Options.bDimIdle = DBGetContactSettingByte(NULL, "FavContacts", "DimIdle", 1); + + g_Options.wMaxRecent = DBGetContactSettingByte(NULL, "FavContacts", "MaxRecent", 10); +} + +static void sttSaveOptions() +{ + DBWriteContactSettingByte(NULL, "FavContacts", "SecondLine", g_Options.bSecondLine); + DBWriteContactSettingByte(NULL, "FavContacts", "Avatars", g_Options.bAvatars); + DBWriteContactSettingByte(NULL, "FavContacts", "AvatarBorder", g_Options.bAvatarBorder); + DBWriteContactSettingWord(NULL, "FavContacts", "AvatarRadius", g_Options.wAvatarRadius); + DBWriteContactSettingByte(NULL, "FavContacts", "NoTransparentBorder", g_Options.bNoTransparentBorder); + DBWriteContactSettingByte(NULL, "FavContacts", "SysColors", g_Options.bSysColors); + DBWriteContactSettingByte(NULL, "FavContacts", "CenterHotkey", g_Options.bCenterHotkey); + DBWriteContactSettingByte(NULL, "FavContacts", "UseGroups", g_Options.bUseGroups); + DBWriteContactSettingByte(NULL, "FavContacts", "UseColumns", g_Options.bUseColumns); + DBWriteContactSettingByte(NULL, "FavContacts", "RightAvatars", g_Options.bRightAvatars); + DBWriteContactSettingByte(NULL, "FavContacts", "DimIdle", g_Options.bDimIdle); + DBWriteContactSettingWord(NULL, "FavContacts", "MaxRecent", g_Options.wMaxRecent); +} + +static bool sttIsGroup(int id) +{ + if (id == 1) return true; + + DBVARIANT dbv = {0}; + char buf[32]; + wsprintfA(buf, "%d", (int)(id-2)); + if (!DBGetContactSettingTString(NULL, "CListGroups", buf, &dbv)) + { + DBFreeVariant(&dbv); + return true; + } + return false; +} + +static TCHAR *sttGetGroupName(int id) +{ + if (id == 1) + { + if (g_Options.bUseGroups) + return mir_tstrdup(TranslateT("")); + return mir_tstrdup(TranslateT("Favourite Contacts")); + } + + DBVARIANT dbv = {0}; + char buf[32]; + wsprintfA(buf, "%d", (int)(id-2)); + if (!DBGetContactSettingTString(NULL, "CListGroups", buf, &dbv)) + { + TCHAR *res = mir_tstrdup(dbv.ptszVal+1); + DBFreeVariant(&dbv); + return res; + } + return NULL; +} + +static int sttGetGroupId(TCHAR *name) +{ + for (int i = 0; ; ++i) + { + DBVARIANT dbv = {0}; + char buf[32]; + wsprintfA(buf, "%d", (int)i); + if (!DBGetContactSettingTString(NULL, "CListGroups", buf, &dbv)) + { + if (!lstrcmp(dbv.ptszVal+1, name)) + { + DBFreeVariant(&dbv); + return i+2; + } + + DBFreeVariant(&dbv); + } else + { + // default is root + return 1; + } + } +} + +static BOOL sttMeasureItem_Group(LPMEASUREITEMSTRUCT lpmis, Options *options) +{ + if (true) + { + HDC hdc = GetDC(g_hwndMenuHost); + HFONT hfntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + TCHAR *name = sttGetGroupName(lpmis->itemData); + SIZE sz; + if (!options->bSysColors) SelectObject(hdc, g_Options.hfntName); + GetTextExtentPoint32(hdc, name, lstrlen(name), &sz); + lpmis->itemHeight = sz.cy + 8; + lpmis->itemWidth = sz.cx + 10; + mir_free(name); + SelectObject(hdc, hfntSave); + ReleaseDC(g_hwndMenuHost, hdc); + } + + return TRUE; +} + +static BOOL sttMeasureItem_Contact(LPMEASUREITEMSTRUCT lpmis, Options *options) +{ + HANDLE hContact = (HANDLE)lpmis->itemData; + + lpmis->itemHeight = 4; + lpmis->itemWidth = 8+10; + + if (true) + { + lpmis->itemWidth += 20; + } + + if (true) + { + SIZE sz; + int textWidth = 0; + + HDC hdc = GetDC(g_hwndMenuHost); + HFONT hfntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + + if (options->bSecondLine) + { + DBVARIANT dbv; + TCHAR *title; + bool bFree = false; + if (DBGetContactSettingTString(hContact, "CList", "StatusMsg", &dbv) || !*dbv.ptszVal) + { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + int status = DBGetContactSettingWord(hContact, proto, "Status", ID_STATUS_OFFLINE); + title = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, GCMDF_TCHAR); + } else + { + title = dbv.ptszVal; + bFree = true; + } + + if (!options->bSysColors) SelectObject(hdc, g_Options.hfntSecond); + GetTextExtentPoint32(hdc, title, lstrlen(title), &sz); + if (bFree) DBFreeVariant(&dbv); + textWidth = sz.cx; + lpmis->itemHeight += sz.cy + 3; + } + + TCHAR *name = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); + + if (!options->bSysColors) SelectObject(hdc, g_Options.hfntName); + GetTextExtentPoint32(hdc, name, lstrlen(name), &sz); + textWidth = max(textWidth, sz.cx); + + SelectObject(hdc, hfntSave); + ReleaseDC(g_hwndMenuHost, hdc); + + lpmis->itemWidth += textWidth; + lpmis->itemHeight += sz.cy; + } + + if (options->bAvatars) + { + AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); + if (ace && (ace != (AVATARCACHEENTRY *)CALLSERVICE_NOTFOUND)) + { + int avatarWidth = lpmis->itemHeight; + if (ace->bmWidth < ace->bmHeight) + avatarWidth = lpmis->itemHeight * ace->bmWidth / ace->bmHeight; + + lpmis->itemWidth += avatarWidth + 5; + } + } + + if (lpmis->itemHeight < 18) lpmis->itemHeight = 18; + + return TRUE; +} + +static BOOL sttMeasureItem(LPMEASUREITEMSTRUCT lpmis, Options *options=NULL) +{ + if (!options) options = &g_Options; + + if (!lpmis->itemData) + return FALSE; + + BOOL res = FALSE; + if (sttIsGroup(lpmis->itemData)) + res = sttMeasureItem_Group(lpmis, options); + else if (CallService(MS_DB_CONTACT_IS, lpmis->itemData, 0)) + res = sttMeasureItem_Contact(lpmis, options); + + if (res && (lpmis->itemWidth > g_maxItemWidth)) lpmis->itemWidth = g_maxItemWidth; + if (res && g_widthMultiplier) lpmis->itemWidth *= g_widthMultiplier; + + return FALSE; +} + +static BOOL sttDrawItem_Group(LPDRAWITEMSTRUCT lpdis, Options *options = NULL) +{ + lpdis->rcItem.top++; + lpdis->rcItem.bottom--; + + HFONT hfntSave = (HFONT)SelectObject(lpdis->hDC, GetStockObject(DEFAULT_GUI_FONT)); + SetBkMode(lpdis->hDC, TRANSPARENT); + if (options->bSysColors) + { + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + //FrameRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } else + { + HBRUSH hbr; + hbr = CreateSolidBrush(g_Options.clBackSel); + FillRect(lpdis->hDC, &lpdis->rcItem, hbr); + DeleteObject(hbr); + //hbr = CreateSolidBrush(g_Options.clBackSel); + //FrameRect(lpdis->hDC, &lpdis->rcItem, hbr); + //DeleteObject(hbr); + SetTextColor(lpdis->hDC, g_Options.clLine1Sel); + } + + if (true) + { + TCHAR *name = sttGetGroupName(lpdis->itemData); + if (!options->bSysColors) SelectObject(lpdis->hDC, g_Options.hfntName); + DrawText(lpdis->hDC, name, lstrlen(name), &lpdis->rcItem, DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_CENTER); + mir_free(name); + } + + SelectObject(lpdis->hDC, hfntSave); + + return TRUE; +} + +void ImageList_DrawDimmed(HIMAGELIST himl, int i, HDC hdc, int left, int top, UINT fStyle) +{ + typedef BOOL (WINAPI *TFnAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); + static TFnAlphaBlend pfnAlphaBlend = NULL; + bool load_funcs = true; + + if (load_funcs) + { + pfnAlphaBlend = (TFnAlphaBlend)GetProcAddress(GetModuleHandleA("msimg32"), "AlphaBlend"); + load_funcs = false; + } + + int dx, dy; + ImageList_GetIconSize(himl, &dx, &dy); + + HDC dcMem = CreateCompatibleDC(hdc); + HBITMAP hbm = CreateCompatibleBitmap(hdc, dx, dy); + HBITMAP hbmOld = (HBITMAP)SelectObject(dcMem, hbm); + BitBlt(dcMem, 0, 0, dx, dx, hdc, left, top, SRCCOPY); + ImageList_Draw(himl, i, dcMem, 0, 0, fStyle); + if (pfnAlphaBlend) + { + BLENDFUNCTION bf = {0}; + bf.SourceConstantAlpha = 180; + pfnAlphaBlend(hdc, left, top, dx, dy, dcMem, 0, 0, dx, dy, bf); + } else + { + SetStretchBltMode(hdc, HALFTONE); + StretchBlt(hdc, left, top, dx, dy, dcMem, 0, 0, dx, dy, SRCCOPY); + } + SelectObject(dcMem, hbmOld); + DeleteObject(hbm); + DeleteDC(dcMem); +} + +static BOOL sttDrawItem_Contact(LPDRAWITEMSTRUCT lpdis, Options *options = NULL) +{ + HANDLE hContact = (HANDLE)lpdis->itemData; + + HDC hdcTemp = CreateCompatibleDC(lpdis->hDC); + HBITMAP hbmTemp = CreateCompatibleBitmap(lpdis->hDC, lpdis->rcItem.right-lpdis->rcItem.left, lpdis->rcItem.bottom-lpdis->rcItem.top); + HBITMAP hbmSave = (HBITMAP)SelectObject(hdcTemp, hbmTemp); + RECT rcSave = lpdis->rcItem; + + OffsetRect(&lpdis->rcItem, -lpdis->rcItem.left, -lpdis->rcItem.top); + + HFONT hfntSave = (HFONT)SelectObject(hdcTemp, GetStockObject(DEFAULT_GUI_FONT)); + SetBkMode(hdcTemp, TRANSPARENT); + COLORREF clBack, clLine1, clLine2; + if (lpdis->itemState & ODS_SELECTED) + { + if (options->bSysColors) + { + FillRect(hdcTemp, &lpdis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT)); + clBack = GetSysColor(COLOR_HIGHLIGHT); + clLine1 = GetSysColor(COLOR_HIGHLIGHTTEXT); + } else + { + clBack = g_Options.clBackSel; + clLine1 = g_Options.clLine1Sel; + clLine2 = g_Options.clLine2Sel; + } + } else + { + if (options->bSysColors) + { + FillRect(hdcTemp, &lpdis->rcItem, GetSysColorBrush(COLOR_MENU)); + clBack = GetSysColor(COLOR_MENU); + clLine1 = GetSysColor(COLOR_MENUTEXT); + } else + { + clBack = g_Options.clBack; + clLine1 = g_Options.clLine1; + clLine2 = g_Options.clLine2; + } + } + if (options->bSysColors) + { + clLine2 = RGB( + (GetRValue(clLine1) * 66UL + GetRValue(clBack) * 34UL) / 100, + (GetGValue(clLine1) * 66UL + GetGValue(clBack) * 34UL) / 100, + (GetBValue(clLine1) * 66UL + GetBValue(clBack) * 34UL) / 100 + ); + } else + { + HBRUSH hbr = CreateSolidBrush(clBack); + FillRect(hdcTemp, &lpdis->rcItem, hbr); + DeleteObject(hbr); + } + + lpdis->rcItem.left += 4; + lpdis->rcItem.right -= 4; + + lpdis->rcItem.top += 2; + lpdis->rcItem.bottom -= 2; + + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + if (true) + { + HIMAGELIST hIml = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0); + int iIcon = CallService(MS_CLIST_GETCONTACTICON, (WPARAM)hContact, 0); + + if (DBGetContactSettingDword(hContact, proto, "IdleTS", 0)) + { + ImageList_DrawDimmed(hIml, iIcon, hdcTemp, + lpdis->rcItem.left, (lpdis->rcItem.top + lpdis->rcItem.bottom - 16) / 2, + ILD_TRANSPARENT); + } else + { + ImageList_Draw(hIml, iIcon, hdcTemp, + lpdis->rcItem.left, (lpdis->rcItem.top + lpdis->rcItem.bottom - 16) / 2, + ILD_TRANSPARENT); + } + + lpdis->rcItem.left += 20; + } + + if (options->wMaxRecent && DBGetContactSettingByte(hContact, "FavContacts", "IsFavourite", 0)) + { + DrawIconEx(hdcTemp, lpdis->rcItem.right - 18, (lpdis->rcItem.top + lpdis->rcItem.bottom - 16) / 2, + (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, g_icoFavourite), 16, 16, 0, NULL, DI_NORMAL); + lpdis->rcItem.right -= 20; + } + + if (options->bAvatars) + { + AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); + if (ace && (ace != (AVATARCACHEENTRY *)CALLSERVICE_NOTFOUND)) + { + int avatarWidth = lpdis->rcItem.bottom - lpdis->rcItem.top; + if (ace->bmWidth < ace->bmHeight) + avatarWidth = (lpdis->rcItem.bottom - lpdis->rcItem.top) * ace->bmWidth / ace->bmHeight; + + AVATARDRAWREQUEST avdr = {0}; + avdr.cbSize = sizeof(avdr); + avdr.hContact = hContact; + avdr.hTargetDC = hdcTemp; + avdr.rcDraw = lpdis->rcItem; + if (options->bRightAvatars) + avdr.rcDraw.left = avdr.rcDraw.right - avatarWidth; + else + avdr.rcDraw.right = avdr.rcDraw.left + avatarWidth; + avdr.dwFlags = AVDRQ_FALLBACKPROTO; + if (options->bAvatarBorder) + { + avdr.dwFlags |= AVDRQ_DRAWBORDER; + avdr.clrBorder = clLine1; + if (options->bNoTransparentBorder) + avdr.dwFlags |= AVDRQ_HIDEBORDERONTRANSPARENCY; + if (options->wAvatarRadius) + { + avdr.dwFlags |= AVDRQ_ROUNDEDCORNER; + avdr.radius = (unsigned char)options->wAvatarRadius; + } + } + avdr.alpha = 255; + CallService(MS_AV_DRAWAVATAR, 0, (LPARAM)&avdr); + + if (options->bRightAvatars) + lpdis->rcItem.right += avatarWidth + 5; + else + lpdis->rcItem.left += avatarWidth + 5; + } + } + + if (true) + { + TCHAR *name = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); + + if (!options->bSysColors) SelectObject(hdcTemp, g_Options.hfntName); + SetTextColor(hdcTemp, clLine1); + DrawText(hdcTemp, name, lstrlen(name), &lpdis->rcItem, DT_NOPREFIX|DT_SINGLELINE|DT_TOP|DT_LEFT); + + SIZE sz; GetTextExtentPoint32(hdcTemp, name, lstrlen(name), &sz); + lpdis->rcItem.top += sz.cy + 3; + } + + if (options->bSecondLine) + { + DBVARIANT dbv; + TCHAR *title; + bool bFree = false; + if (DBGetContactSettingTString(hContact, "CList", "StatusMsg", &dbv) || !*dbv.ptszVal) + { + int status = DBGetContactSettingWord(hContact, proto, "Status", ID_STATUS_OFFLINE); + title = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, GCMDF_TCHAR); + } else + { + title = dbv.ptszVal; + bFree = true; + } + + if (!options->bSysColors) SelectObject(hdcTemp, g_Options.hfntSecond); + SetTextColor(hdcTemp, clLine2); + DrawText(hdcTemp, title, lstrlen(title), &lpdis->rcItem, DT_NOPREFIX|DT_SINGLELINE|DT_TOP|DT_LEFT); + + if (bFree) DBFreeVariant(&dbv); + } + + SelectObject(hdcTemp, hfntSave); + + BitBlt(lpdis->hDC, + rcSave.left, rcSave.top, + rcSave.right-rcSave.left, rcSave.bottom-rcSave.top, + hdcTemp, 0, 0, SRCCOPY); + + SelectObject(hdcTemp, hbmSave); + DeleteObject(hbmTemp); + DeleteDC(hdcTemp); + + return TRUE; +} + +static BOOL sttDrawItem(LPDRAWITEMSTRUCT lpdis, Options *options=NULL) +{ + if (!options) options = &g_Options; + + if (!lpdis->itemData) + return FALSE; + + if (sttIsGroup(lpdis->itemData)) + return sttDrawItem_Group(lpdis, options); + + if (CallService(MS_DB_CONTACT_IS, lpdis->itemData, 0)) + return sttDrawItem_Contact(lpdis, options); + + return FALSE; +} + +static LRESULT CALLBACK MenuHostWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hContact = NULL; + + switch (message) + { + case WM_MEASUREITEM: + { + LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; + + if (lpmis->CtlType != ODT_MENU) return FALSE; + + if ((lpmis->itemID >= CLISTMENUIDMIN) && (lpmis->itemID <= CLISTMENUIDMAX)) + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + + return sttMeasureItem(lpmis); + } + + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; + + if (lpdis->CtlType != ODT_MENU) return FALSE; + + if ((lpdis->itemID >= CLISTMENUIDMIN) && (lpdis->itemID <= CLISTMENUIDMAX)) + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + + return sttDrawItem(lpdis); + } + + case WM_MENUCHAR: + { + while (GetMenuItemCount((HMENU)lParam) > 1) + RemoveMenu((HMENU)lParam, 1, MF_BYPOSITION); + + if (LOWORD(wParam) == VK_BACK) + { + if (int l = lstrlen(g_filter)) + g_filter[l-1] = 0; + } else + if (_istalnum(LOWORD(wParam))) + { + if (lstrlen(g_filter) < SIZEOF(g_filter)-1) + { + TCHAR s[] = { LOWORD(wParam), 0 }; + lstrcat(g_filter, s); + } + } + + int nRecent = 0; + int maxRecent = g_Options.wMaxRecent ? g_Options.wMaxRecent : 10; + for (int i = 0; nRecent < maxRecent; ++i) + { + HANDLE hContact = g_contactCache->get(i); + if (!hContact) break; + if (!g_contactCache->filter(i, g_filter)) continue; + + AppendMenu((HMENU)lParam, MF_OWNERDRAW, nRecent+1, (LPCTSTR)hContact); + ++nRecent; + } + return MAKELRESULT(1, MNC_SELECT); + } + + case WM_MENURBUTTONUP: + { + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_DATA; + GetMenuItemInfo((HMENU)lParam, wParam, TRUE, &mii); + HANDLE hContact = (HANDLE)mii.dwItemData; + if (!CallService(MS_DB_CONTACT_IS, mii.dwItemData, 0)) return FALSE; + + HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0); + + POINT pt; + GetCursorPos(&pt); + HWND hwndSave = GetForegroundWindow(); + SetForegroundWindow(g_hwndMenuHost); + int res = TrackPopupMenu(hMenu, TPM_RECURSE|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, g_hwndMenuHost, NULL); + SetForegroundWindow(hwndSave); + DestroyMenu(hMenu); + + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(res, MPCF_CONTACTMENU), (LPARAM)hContact); + return TRUE; + } + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + +int sttShowMenu(bool centered) +{ + TFavContacts favList; + HMENU hMenu = CreatePopupMenu(); + SIZE szMenu = {0}; + SIZE szColumn = {0}; + TCHAR *prevGroup = NULL; + int i, idItem; + HANDLE hContact; + + favList.build(); + + g_widthMultiplier = 0; + + g_maxItemWidth = GetSystemMetrics(SM_CXSCREEN); + if (g_Options.bUseColumns) g_maxItemWidth /= favList.groupCount(); + + prevGroup = NULL; + for (i = 0; i < favList.getCount(); ++i) + { + hContact = favList[i]->getHandle(); + + MEASUREITEMSTRUCT mis = {0}; + mis.CtlID = 0; + mis.CtlType = ODT_MENU; + + if (!prevGroup || lstrcmp(prevGroup, favList[i]->getGroup())) + { + if (prevGroup && g_Options.bUseColumns) + { + szMenu.cx += szColumn.cx; + szMenu.cy = max(szMenu.cy, szColumn.cy); + szColumn.cx = szColumn.cy = 0; + } + + DWORD groupID = sttGetGroupId(favList[i]->getGroup()); + + AppendMenu(hMenu, + MF_OWNERDRAW|MF_SEPARATOR| ((prevGroup && g_Options.bUseColumns) ? MF_MENUBREAK : 0), + ++idItem, (LPCTSTR)groupID); + + mis.itemData = groupID; + mis.itemID = idItem; + sttMeasureItem(&mis); + szColumn.cx = max(szColumn.cx, mis.itemWidth); + szColumn.cy += mis.itemHeight; + } + + AppendMenu(hMenu, MF_OWNERDRAW, ++idItem, (LPCTSTR)hContact); + + mis.itemData = (DWORD)hContact; + mis.itemID = idItem; + sttMeasureItem(&mis); + szColumn.cx = max(szColumn.cx, mis.itemWidth); + szColumn.cy += mis.itemHeight; + + prevGroup = favList[i]->getGroup(); + } + szMenu.cx += szColumn.cx; + szMenu.cy = max(szMenu.cy, szColumn.cy); + szColumn.cx = szColumn.cy = 0; + + unsigned maxWidth = GetSystemMetrics(SM_CXSCREEN) * DBGetContactSettingByte(NULL, "FavContacts", "MenuWidth", 66) / 100; + if (szMenu.cx > maxWidth) + { + g_widthMultiplier = (float)maxWidth / szMenu.cx; + szMenu.cx *= g_widthMultiplier; + } + + POINT pt; + +// RECT rc; +// GetMenuItemRect(g_hwndMenuHost, hMenu, 1, &rc); + + if (centered) + { + if ((pt.x = (GetSystemMetrics(SM_CXSCREEN) - szMenu.cx) / 2) < 0) pt.x = 0; + if ((pt.y = (GetSystemMetrics(SM_CYSCREEN) - szMenu.cy) / 2) < 0) pt.y = 0; + } else + { + GetCursorPos(&pt); + } + + HWND hwndSave = GetForegroundWindow(); + SetForegroundWindow(g_hwndMenuHost); + hContact = NULL; + g_filter[0] = 0; + if (int res = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, g_hwndMenuHost, NULL)) + { + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_DATA; + GetMenuItemInfo(hMenu, res, FALSE, &mii); + hContact = (HANDLE)mii.dwItemData; + } + SetForegroundWindow(hwndSave); + DestroyMenu(hMenu); + + if (hContact) + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)hContact, 0); + + return 0; +} + +INT_PTR svcShowMenu(WPARAM wParam, LPARAM lParam) +{ + sttShowMenu(false); + return 0; +} + +INT_PTR svcShowMenuCentered(WPARAM wParam, LPARAM lParam) +{ + sttShowMenu(g_Options.bCenterHotkey ? true : false); + return 0; +} + +static HANDLE hDialogsList = NULL; +static HANDLE hContactToActivate = NULL; + +INT_PTR svcOpenContact(WPARAM wParam, LPARAM lParam) +{ + hContactToActivate = (HANDLE)wParam; + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)hContactToActivate, 0); + return 0; +} + +int ProcessSrmmEvent( WPARAM wParam, LPARAM lParam ) +{ + MessageWindowEventData *event = (MessageWindowEventData *)lParam; + + if ( event->uType == MSG_WINDOW_EVT_OPEN ) + { + if ( !hDialogsList ) + hDialogsList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + WindowList_Add(hDialogsList, event->hwndWindow, event->hContact); + + BYTE fav = DBGetContactSettingByte(event->hContact, "FavContacts", "IsFavourite", 0); + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = "FavContacts"; + sid.flags = fav ? 0 : MBF_DISABLED; + CallService(MS_MSG_MODIFYICON, (WPARAM)event->hContact, (LPARAM)&sid); + + if (event->hContact == hContactToActivate) + { + HWND hwndRoot = event->hwndWindow; + while (HWND hwndParent = GetParent(hwndRoot)) + hwndRoot = hwndParent; + + AttachThreadInput(GetWindowThreadProcessId(GetForegroundWindow(), NULL), GetCurrentThreadId(), TRUE); + SetForegroundWindow(hwndRoot); + SetActiveWindow(hwndRoot); + SetFocus(hwndRoot); + AttachThreadInput(GetWindowThreadProcessId(GetForegroundWindow(), NULL), GetCurrentThreadId(), FALSE); + } + + hContactToActivate = NULL; + } + else if ( event->uType == MSG_WINDOW_EVT_CLOSING ) + { + if (hDialogsList) + WindowList_Remove(hDialogsList, event->hwndWindow); + } + + return 0; +} + +int ProcessSrmmIconClick( WPARAM wParam, LPARAM lParam ) +{ + StatusIconClickData *sicd = (StatusIconClickData *)lParam; + if (lstrcmpA(sicd->szModule, "FavContacts")) return 0; + + HANDLE hContact = (HANDLE)wParam; + if (!hContact) return 0; + + if (sicd->flags & MBCF_RIGHTBUTTON) + { + BYTE fav = !DBGetContactSettingByte(hContact, "FavContacts", "IsFavourite", 0); + DBWriteContactSettingByte(hContact, "FavContacts", "IsFavourite", fav); + if (fav) CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); + + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = "FavContacts"; + sid.flags = fav ? 0 : MBF_DISABLED; + CallService(MS_MSG_MODIFYICON, (WPARAM)hContact, (LPARAM)&sid); + } else + { + sttShowMenu(false); + } + + return 0; +} + +/////////////////////////////////////////////// +// Options +static void sttResetListOptions(HWND hwndList) +{ + int i; + SendMessage(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL); + SendMessage(hwndList,CLM_SETBKCOLOR,GetSysColor(COLOR_WINDOW),0); + SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0); + SendMessage(hwndList,CLM_SETLEFTMARGIN,4,0); + SendMessage(hwndList,CLM_SETINDENT,10,0); + SendMessage(hwndList,CLM_SETHIDEEMPTYGROUPS,1,0); + SendMessage(hwndList,CLM_SETHIDEOFFLINEROOT,1,0); + for (i = 0; i <= FONTID_MAX; ++i) + SendMessage(hwndList, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); +} + +static void sttActivateOptionsPage(HWND hwnd, TCHAR *aSection, TCHAR *aPage) +{ + TCHAR buf[256]; + TCHAR *section = TranslateTS(aSection); + + HWND hwndTree = FindWindowEx(GetParent(hwnd), NULL, WC_TREEVIEW, NULL); + for (HTREEITEM htiSection = TreeView_GetRoot(hwndTree); htiSection; htiSection = TreeView_GetNextSibling(hwndTree, htiSection)) + { + TVITEM tvi = {0}; + tvi.mask = TVIF_TEXT; + tvi.hItem = htiSection; + tvi.pszText = buf; + tvi.cchTextMax = SIZEOF(buf); + TreeView_GetItem(hwndTree, &tvi); + + if (!lstrcmp(buf, section)) + { + if (!aPage) + { + TreeView_Select(hwndTree, htiSection, TVGN_CARET); + return; + } else + { + TreeView_Expand(hwndTree, htiSection, TVE_EXPAND); + } + + TCHAR *page = TranslateTS(aPage); + for (HTREEITEM htiPage = TreeView_GetChild(hwndTree, htiSection); htiPage; htiPage = TreeView_GetNextSibling(hwndTree, htiPage)) + { + TVITEM tvi = {0}; + tvi.mask = TVIF_TEXT; + tvi.hItem = htiPage; + tvi.pszText = buf; + tvi.cchTextMax = SIZEOF(buf); + TreeView_GetItem(hwndTree, &tvi); + + if (!lstrcmp(buf, page)) + { + TreeView_Select(hwndTree, htiPage, TVGN_CARET); + return; + } + } + + break; + } + } +} + +static BOOL CALLBACK OptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static bool bInitialized = false; + static HANDLE hSelectedContact = 0; + + switch (msg) + { + case WM_INITDIALOG: + { + bInitialized = false; + + TranslateDialogDefault(hwnd); + + CheckDlgButton(hwnd, IDC_CHK_GROUPS, g_Options.bUseGroups ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_GROUPCOLUMS, g_Options.bUseColumns ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_SECONDLINE, g_Options.bSecondLine ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_AVATARS, g_Options.bAvatars ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_AVATARBORDER, g_Options.bAvatarBorder ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_NOTRANSPARENTBORDER, g_Options.bNoTransparentBorder ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_SYSCOLORS, g_Options.bSysColors ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_CENTERHOTKEY, g_Options.bCenterHotkey ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_RIGHTAVATARS, g_Options.bRightAvatars ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CHK_DIMIDLE, g_Options.bDimIdle ? BST_CHECKED : BST_UNCHECKED); + SetDlgItemInt(hwnd, IDC_TXT_RADIUS, g_Options.wAvatarRadius, FALSE); + SetDlgItemInt(hwnd, IDC_TXT_MAXRECENT, g_Options.wMaxRecent, FALSE); + + SetWindowLong(GetDlgItem(hwnd, IDC_CLIST), GWL_STYLE, + GetWindowLong(GetDlgItem(hwnd, IDC_CLIST), GWL_STYLE)|CLS_CHECKBOXES|CLS_HIDEEMPTYGROUPS|CLS_USEGROUPS|CLS_GREYALTERNATE|CLS_GROUPCHECKBOXES); + SendMessage(GetDlgItem(hwnd, IDC_CLIST), CLM_SETEXSTYLE, CLS_EX_DISABLEDRAGDROP|CLS_EX_TRACKSELECT, 0); + sttResetListOptions(GetDlgItem(hwnd, IDC_CLIST)); + + hSelectedContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + for ( ; hContact; hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + { + SendDlgItemMessage(hwnd, IDC_CLIST, CLM_SETCHECKMARK, + SendDlgItemMessage(hwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0), + DBGetContactSettingByte(hContact, "FavContacts", "IsFavourite", 0)); + } + + if (!ServiceExists(MS_HOTKEY_REGISTER)) + EnableWindow(GetDlgItem(hwnd, IDC_BTN_HOTKEYS), FALSE); + + bInitialized = true; + + PostMessage(hwnd, WM_APP, 0, 0); + + return TRUE; + } + + case WM_APP: + { + BOOL bGroups = IsDlgButtonChecked(hwnd, IDC_CHK_GROUPS); + EnableWindow(GetDlgItem(hwnd, IDC_CHK_GROUPCOLUMS), bGroups); + + BOOL bAvatars = IsDlgButtonChecked(hwnd, IDC_CHK_AVATARS); + BOOL bBorders = IsDlgButtonChecked(hwnd, IDC_CHK_AVATARBORDER); + EnableWindow(GetDlgItem(hwnd, IDC_CHK_AVATARBORDER), bAvatars); + EnableWindow(GetDlgItem(hwnd, IDC_CHK_RIGHTAVATARS), bAvatars); + EnableWindow(GetDlgItem(hwnd, IDC_CHK_NOTRANSPARENTBORDER), bAvatars && bBorders); + EnableWindow(GetDlgItem(hwnd, IDC_TXT_RADIUS), bAvatars && bBorders); + return TRUE; + } + + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; + if (lpdis->CtlID == IDC_CANVAS) + { + MEASUREITEMSTRUCT mis = {0}; + DRAWITEMSTRUCT dis = *lpdis; + + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(COLOR_BTNFACE)); + if (hSelectedContact) + { + Options options; + options.bSecondLine = IsDlgButtonChecked(hwnd, IDC_CHK_SECONDLINE); + options.bAvatars = IsDlgButtonChecked(hwnd, IDC_CHK_AVATARS); + options.bAvatarBorder = IsDlgButtonChecked(hwnd, IDC_CHK_AVATARBORDER); + options.bNoTransparentBorder = IsDlgButtonChecked(hwnd, IDC_CHK_NOTRANSPARENTBORDER); + options.bSysColors = IsDlgButtonChecked(hwnd, IDC_CHK_SYSCOLORS); + options.bCenterHotkey = IsDlgButtonChecked(hwnd, IDC_CHK_CENTERHOTKEY); + options.bRightAvatars = IsDlgButtonChecked(hwnd, IDC_CHK_RIGHTAVATARS); + options.bDimIdle = IsDlgButtonChecked(hwnd, IDC_CHK_DIMIDLE); + options.wAvatarRadius = GetDlgItemInt(hwnd, IDC_TXT_RADIUS, NULL, FALSE); + options.wMaxRecent = GetDlgItemInt(hwnd, IDC_TXT_MAXRECENT, NULL, FALSE); + + mis.CtlID = 0; + mis.CtlType = ODT_MENU; + mis.itemData = (DWORD)hSelectedContact; + sttMeasureItem(&mis, &options); + dis.rcItem.bottom = dis.rcItem.top + mis.itemHeight; + + dis.CtlID = 0; + dis.CtlType = ODT_MENU; + dis.itemData = (DWORD)hSelectedContact; + sttDrawItem(&dis, &options); + + RECT rc = lpdis->rcItem; + rc.bottom = rc.top + mis.itemHeight; + FrameRect(lpdis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHT)); + } + + return TRUE; + } + return FALSE; + } + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_CHK_SECONDLINE: + case IDC_CHK_AVATARS: + case IDC_CHK_AVATARBORDER: + case IDC_CHK_NOTRANSPARENTBORDER: + case IDC_CHK_SYSCOLORS: + case IDC_CHK_CENTERHOTKEY: + case IDC_CHK_GROUPS: + case IDC_CHK_GROUPCOLUMS: + case IDC_CHK_RIGHTAVATARS: + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + RedrawWindow(GetDlgItem(hwnd, IDC_CANVAS), NULL, NULL, RDW_INVALIDATE); + PostMessage(hwnd, WM_APP, 0, 0); + break; + + case IDC_BTN_HOTKEYS: + if (ServiceExists(MS_HOTKEY_REGISTER)) + { + sttActivateOptionsPage(hwnd, _T("Customize"), _T("Hotkeys")); + } + break; + + case IDC_BTN_FONTS: + sttActivateOptionsPage(hwnd, _T("Customize"), _T("Fonts")); + break; + + case IDC_TXT_RADIUS: + if ((HIWORD(wParam) == EN_CHANGE) && bInitialized) + { + RedrawWindow(GetDlgItem(hwnd, IDC_CANVAS), NULL, NULL, RDW_INVALIDATE); + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + } + break; + + case IDC_TXT_MAXRECENT: + if ((HIWORD(wParam) == EN_CHANGE) && bInitialized) + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + break; + } + break; + } + + case WM_NOTIFY: + { + if ((((LPNMHDR)lParam)->idFrom == 0) && (((LPNMHDR)lParam)->code == PSN_APPLY)) + { + g_Options.bSecondLine = IsDlgButtonChecked(hwnd, IDC_CHK_SECONDLINE); + g_Options.bAvatars = IsDlgButtonChecked(hwnd, IDC_CHK_AVATARS); + g_Options.bAvatarBorder = IsDlgButtonChecked(hwnd, IDC_CHK_AVATARBORDER); + g_Options.bNoTransparentBorder = IsDlgButtonChecked(hwnd, IDC_CHK_NOTRANSPARENTBORDER); + g_Options.bSysColors = IsDlgButtonChecked(hwnd, IDC_CHK_SYSCOLORS); + g_Options.bCenterHotkey = IsDlgButtonChecked(hwnd, IDC_CHK_CENTERHOTKEY); + g_Options.bUseGroups = IsDlgButtonChecked(hwnd, IDC_CHK_GROUPS); + g_Options.bUseColumns = IsDlgButtonChecked(hwnd, IDC_CHK_GROUPCOLUMS); + g_Options.bRightAvatars = IsDlgButtonChecked(hwnd, IDC_CHK_RIGHTAVATARS); + g_Options.bDimIdle = IsDlgButtonChecked(hwnd, IDC_CHK_DIMIDLE); + g_Options.wAvatarRadius = GetDlgItemInt(hwnd, IDC_TXT_RADIUS, NULL, FALSE); + g_Options.wMaxRecent = GetDlgItemInt(hwnd, IDC_TXT_MAXRECENT, NULL, FALSE); + + sttSaveOptions(); + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + for ( ; hContact; hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + { + BYTE fav = SendDlgItemMessage(hwnd, IDC_CLIST, CLM_GETCHECKMARK, + SendDlgItemMessage(hwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0), 0); + if (fav != DBGetContactSettingByte(hContact, "FavContacts", "IsFavourite", 0)) + DBWriteContactSettingByte(hContact, "FavContacts", "IsFavourite", fav); + if (fav) CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); + } + } else + if (((LPNMHDR)lParam)->idFrom == IDC_CLIST) + { + switch (((LPNMHDR)lParam)->code) + { + case CLN_OPTIONSCHANGED: + { + sttResetListOptions(GetDlgItem(hwnd,IDC_CLIST)); + break; + } + + case CLN_NEWCONTACT: + { + int iSelection = (int)((NMCLISTCONTROL *)lParam)->hItem; + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + for ( ; hContact; hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + if (SendDlgItemMessage(hwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0) == iSelection) + { + SendDlgItemMessage(hwnd, IDC_CLIST, CLM_SETCHECKMARK, iSelection, + DBGetContactSettingByte(hContact, "FavContacts", "IsFavourite", 0)); + break; + } + break; + } + + case CLN_CHECKCHANGED: + { + int iSelection = (int)((NMCLISTCONTROL *)lParam)->hItem; + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + for ( ; hContact; hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) + if (SendDlgItemMessage(hwnd, IDC_CLIST, CLM_FINDCONTACT, (WPARAM)hContact, 0) == iSelection) + break; + if (hContact) + { + hSelectedContact = hContact; + RedrawWindow(GetDlgItem(hwnd, IDC_CANVAS), NULL, NULL, RDW_INVALIDATE); + } + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + } + } + } + break; + } + } + + return FALSE; +} -- cgit v1.2.3