From 78d71d2cad6f243c6ff31d41380b8c5b58407de5 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Thu, 17 May 2012 17:37:22 +0000 Subject: added some plugins git-svn-id: http://svn.miranda-ng.org/main/trunk@20 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Autorun/autorun.h | 14 + plugins/Autorun/autorun.rc | 83 ++ plugins/Autorun/autorun.sln | 26 + plugins/Autorun/autorun.txt | 50 + plugins/Autorun/autorun.vcxproj | 230 ++++ plugins/Autorun/autorun.vcxproj.filters | 40 + plugins/Autorun/main.c | 165 +++ plugins/Autorun/resource.h | 15 + plugins/Boltun/Boltun.rc | 155 +++ plugins/Boltun/Boltun2.gif | Bin 0 -> 13171 bytes plugins/Boltun/Boltun_10.sln | 19 + plugins/Boltun/Boltun_10.vcxproj | 197 +++ plugins/Boltun/Boltun_10.vcxproj.filters | 110 ++ plugins/Boltun/Engine/COPYING.txt | 339 +++++ plugins/Boltun/Engine/CriticalSection.h | 56 + plugins/Boltun/Engine/Mind.cpp | 448 ++++++ plugins/Boltun/Engine/Mind.h | 89 ++ plugins/Boltun/Engine/MyCodeCvt.cpp | 85 ++ plugins/Boltun/Engine/MyCodeCvt.h | 59 + plugins/Boltun/Engine/PerContactData.h | 173 +++ plugins/Boltun/Engine/TalkEngine.cpp | 609 ++++++++ plugins/Boltun/Engine/TalkEngine.h | 112 ++ plugins/Boltun/Engine/UnrecentChooser.cpp | 100 ++ plugins/Boltun/Engine/UnrecentChooser.h | 47 + plugins/Boltun/Engine/ValueChooser.h | 88 ++ plugins/Boltun/Engine/WordsList.cpp | 169 +++ plugins/Boltun/Engine/WordsList.h | 56 + plugins/Boltun/Engine/boltun.mindw | Bin 0 -> 342176 bytes plugins/Boltun/Engine/tstring.h | 34 + plugins/Boltun/TODO.txt | 35 + plugins/Boltun/actionQueue.cpp | 256 ++++ plugins/Boltun/actionQueue.h | 30 + plugins/Boltun/boltun.cpp | 718 ++++++++++ plugins/Boltun/boltun.h | 80 ++ plugins/Boltun/config.cpp | 159 +++ plugins/Boltun/config.h | 157 +++ plugins/Boltun/lang_pack.txt | 64 + plugins/Boltun/mind.txt | 142 ++ plugins/Boltun/readme.txt | 124 ++ plugins/Boltun/res/boltun.ico | Bin 0 -> 766 bytes plugins/Boltun/res/smiles.dat | Bin 0 -> 3394 bytes plugins/Boltun/resource.h | 46 + plugins/CountryFlags/Info_Src.txt | 32 + plugins/CountryFlags/License_Appendix.txt | 64 + plugins/CountryFlags/countrylistext.c | 345 +++++ plugins/CountryFlags/docs/Flags-Developer.txt | 48 + plugins/CountryFlags/docs/Flags-License.txt | 278 ++++ plugins/CountryFlags/docs/Flags-Readme.txt | 140 ++ plugins/CountryFlags/docs/Flags-Translation.txt | 74 + plugins/CountryFlags/extraimg.c | 495 +++++++ plugins/CountryFlags/flags.def | 11 + plugins/CountryFlags/flags.h | 89 ++ plugins/CountryFlags/flags.sln | 29 + plugins/CountryFlags/flags.vcxproj | 408 ++++++ plugins/CountryFlags/flags.vcxproj.filters | 138 ++ plugins/CountryFlags/huffman.c | 506 +++++++ plugins/CountryFlags/icons.c | 284 ++++ plugins/CountryFlags/ip2country.c | 327 +++++ plugins/CountryFlags/main.c | 163 +++ plugins/CountryFlags/res/flags.bmp | Bin 0 -> 122022 bytes plugins/CountryFlags/res/ip-to-country.bin | Bin 0 -> 647987 bytes plugins/CountryFlags/resource.h | 25 + plugins/CountryFlags/resource.rc | 128 ++ plugins/CountryFlags/utils.c | 162 +++ plugins/CountryFlags/version.h | 38 + plugins/CountryFlags/version.rc | 47 + plugins/FavContacts/favcontacts.sln | 19 + plugins/FavContacts/favcontacts.vcxproj | 131 ++ plugins/FavContacts/favcontacts.vcxproj.filters | 76 + plugins/FavContacts/res/favlist.ico | Bin 0 -> 2550 bytes plugins/FavContacts/res/favorite.ico | Bin 0 -> 2550 bytes plugins/FavContacts/res/regular.ico | Bin 0 -> 2550 bytes plugins/FavContacts/res/userprefs.ico | Bin 0 -> 2550 bytes plugins/FavContacts/resource.h | 39 + plugins/FavContacts/resource.rc | 166 +++ plugins/FavContacts/src/contact_cache.cpp | 231 ++++ plugins/FavContacts/src/contact_cache.h | 61 + plugins/FavContacts/src/cserver.cpp | 82 ++ plugins/FavContacts/src/cserver.h | 42 + plugins/FavContacts/src/csocket.cpp | 22 + plugins/FavContacts/src/csocket.h | 16 + plugins/FavContacts/src/favlist.cpp | 0 plugins/FavContacts/src/favlist.h | 134 ++ plugins/FavContacts/src/headers.h | 94 ++ plugins/FavContacts/src/http_api.cpp | 165 +++ plugins/FavContacts/src/http_api.h | 7 + plugins/FavContacts/src/main.cpp | 1453 ++++++++++++++++++++ plugins/FloatingContacts/FltCont_10.sln | 26 + plugins/FloatingContacts/FltCont_10.vcxproj | 254 ++++ .../FloatingContacts/FltCont_10.vcxproj.filters | 76 + plugins/FloatingContacts/Script.rc | 2 + plugins/FloatingContacts/bitmap_funcs.cpp | 1239 +++++++++++++++++ plugins/FloatingContacts/bitmap_funcs.h | 127 ++ .../FloatingContacts/docs/fltcontacts_langpack.txt | 68 + .../FloatingContacts/docs/fltcontacts_readme.txt | 91 ++ .../docs/fltcontacts_russian_langpack.txt | 70 + plugins/FloatingContacts/filedrop.cpp | 368 +++++ plugins/FloatingContacts/filedrop.h | 26 + plugins/FloatingContacts/fltcnt.rc | 232 ++++ plugins/FloatingContacts/fltcont.h | 191 +++ plugins/FloatingContacts/hide.ico | Bin 0 -> 2550 bytes plugins/FloatingContacts/main.cpp | 1331 ++++++++++++++++++ plugins/FloatingContacts/options.cpp | 1179 ++++++++++++++++ plugins/FloatingContacts/resource.h | 75 + plugins/FloatingContacts/show.ico | Bin 0 -> 2550 bytes plugins/FloatingContacts/stdhdr.h | 64 + plugins/FloatingContacts/thumbs.cpp | 1013 ++++++++++++++ plugins/FloatingContacts/thumbs.h | 74 + plugins/FloatingContacts/version.h | 29 + plugins/FloatingContacts/version.rc | 36 + plugins/Gender/commonheaders.h | 63 + plugins/Gender/docs/gender-readme.txt | 62 + plugins/Gender/docs/gender-translate.txt | 24 + plugins/Gender/gender.rc | 129 ++ plugins/Gender/gender_10.sln | 31 + plugins/Gender/gender_10.vcxproj | 263 ++++ plugins/Gender/icons/female.ico | Bin 0 -> 2550 bytes plugins/Gender/icons/gender.ico | Bin 0 -> 2550 bytes plugins/Gender/icons/male.ico | Bin 0 -> 2550 bytes plugins/Gender/main.cpp | 474 +++++++ plugins/Gender/options.cpp | 167 +++ plugins/Gender/resource.h | 25 + plugins/ProfileManager/pmanagerEx.c | 109 ++ plugins/ProfileManager/pmanagerEx.vcproj | 247 ++++ plugins/ProfileManager/res/ChangePM.ico | Bin 0 -> 1150 bytes plugins/ProfileManager/res/LoadPM.ico | Bin 0 -> 1150 bytes plugins/ProfileManager/resource.h | 17 + plugins/ProfileManager/resource.rc | 46 + plugins/Rate/commonheaders.h | 78 ++ plugins/Rate/docs/Rate-readme.txt | 49 + plugins/Rate/docs/rate.txt | 1 + plugins/Rate/icons/rate_high.ico | Bin 0 -> 1150 bytes plugins/Rate/icons/rate_low.ico | Bin 0 -> 1150 bytes plugins/Rate/icons/rate_med.ico | Bin 0 -> 1150 bytes plugins/Rate/main.cpp | 289 ++++ plugins/Rate/options.cpp | 224 +++ plugins/Rate/rate.rc | 124 ++ plugins/Rate/rate_10.sln | 26 + plugins/Rate/rate_10.vcxproj | 180 +++ plugins/Rate/rate_10.vcxproj.filters | 58 + plugins/Rate/resource.h | 22 + plugins/TooltipNotify/doc/todo.txt | 0 plugins/TooltipNotify/doc/tt_wnd_def_style.txt | 9 + plugins/TooltipNotify/doc/ttnotify-readme.txt | 128 ++ plugins/TooltipNotify/doc/ttnotify_translation.txt | 47 + plugins/TooltipNotify/src/DbHelpers.cpp | 120 ++ plugins/TooltipNotify/src/DbHelpers.h | 9 + plugins/TooltipNotify/src/Settings.h | 42 + plugins/TooltipNotify/src/Tooltip.cpp | 219 +++ plugins/TooltipNotify/src/Tooltip.h | 55 + plugins/TooltipNotify/src/TooltipNotify.cpp | 1114 +++++++++++++++ plugins/TooltipNotify/src/TooltipNotify.h | 143 ++ plugins/TooltipNotify/src/Utils.cpp | 32 + plugins/TooltipNotify/src/Utils.h | 8 + plugins/TooltipNotify/src/main.cpp | 218 +++ plugins/TooltipNotify/src/main.rc | 204 +++ plugins/TooltipNotify/src/resource.h | 47 + plugins/TooltipNotify/src/stdafx.cpp | 8 + plugins/TooltipNotify/src/stdafx.h | 37 + plugins/TooltipNotify/src/version.h | 11 + plugins/TooltipNotify/src/version.rc | 52 + plugins/TooltipNotify/ttnotify_10.sln | 25 + plugins/TooltipNotify/ttnotify_10.vcxproj | 262 ++++ plugins/TooltipNotify/ttnotify_10.vcxproj.filters | 79 ++ plugins/UserGuide/UserGuide_10.sln | 25 + plugins/UserGuide/UserGuide_10.vcxproj | 285 ++++ plugins/UserGuide/UserGuide_10.vcxproj.filters | 27 + plugins/UserGuide/commonheaders.h | 10 + plugins/UserGuide/main.c | 130 ++ plugins/w7ui/clistproxywindow.cpp | 292 ++++ plugins/w7ui/clistproxywindow.h | 64 + plugins/w7ui/dwmwindow.cpp | 209 +++ plugins/w7ui/dwmwindow.h | 59 + plugins/w7ui/headers.h | 81 ++ plugins/w7ui/jumplist.cpp | 123 ++ plugins/w7ui/jumplist.h | 7 + plugins/w7ui/jumplistarray.cpp | 214 +++ plugins/w7ui/jumplistarray.h | 29 + plugins/w7ui/jumplistbuilder.cpp | 127 ++ plugins/w7ui/jumplistbuilder.h | 47 + plugins/w7ui/main.cpp | 93 ++ plugins/w7ui/srmmproxywindow.cpp | 374 +++++ plugins/w7ui/srmmproxywindow.h | 42 + plugins/w7ui/subclassmgr.cpp | 0 plugins/w7ui/subclassmgr.h | 71 + plugins/w7ui/w7ui.cpp | 180 +++ plugins/w7ui/w7ui_10.sln | 37 + plugins/w7ui/w7ui_10.vcxproj | 364 +++++ plugins/w7ui/win7api.cpp | 25 + plugins/w7ui/win7api.h | 38 + plugins/w7ui/win7api_ICustomDestinationList.h | 34 + plugins/w7ui/win7api_IObjectArray.h | 15 + plugins/w7ui/win7api_IObjectCollection.h | 16 + plugins/w7ui/win7api_ITaskbarList3.h | 65 + 194 files changed, 27179 insertions(+) create mode 100644 plugins/Autorun/autorun.h create mode 100644 plugins/Autorun/autorun.rc create mode 100644 plugins/Autorun/autorun.sln create mode 100644 plugins/Autorun/autorun.txt create mode 100644 plugins/Autorun/autorun.vcxproj create mode 100644 plugins/Autorun/autorun.vcxproj.filters create mode 100644 plugins/Autorun/main.c create mode 100644 plugins/Autorun/resource.h create mode 100644 plugins/Boltun/Boltun.rc create mode 100644 plugins/Boltun/Boltun2.gif create mode 100644 plugins/Boltun/Boltun_10.sln create mode 100644 plugins/Boltun/Boltun_10.vcxproj create mode 100644 plugins/Boltun/Boltun_10.vcxproj.filters create mode 100644 plugins/Boltun/Engine/COPYING.txt create mode 100644 plugins/Boltun/Engine/CriticalSection.h create mode 100644 plugins/Boltun/Engine/Mind.cpp create mode 100644 plugins/Boltun/Engine/Mind.h create mode 100644 plugins/Boltun/Engine/MyCodeCvt.cpp create mode 100644 plugins/Boltun/Engine/MyCodeCvt.h create mode 100644 plugins/Boltun/Engine/PerContactData.h create mode 100644 plugins/Boltun/Engine/TalkEngine.cpp create mode 100644 plugins/Boltun/Engine/TalkEngine.h create mode 100644 plugins/Boltun/Engine/UnrecentChooser.cpp create mode 100644 plugins/Boltun/Engine/UnrecentChooser.h create mode 100644 plugins/Boltun/Engine/ValueChooser.h create mode 100644 plugins/Boltun/Engine/WordsList.cpp create mode 100644 plugins/Boltun/Engine/WordsList.h create mode 100644 plugins/Boltun/Engine/boltun.mindw create mode 100644 plugins/Boltun/Engine/tstring.h create mode 100644 plugins/Boltun/TODO.txt create mode 100644 plugins/Boltun/actionQueue.cpp create mode 100644 plugins/Boltun/actionQueue.h create mode 100644 plugins/Boltun/boltun.cpp create mode 100644 plugins/Boltun/boltun.h create mode 100644 plugins/Boltun/config.cpp create mode 100644 plugins/Boltun/config.h create mode 100644 plugins/Boltun/lang_pack.txt create mode 100644 plugins/Boltun/mind.txt create mode 100644 plugins/Boltun/readme.txt create mode 100644 plugins/Boltun/res/boltun.ico create mode 100644 plugins/Boltun/res/smiles.dat create mode 100644 plugins/Boltun/resource.h create mode 100644 plugins/CountryFlags/Info_Src.txt create mode 100644 plugins/CountryFlags/License_Appendix.txt create mode 100644 plugins/CountryFlags/countrylistext.c create mode 100644 plugins/CountryFlags/docs/Flags-Developer.txt create mode 100644 plugins/CountryFlags/docs/Flags-License.txt create mode 100644 plugins/CountryFlags/docs/Flags-Readme.txt create mode 100644 plugins/CountryFlags/docs/Flags-Translation.txt create mode 100644 plugins/CountryFlags/extraimg.c create mode 100644 plugins/CountryFlags/flags.def create mode 100644 plugins/CountryFlags/flags.h create mode 100644 plugins/CountryFlags/flags.sln create mode 100644 plugins/CountryFlags/flags.vcxproj create mode 100644 plugins/CountryFlags/flags.vcxproj.filters create mode 100644 plugins/CountryFlags/huffman.c create mode 100644 plugins/CountryFlags/icons.c create mode 100644 plugins/CountryFlags/ip2country.c create mode 100644 plugins/CountryFlags/main.c create mode 100644 plugins/CountryFlags/res/flags.bmp create mode 100644 plugins/CountryFlags/res/ip-to-country.bin create mode 100644 plugins/CountryFlags/resource.h create mode 100644 plugins/CountryFlags/resource.rc create mode 100644 plugins/CountryFlags/utils.c create mode 100644 plugins/CountryFlags/version.h create mode 100644 plugins/CountryFlags/version.rc create mode 100644 plugins/FavContacts/favcontacts.sln create mode 100644 plugins/FavContacts/favcontacts.vcxproj create mode 100644 plugins/FavContacts/favcontacts.vcxproj.filters create mode 100644 plugins/FavContacts/res/favlist.ico create mode 100644 plugins/FavContacts/res/favorite.ico create mode 100644 plugins/FavContacts/res/regular.ico create mode 100644 plugins/FavContacts/res/userprefs.ico create mode 100644 plugins/FavContacts/resource.h create mode 100644 plugins/FavContacts/resource.rc create mode 100644 plugins/FavContacts/src/contact_cache.cpp create mode 100644 plugins/FavContacts/src/contact_cache.h create mode 100644 plugins/FavContacts/src/cserver.cpp create mode 100644 plugins/FavContacts/src/cserver.h create mode 100644 plugins/FavContacts/src/csocket.cpp create mode 100644 plugins/FavContacts/src/csocket.h create mode 100644 plugins/FavContacts/src/favlist.cpp create mode 100644 plugins/FavContacts/src/favlist.h create mode 100644 plugins/FavContacts/src/headers.h create mode 100644 plugins/FavContacts/src/http_api.cpp create mode 100644 plugins/FavContacts/src/http_api.h create mode 100644 plugins/FavContacts/src/main.cpp create mode 100644 plugins/FloatingContacts/FltCont_10.sln create mode 100644 plugins/FloatingContacts/FltCont_10.vcxproj create mode 100644 plugins/FloatingContacts/FltCont_10.vcxproj.filters create mode 100644 plugins/FloatingContacts/Script.rc create mode 100644 plugins/FloatingContacts/bitmap_funcs.cpp create mode 100644 plugins/FloatingContacts/bitmap_funcs.h create mode 100644 plugins/FloatingContacts/docs/fltcontacts_langpack.txt create mode 100644 plugins/FloatingContacts/docs/fltcontacts_readme.txt create mode 100644 plugins/FloatingContacts/docs/fltcontacts_russian_langpack.txt create mode 100644 plugins/FloatingContacts/filedrop.cpp create mode 100644 plugins/FloatingContacts/filedrop.h create mode 100644 plugins/FloatingContacts/fltcnt.rc create mode 100644 plugins/FloatingContacts/fltcont.h create mode 100644 plugins/FloatingContacts/hide.ico create mode 100644 plugins/FloatingContacts/main.cpp create mode 100644 plugins/FloatingContacts/options.cpp create mode 100644 plugins/FloatingContacts/resource.h create mode 100644 plugins/FloatingContacts/show.ico create mode 100644 plugins/FloatingContacts/stdhdr.h create mode 100644 plugins/FloatingContacts/thumbs.cpp create mode 100644 plugins/FloatingContacts/thumbs.h create mode 100644 plugins/FloatingContacts/version.h create mode 100644 plugins/FloatingContacts/version.rc create mode 100644 plugins/Gender/commonheaders.h create mode 100644 plugins/Gender/docs/gender-readme.txt create mode 100644 plugins/Gender/docs/gender-translate.txt create mode 100644 plugins/Gender/gender.rc create mode 100644 plugins/Gender/gender_10.sln create mode 100644 plugins/Gender/gender_10.vcxproj create mode 100644 plugins/Gender/icons/female.ico create mode 100644 plugins/Gender/icons/gender.ico create mode 100644 plugins/Gender/icons/male.ico create mode 100644 plugins/Gender/main.cpp create mode 100644 plugins/Gender/options.cpp create mode 100644 plugins/Gender/resource.h create mode 100644 plugins/ProfileManager/pmanagerEx.c create mode 100644 plugins/ProfileManager/pmanagerEx.vcproj create mode 100644 plugins/ProfileManager/res/ChangePM.ico create mode 100644 plugins/ProfileManager/res/LoadPM.ico create mode 100644 plugins/ProfileManager/resource.h create mode 100644 plugins/ProfileManager/resource.rc create mode 100644 plugins/Rate/commonheaders.h create mode 100644 plugins/Rate/docs/Rate-readme.txt create mode 100644 plugins/Rate/docs/rate.txt create mode 100644 plugins/Rate/icons/rate_high.ico create mode 100644 plugins/Rate/icons/rate_low.ico create mode 100644 plugins/Rate/icons/rate_med.ico create mode 100644 plugins/Rate/main.cpp create mode 100644 plugins/Rate/options.cpp create mode 100644 plugins/Rate/rate.rc create mode 100644 plugins/Rate/rate_10.sln create mode 100644 plugins/Rate/rate_10.vcxproj create mode 100644 plugins/Rate/rate_10.vcxproj.filters create mode 100644 plugins/Rate/resource.h create mode 100644 plugins/TooltipNotify/doc/todo.txt create mode 100644 plugins/TooltipNotify/doc/tt_wnd_def_style.txt create mode 100644 plugins/TooltipNotify/doc/ttnotify-readme.txt create mode 100644 plugins/TooltipNotify/doc/ttnotify_translation.txt create mode 100644 plugins/TooltipNotify/src/DbHelpers.cpp create mode 100644 plugins/TooltipNotify/src/DbHelpers.h create mode 100644 plugins/TooltipNotify/src/Settings.h create mode 100644 plugins/TooltipNotify/src/Tooltip.cpp create mode 100644 plugins/TooltipNotify/src/Tooltip.h create mode 100644 plugins/TooltipNotify/src/TooltipNotify.cpp create mode 100644 plugins/TooltipNotify/src/TooltipNotify.h create mode 100644 plugins/TooltipNotify/src/Utils.cpp create mode 100644 plugins/TooltipNotify/src/Utils.h create mode 100644 plugins/TooltipNotify/src/main.cpp create mode 100644 plugins/TooltipNotify/src/main.rc create mode 100644 plugins/TooltipNotify/src/resource.h create mode 100644 plugins/TooltipNotify/src/stdafx.cpp create mode 100644 plugins/TooltipNotify/src/stdafx.h create mode 100644 plugins/TooltipNotify/src/version.h create mode 100644 plugins/TooltipNotify/src/version.rc create mode 100644 plugins/TooltipNotify/ttnotify_10.sln create mode 100644 plugins/TooltipNotify/ttnotify_10.vcxproj create mode 100644 plugins/TooltipNotify/ttnotify_10.vcxproj.filters create mode 100644 plugins/UserGuide/UserGuide_10.sln create mode 100644 plugins/UserGuide/UserGuide_10.vcxproj create mode 100644 plugins/UserGuide/UserGuide_10.vcxproj.filters create mode 100644 plugins/UserGuide/commonheaders.h create mode 100644 plugins/UserGuide/main.c create mode 100644 plugins/w7ui/clistproxywindow.cpp create mode 100644 plugins/w7ui/clistproxywindow.h create mode 100644 plugins/w7ui/dwmwindow.cpp create mode 100644 plugins/w7ui/dwmwindow.h create mode 100644 plugins/w7ui/headers.h create mode 100644 plugins/w7ui/jumplist.cpp create mode 100644 plugins/w7ui/jumplist.h create mode 100644 plugins/w7ui/jumplistarray.cpp create mode 100644 plugins/w7ui/jumplistarray.h create mode 100644 plugins/w7ui/jumplistbuilder.cpp create mode 100644 plugins/w7ui/jumplistbuilder.h create mode 100644 plugins/w7ui/main.cpp create mode 100644 plugins/w7ui/srmmproxywindow.cpp create mode 100644 plugins/w7ui/srmmproxywindow.h create mode 100644 plugins/w7ui/subclassmgr.cpp create mode 100644 plugins/w7ui/subclassmgr.h create mode 100644 plugins/w7ui/w7ui.cpp create mode 100644 plugins/w7ui/w7ui_10.sln create mode 100644 plugins/w7ui/w7ui_10.vcxproj create mode 100644 plugins/w7ui/win7api.cpp create mode 100644 plugins/w7ui/win7api.h create mode 100644 plugins/w7ui/win7api_ICustomDestinationList.h create mode 100644 plugins/w7ui/win7api_IObjectArray.h create mode 100644 plugins/w7ui/win7api_IObjectCollection.h create mode 100644 plugins/w7ui/win7api_ITaskbarList3.h diff --git a/plugins/Autorun/autorun.h b/plugins/Autorun/autorun.h new file mode 100644 index 0000000000..4452ef7a4a --- /dev/null +++ b/plugins/Autorun/autorun.h @@ -0,0 +1,14 @@ +#define IDD_OPT_AUTORUN 101 +#define IDC_AUTORUN 102 + +#define SUB_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run" +#define ModuleName "Autorun" + +// Plugin UUID for New plugin loader +// req. 0.7.18+ core +// {EB0465E2-CEEE-11DB-83EF-C1BF55D89593} + +#define MIID_AUTORUN {0xeb0465e2, 0xceee, 0x11db, { 0x83, 0xef, 0xc1, 0xbf, 0x55, 0xd8, 0x95, 0x93}} + +HKEY ROOT_KEY = HKEY_CURRENT_USER; + diff --git a/plugins/Autorun/autorun.rc b/plugins/Autorun/autorun.rc new file mode 100644 index 0000000000..b643834124 --- /dev/null +++ b/plugins/Autorun/autorun.rc @@ -0,0 +1,83 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "autorun.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPT_AUTORUN DIALOGEX 0, 0, 200, 90 +STYLE DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg" +BEGIN + GROUPBOX "Autorun",0,3,3,193,60 + CONTROL "Launch Miranda IM at system startup",IDC_AUTORUN,"Button", + BS_AUTOCHECKBOX | BS_FLAT | WS_TABSTOP,15,20,165,10 + LTEXT "Note: At startup Miranda IM will use current profile", + IDC_STATIC,15,35,165,20,NOT WS_GROUP +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""autorun.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Autorun/autorun.sln b/plugins/Autorun/autorun.sln new file mode 100644 index 0000000000..0c93ceee03 --- /dev/null +++ b/plugins/Autorun/autorun.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autorun", "autorun.vcxproj", "{CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Debug|Win32.ActiveCfg = Debug|Win32 + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Debug|Win32.Build.0 = Debug|Win32 + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Debug|x64.ActiveCfg = Debug|x64 + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Debug|x64.Build.0 = Debug|x64 + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Release|Win32.ActiveCfg = Release|Win32 + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Release|Win32.Build.0 = Release|Win32 + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Release|x64.ActiveCfg = Release|x64 + {CC905A6E-3CCF-DB35-B1BD-0E0D0E5635B9}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/Autorun/autorun.txt b/plugins/Autorun/autorun.txt new file mode 100644 index 0000000000..cec7052075 --- /dev/null +++ b/plugins/Autorun/autorun.txt @@ -0,0 +1,50 @@ +Autorun 0.1.0.0 + +Written by and copyright (c) Sergey V. Gershovich a.k.a. Jazzy$, March 2003 + e-mail: jazzy@arcticsu.ru + +This plugin is a simple way to enable/disable to launch Miranda IM +with system startup. + + +***** DISCLAIMER OF WARRANTY ***** + +This software and the accompanying files are presented "AS IS" and without +warranties whether expressed or implied. Use it at your own risk. + +********************************** + +Usage +------ +Goto: Options->Plugins->Autorun + + +Version history +---------------------- +0.1.0.0: - Preparation for 0.8.x.x plugin loader + MIID_AUTORUN {EB0465E2-CEEE-11DB-83EF-C1BF55D89593} +0.0.0.3: - Decrease size of plugin to 3 kb + - Change image base address to: 0x30040000 + - Miranda IM v0.3alpha build 040303 or higher is required! + - Language strings updated + +0.0.0.2: - Some bugfix with long path & DB-filename + +0.0.0.1: - Initial release + + +Translation +----------- +"Autorun" can be translated with the Miranda IM language files + + +;; == Autorun v0.0.0.3 == + +;Name of plugin +;[Autorun] + +;Options page string +;[Launch Miranda IM at system startup] + +;Options page string +;[Note: At startup Miranda IM will use current profile] \ No newline at end of file diff --git a/plugins/Autorun/autorun.vcxproj b/plugins/Autorun/autorun.vcxproj new file mode 100644 index 0000000000..4c24b4cfc4 --- /dev/null +++ b/plugins/Autorun/autorun.vcxproj @@ -0,0 +1,230 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + + + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + + + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + + + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + true + + + + MultiThreadedDebug + false + Disabled + Level3 + true + EditAndContinue + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;autorun_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\autorun.tlb + true + Win32 + + + _DEBUG;%(PreprocessorDefinitions) + + + + true + true + Windows + 0x30040000 + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(IntDir)$(TargetName).lib + + + + + MultiThreadedDebug + false + Disabled + Level3 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_WINDOWS;_USRDLL;autorun_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\autorun.tlb + true + + + _DEBUG;%(PreprocessorDefinitions) + + + + true + true + Windows + 0x30040000 + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(IntDir)$(TargetName).lib + + + + + MultiThreadedDLL + OnlyExplicitInline + true + true + Full + Level3 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;autorun_EXPORTS; _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Size + true + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\autorun.tlb + false + Win32 + + + NDEBUG;%(PreprocessorDefinitions) + + + + true + Windows + 0x30040000 + kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) + /FILEALIGN:512 /SECTION:.text,ER /IGNORE:4078 /IGNORE:4078 + true + true + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + MultiThreadedDLL + true + true + Full + Level3 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_USRDLL;autorun_EXPORTS; _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Size + true + OnlyExplicitInline + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Release\autorun.tlb + false + + + NDEBUG;%(PreprocessorDefinitions) + + + + true + Windows + 0x30040000 + kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) + /FILEALIGN:512 /SECTION:.text,ER /IGNORE:4078 /IGNORE:4078 + true + true + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/Autorun/autorun.vcxproj.filters b/plugins/Autorun/autorun.vcxproj.filters new file mode 100644 index 0000000000..2977fdc693 --- /dev/null +++ b/plugins/Autorun/autorun.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {08a21636-368d-4feb-8d0d-0a27f237e1a2} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {9e6f20dc-3391-4299-9f74-e91d4f984ad3} + h;hpp;hxx;hm;inl + + + {18fd6180-ebb2-4558-b945-c4dac823f11b} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + + + Source Files + + + \ No newline at end of file diff --git a/plugins/Autorun/main.c b/plugins/Autorun/main.c new file mode 100644 index 0000000000..c5a498afa1 --- /dev/null +++ b/plugins/Autorun/main.c @@ -0,0 +1,165 @@ +#include +#include "autorun.h" + +#include "newpluginapi.h" +#include "m_langpack.h" +#include "m_options.h" +#include "m_database.h" +#pragma hdrstop + + +HINSTANCE hInst; +PLUGINLINK *pluginLink; +HANDLE hHookOptionInit = NULL; + +PLUGININFOEX pluginInfoEx= +{ // about plugin + sizeof(PLUGININFOEX), + "Autorun", + PLUGIN_MAKE_VERSION(0,1,0,1), + "This plugin is a simple way to enable/disable to launch Miranda IM with system startup.", + "Sergey V. Gershovich a.k.a. Jazzy$ (fixed by Wolfram3D)", + "", + "Copyright 2002-2007 Sergey V. Gershovich a.k.a. Jazzy$", + "http://miranda-im.org/download/index.php?action=viewfile&id=285", + 0, 0, + MIID_AUTORUN +}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + // plugin entry point + if (fdwReason == DLL_PROCESS_ATTACH) + { + hInst = hinstDLL; + DisableThreadLibraryCalls(hinstDLL); + } + return TRUE; +} +void GetProfilePath(char *res) +{ + char dbname[MAX_PATH], dbpath[MAX_PATH], exename[MAX_PATH]; + CallService(MS_DB_GETPROFILENAME,sizeof(dbname),(LPARAM)(char*) dbname); + CallService(MS_DB_GETPROFILEPATH,sizeof(dbpath),(LPARAM)(char*) dbpath); + GetModuleFileName(NULL,exename,sizeof(exename)); + lstrcat(dbpath,"\\"); + lstrcpyn(dbpath+lstrlen(dbpath),dbname,lstrlen(dbname)-3); + strcat(dbpath, "\\"); + strcat(dbpath, dbname); // path + profile name + wsprintf(res,"\"%s\" \"%s\"",exename, dbpath); +} + +static void SetAutorun(BOOL autorun) +{ + HKEY hKey; + DWORD dw; + switch (autorun) + { + case TRUE: + if (RegCreateKeyEx(ROOT_KEY, SUB_KEY,0,NULL,0,KEY_CREATE_SUB_KEY|KEY_SET_VALUE,NULL,&hKey,&dw) == ERROR_SUCCESS) + { + char result[MAX_PATH]; + GetProfilePath (result); + RegSetValueEx(hKey,"MirandaIM",0,REG_SZ,result,lstrlen(result)+1); + RegCloseKey(hKey); + break; + } + case FALSE: + if (RegOpenKey(ROOT_KEY,SUB_KEY,&hKey) == ERROR_SUCCESS) + { + RegDeleteValue(hKey,"MirandaIM"); + RegCloseKey(hKey); + break; + } + } +} + + +static BOOL CmpCurrentAndRegistry() +{ + HKEY hKey; + DWORD dwBufLen = MAX_PATH; + char result[MAX_PATH], dbpath[MAX_PATH]; + GetProfilePath (result); + + if (RegOpenKeyEx(ROOT_KEY, SUB_KEY, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) + { + if (RegQueryValueEx(hKey,"MirandaIM",NULL,NULL,(LPBYTE)dbpath,&dwBufLen) == ERROR_SUCCESS) + { + return (lstrcmpi(result,dbpath) == 0 ? TRUE : FALSE); + } + else + return FALSE; + } + else + return FALSE; +} + +static INT_PTR CALLBACK DlgProcAutorunOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + CheckDlgButton(hwndDlg,IDC_AUTORUN,CmpCurrentAndRegistry()); // Check chekbox if Registry value exists + return TRUE; + case WM_COMMAND: + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); // Send message to activate "Apply" button + return TRUE; + break; + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: // if "Apply" pressed then... + SetAutorun(IsDlgButtonChecked(hwndDlg,IDC_AUTORUN)); //Save changes to registry; + return TRUE; + } + break; + } + break; + } + return FALSE; +} + + +static int AutorunOptInitialise(WPARAM wParam,LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + odp.cbSize=sizeof(odp); + odp.position=100100000; + odp.hInstance=hInst; + odp.pszTemplate=MAKEINTRESOURCE(IDD_OPT_AUTORUN); + odp.pszTitle=Translate(ModuleName); + odp.pszGroup=Translate("Plugins"); + odp.pfnDlgProc=DlgProcAutorunOpts; + odp.flags=ODPF_BOLDGROUPS; + CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp); + return 0; +} +//========================================================================== +__declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfoEx; +} + +static const MUUID interfaces[] = {MIID_AUTORUN, MIID_LAST}; +__declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +int __declspec(dllexport) Load(PLUGINLINK *link) +{ + pluginLink = link; + hHookOptionInit = HookEvent(ME_OPT_INITIALISE,AutorunOptInitialise); + return 0; +} + +int __declspec(dllexport) Unload(void) +{ + if (hHookOptionInit) + UnhookEvent(hHookOptionInit); + return 0; +} \ No newline at end of file diff --git a/plugins/Autorun/resource.h b/plugins/Autorun/resource.h new file mode 100644 index 0000000000..c5b53f192c --- /dev/null +++ b/plugins/Autorun/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by autorun.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/Boltun/Boltun.rc b/plugins/Boltun/Boltun.rc new file mode 100644 index 0000000000..4ae46eea47 --- /dev/null +++ b/plugins/Boltun/Boltun.rc @@ -0,0 +1,155 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Canada) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAINBOLTUN ICON "res\\boltun.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// SMILES +// + +IDR_SMILES SMILES "res\\smiles.dat" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MAIN DIALOGEX 0, 0, 307, 231 +STYLE DS_SETFONT | WS_CHILD | WS_BORDER +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Boltun",IDC_PLUGINRM,5,2,297,222 + CONTROL "Boltun Autochat everybody",IDC_EVERYBODY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,20,230,10 + CONTROL "Boltun Autochat everybody not in contact list",IDC_NOTINLIST, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,33,230,10 + CONTROL "Boltun Autochat everybody while away",IDC_AUTOAWAY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,46,230,10 + CONTROL "Warn contacts Boltun is chatting",IDC_WARN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,59,230,10 + CONTROL "Mark replied messages as read",IDC_MARKREAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,72,230,10 + EDITTEXT IDC_WAITTIME,26,161,24,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "sec",IDC_LSEC,53,161,72,8 + EDITTEXT IDC_WARNTXT,17,97,272,31,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL + GROUPBOX "Warning text",IDC_LWARN,12,85,283,50 + GROUPBOX "Time before the answer",IDC_LWAITTIME,12,138,283,72 + CONTROL "Typing time depends on message length (in chars)",IDC_PAUSEDEPENDS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,178,270,11 + CONTROL "Typing and thinking time can be much longer",IDC_PAUSERANDOM, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,193,270,10 + LTEXT "Typing time (for a message of 4 words):",IDC_STATIC,21,148,145,8 + LTEXT "Thinking time:",IDC_STATIC,173,148,111,8 + EDITTEXT IDC_THINKTIME,177,161,24,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "sec",IDC_LSEC2,205,161,72,8 +END + +IDD_ENGINE DIALOGEX 0, 0, 307, 231 +STYLE DS_SETFONT | WS_CHILD | WS_BORDER +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Engine",IDC_PLUGINRM,5,48,297,174 + EDITTEXT IDC_MINDFILE,12,19,210,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "...",IDC_BTNPATH,226,18,16,16 + GROUPBOX "Base of remarks",IDC_TXTREPLICPATH,5,6,297,36 + PUSHBUTTON "Reload",IDC_BTNRELOAD,246,18,52,16 + CONTROL "Stay silent, if have no good aswers",IDC_ENGINE_SILENT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,62,283,10 + CONTROL "Start answers with a lowercase letter",IDC_ENGINE_LOWERCASE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,94,282,10 + CONTROL "Don't use ""I don't understand""-like answers",IDC_ENGINE_UNDERSTAND_ALWAYS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,27,78,248,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_MAIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 300 + TOPMARGIN, 7 + BOTTOMMARGIN, 224 + END + + IDD_ENGINE, DIALOG + BEGIN + RIGHTMARGIN, 306 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (Canada) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Boltun/Boltun2.gif b/plugins/Boltun/Boltun2.gif new file mode 100644 index 0000000000..fc2b4a93df Binary files /dev/null and b/plugins/Boltun/Boltun2.gif differ diff --git a/plugins/Boltun/Boltun_10.sln b/plugins/Boltun/Boltun_10.sln new file mode 100644 index 0000000000..9f1aa3541d --- /dev/null +++ b/plugins/Boltun/Boltun_10.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Boltun_10", "Boltun_10.vcxproj", "{98DF7761-41D7-4C5C-9FFE-E5CCB3997783}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Win32 = Debug Unicode|Win32 + Release Unicode|Win32 = Release Unicode|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {98DF7761-41D7-4C5C-9FFE-E5CCB3997783}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {98DF7761-41D7-4C5C-9FFE-E5CCB3997783}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {98DF7761-41D7-4C5C-9FFE-E5CCB3997783}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {98DF7761-41D7-4C5C-9FFE-E5CCB3997783}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/Boltun/Boltun_10.vcxproj b/plugins/Boltun/Boltun_10.vcxproj new file mode 100644 index 0000000000..0f05bca890 --- /dev/null +++ b/plugins/Boltun/Boltun_10.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug Unicode + Win32 + + + Release Unicode + Win32 + + + + {98DF7761-41D7-4C5C-9FFE-E5CCB3997783} + Boltun + boltun + + + + DynamicLibrary + false + Unicode + + + DynamicLibrary + false + Unicode + true + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + false + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(ProjectName)w + $(ProjectName)w + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/Boltun.tlb + + + + + Full + OnlyExplicitInline + true + Size + true + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + NDEBUG;BOLTUN_EXPORTS;WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_UNICODE;UNICODE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Level3 + true + ProgramDatabase + 4996;%(DisableSpecificWarnings) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + %(AdditionalLibraryDirectories) + true + $(IntDir)$(TargetName).lib + MachineX86 + true + true + UseLinkTimeCodeGeneration + + + true + + + + + copy Engine\boltun.mindw "$(SolutionDir)$(Configuration)\Plugins" + + $(OutDir)boltun.mindw;%(Outputs) + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/Boltun.tlb + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + _DEBUG;WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOLTUN_EXPORTS;_UNICODE;UNICODE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Level3 + true + EditAndContinue + 4996;%(DisableSpecificWarnings) + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + odbc32.lib;odbccp32.lib;comctl32.lib;%(AdditionalDependencies) + true + %(AdditionalLibraryDirectories) + true + $(IntDir)$(TargetName).lib + MachineX86 + + + true + + + + + + ../include;%(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + ../include;%(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + + + + + + + + Full + AnySuitable + true + Speed + true + true + true + Default + ProgramDatabase + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + \ No newline at end of file diff --git a/plugins/Boltun/Boltun_10.vcxproj.filters b/plugins/Boltun/Boltun_10.vcxproj.filters new file mode 100644 index 0000000000..e025146d37 --- /dev/null +++ b/plugins/Boltun/Boltun_10.vcxproj.filters @@ -0,0 +1,110 @@ + + + + + {053e819b-1bb3-488b-8dbd-f6b29640c30c} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {e94debaf-39e5-4d66-95b0-b02f301c140c} + + + {db6f678c-e69c-4576-819a-360e80ffc84c} + h;hpp;hxx;hm;inl + + + {614d736c-849c-4a07-ba4e-a6c9b895154b} + + + {c04447a2-5567-4425-92b8-a4a1267e7e32} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\Enigne + + + Source Files\Enigne + + + Source Files\Enigne + + + Source Files\Enigne + + + Source Files\Enigne + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\Engine + + + Header Files\Engine + + + Header Files\Engine + + + Header Files\Engine + + + Header Files\Engine + + + Header Files\Engine + + + Header Files\Engine + + + Header Files\Engine + + + Header Files\Engine + + + + + Resource Files + + + Resource Files + + + + + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/plugins/Boltun/Engine/COPYING.txt b/plugins/Boltun/Engine/COPYING.txt new file mode 100644 index 0000000000..82fa1daad4 --- /dev/null +++ b/plugins/Boltun/Engine/COPYING.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/plugins/Boltun/Engine/CriticalSection.h b/plugins/Boltun/Engine/CriticalSection.h new file mode 100644 index 0000000000..59bc91beb9 --- /dev/null +++ b/plugins/Boltun/Engine/CriticalSection.h @@ -0,0 +1,56 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef CriticalSectionH +#define CriticalSectionH + +#include + +class CriticalSection +{ + CRITICAL_SECTION csQueue; +public: + inline CriticalSection() + { + InitializeCriticalSection(&csQueue); + } + + inline ~CriticalSection() + { + DeleteCriticalSection(&csQueue); + } + + inline void Enter() + { + EnterCriticalSection(&csQueue); + } + + inline void Leave() + { + LeaveCriticalSection(&csQueue); + } + + inline bool TryEnter() + { + return TryEnterCriticalSection(&csQueue) != 0; + } +}; + +#endif /* CriticalSectionH */ \ No newline at end of file diff --git a/plugins/Boltun/Engine/Mind.cpp b/plugins/Boltun/Engine/Mind.cpp new file mode 100644 index 0000000000..6260177095 --- /dev/null +++ b/plugins/Boltun/Engine/Mind.cpp @@ -0,0 +1,448 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#include "Mind.h" +#include +#include +#include "tstring.h" +#include "assert.h" + +#include + +#ifdef UNICODE +#include "MyCodeCvt.h" +#endif + +using namespace std; + +typedef vector string_vec; +typedef multimap string_mmap; + +Mind::Mind() +{ + data = new MindData(); + data->referenceCount = 1; + data->maxSmileLen = 0; +} + +Mind::~Mind() +{ + if (--data->referenceCount == 0) + delete data; +} + +Mind::Mind(const Mind& mind) +{ + mind.data->referenceCount++; + data = mind.data; +} + +const MindData *Mind::GetData() const +{ + return data; +} + +Mind& Mind::operator= (const Mind& mind) +{ + if (--data->referenceCount == 0) + delete data; + mind.data->referenceCount++; + data = mind.data; + return *this; +} + +inline void format(tstring& s) +{ + int pos = s.length() - 1; + if (s[pos] == _T('\r')) + s.resize(pos); +} + +void toLowerStr(TCHAR* ch) +{ + CharLower(ch); +} + +vector Mind::Parse(tstring s) +{ + int len = s.length() - 1; + vector res; + while (len != -1 && _istspace(s[len])) + len--; + if (len < 0) + return res; + s.resize(len); + int it = 0; + while (it != len) + { + while (it != len && _istspace(s[it])) + it++; + if (it == len) + break; + int start = it; + while (it != len && !_istspace(s[it])) + it++; + res.push_back(s.substr(start, it - start)); + } + return res; +} + +void Mind::Load(tstring filename) +{ + basic_ifstream > file; + setlocale(LC_ALL, ""); +#ifdef UNICODE + locale ulocale(locale(), new MyCodeCvt); + file.imbue(ulocale); +#endif + file.open(filename.c_str(), ios_base::in | ios_base::binary); + tstring s1, st; + TCHAR *c, *co; + size_t count; + int error = 0; + int line = 1; +#ifdef UNICODE + bool start = true; +#endif + try + { + while (file.good()) + { + getline(file, st); + if (st.empty()) + break; + line++; +#ifdef UNICODE + if (start) + { + if (st[0] == 65279) + { + st.erase(0, 1); + fileTypeMark = true; + } + else + fileTypeMark = false; + start = false; + } +#endif + format(st); + count = st.length(); + c = co = new TCHAR[count+1]; + _tcscpy(c, st.c_str()); + size_t pos = 0; + while (pos < count && _istspace(*c)) + { + ++pos; + ++c; + } + count -= pos; + if (count > 2) + { + switch (*c) + { + case '(': + if (c[count - 1] != ')') + abort(); + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + toLowerStr(c); + { + WordsList l(c); + if (!l.IsEmpty()) + if (l.IsQuestion()) + data->qkeywords.insert(make_pair(l, s1)); + else + data->keywords.insert(make_pair(l, s1)); + } + break; + case '{': + if (c[count - 1] != '}') + abort(); + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + toLowerStr(c); + { + WordsList l(c); + if (!l.IsEmpty()) + if (l.IsQuestion()) + data->qspecialEscapes.insert(make_pair(l, s1)); + else + data->specialEscapes.insert(make_pair(l, s1)); + } + break; + case '[': + if (c[count - 1] != ']') + throw error; + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + toLowerStr(c); + data->widelyUsed.insert(make_pair(c, s1)); + break; + case '<': + if (c[count - 1] != '>') + throw error; + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 2; + c[count] = '\0'; + if (_tcscmp(c,_T("QUESTION")) == 0) + { + toLowerStr(c); + data->question.insert(s1); + } + else + if (_tcscmp(c,_T("IGNORED")) == 0) + { + toLowerStr(c); + data->special.insert(s1); + } + else + if (_tcscmp(c,_T("ESCAPE")) == 0) + { + data->escape.push_back(s1); + } + else + if (_tcscmp(c,_T("FAILURE")) == 0) + { + data->failure.push_back(s1); + } + else + if (_tcscmp(c,_T("REPEAT")) == 0) + { + data->repeats.push_back(s1); + } + else + { + if (_tcscmp(c,_T("INITIAL")) != 0) + throw error; + data->initial.push_back(s1); + } + break; + case '@': + { + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + ++c; + count -= 1; + toLowerStr(c); + tstring sc(c); + int count1 = s1.length(); + TCHAR *c = new TCHAR[count1 + 1]; + _tcscpy(c, s1.c_str()); + CharLower(c); + s1 = c; + delete c; + vector strs = Parse(s1); + data->raliases.insert(make_pair(sc, strs)); + for (vector::const_iterator it = strs.begin(); it != strs.end(); it++) + data->aliases.insert(make_pair(*it, sc)); + } + break; + default: + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + toLowerStr(c); + data->study.insert(make_pair(c, s1)); + } + } + else + if (count) + { + if (file.eof()) + throw error; + getline(file, s1); + line++; + format(s1); + data->study.insert(make_pair(c, s1)); + } + } + if (!file.eof()) + { + throw error; + } + delete co; + } + catch(...) + { + throw CorruptedMind(line); + delete co; + } +} + +void Mind::Save(tstring filename) const +{ + basic_ofstream > file; +#ifdef UNICODE + locale ulocale(locale(), new MyCodeCvt); + file.imbue(ulocale); +#endif + file.open(filename.c_str(), ios_base::out | ios_base::binary); +#ifdef UNICODE + if (fileTypeMark) + file << TCHAR(65279); +#endif + for (string_mmap::iterator it = data->study.begin(); it != data->study.end(); it++) + { + file << (*it).first << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->keywords.begin(); it != data->keywords.end(); it++) + { + file << _T(" (") << (tstring)(*it).first << _T(")") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->qkeywords.begin(); it != data->qkeywords.end(); it++) + { + file << _T(" (") << (tstring)(*it).first << _T(")") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->specialEscapes.begin(); it != data->specialEscapes.end(); it++) + { + file << _T(" {") << (tstring)(*it).first << _T("}") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (multimap::iterator it = data->qspecialEscapes.begin(); it != data->qspecialEscapes.end(); it++) + { + file << _T(" {") << (tstring)(*it).first << _T("}") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (string_mmap::iterator it = data->widelyUsed.begin(); it != data->widelyUsed.end(); it++) + { + file << _T(" [") << (*it).first << _T("]") << _T('\r') << endl; + file << (*it).second << _T('\r') << endl; + } + for (set::iterator it = data->question.begin(); it != data->question.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (set::iterator it = data->special.begin(); it != data->special.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->escape.begin(); it != data->escape.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->initial.begin(); it != data->initial.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->failure.begin(); it != data->failure.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (string_vec::iterator it = data->repeats.begin(); it != data->repeats.end(); it++) + { + file << _T(" ") << _T('\r') << endl; + file << (*it) << _T('\r') << endl; + } + for (map>::const_iterator it = data->raliases.begin(); it != data->raliases.end(); it++) + { + tstring s; + const vector& v = (*it).second; + bool first = true; + for (vector::const_iterator it1 = v.begin(); it1 != v.end(); it1++) + { + if (first) + { + first = false; + s = *it1; + } + else + { + s += _T(" ") + *it1; + } + } + file << _T('@') << (*it).first << _T('\r') << endl; + file << s << _T('\r') << endl; + } +} + +void Mind::LoadSmiles(tstring filename) +{ + basic_ifstream > file; + file.open(filename.c_str()); + data->smiles.clear(); + tstring s; + unsigned int l = 0; + while (!file.eof()) + { + getline(file, s); + if (s.length() > l) + l = s.length(); + data->smiles.insert(s); + } + data->maxSmileLen = l; +} + +void Mind::LoadSmiles(void *smiles, size_t size) +{ + data->smiles.clear(); + TCHAR* buf = (TCHAR*)smiles; + unsigned l = 0; + TCHAR* end = buf + size; + while (buf != end) + { + TCHAR *lend = buf; + while (lend != end && *lend != _T('\r')) + lend++; + tstring s(buf, lend - buf); + if ((unsigned)(lend - buf) > l) + l = s.length(); + data->smiles.insert(s); + if (lend == end) + break; + buf = lend + 2; + } + data->maxSmileLen = l; +} diff --git a/plugins/Boltun/Engine/Mind.h b/plugins/Boltun/Engine/Mind.h new file mode 100644 index 0000000000..ecf3f5d199 --- /dev/null +++ b/plugins/Boltun/Engine/Mind.h @@ -0,0 +1,89 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef MindH +#define MindH + +#include +#include +#include +#include +#include "WordsList.h" +#include +#include "tstring.h" + + +class Mind; + +typedef struct +{ + friend class Mind; + std::vector initial; + std::set question; + std::set special; + std::vector escape; + std::vector failure; + std::vector repeats; + unsigned int maxSmileLen; + std::set smiles; + std::multimap keywords; + std::multimap qkeywords; + std::multimap widelyUsed; + std::multimap specialEscapes; + std::multimap qspecialEscapes; + std::multimap study; + std::map aliases; + std::map> raliases; +private: + int referenceCount; +} MindData; + +class Mind +{ +private: + MindData *data; +#ifdef UNICODE + bool fileTypeMark; +#endif + std::vector Parse(tstring s); +public: + Mind(); + ~Mind(); + Mind(const Mind& mind); + Mind& operator= (const Mind& mind); + + class CorruptedMind + { + public: + int line; + CorruptedMind(int aline) + : line(aline) + { + }; + }; + + const MindData *GetData() const; + void Load(tstring filename); + void Save(tstring filename) const; + void LoadSmiles(tstring filename); + void LoadSmiles(void* smiles, size_t size); +}; + +#endif diff --git a/plugins/Boltun/Engine/MyCodeCvt.cpp b/plugins/Boltun/Engine/MyCodeCvt.cpp new file mode 100644 index 0000000000..71e056291a --- /dev/null +++ b/plugins/Boltun/Engine/MyCodeCvt.cpp @@ -0,0 +1,85 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifdef UNICODE + +#include "MyCodeCvt.h" + +using namespace std; + +MyCodeCvt::MyCodeCvt(size_t _R) + : MyCodeCvtBase(_R) +{ +} + +MyCodeCvt::result MyCodeCvt::do_in(_St& _State , + const _To* _F1, const _To* _L1, const _To*& _Mid1, + _E* F2, _E* _L2, _E*& _Mid2) const +{ + return noconv; +} + +#ifdef MSVC +MyCodeCvt::result MyCodeCvt::do_out(_St& _State, + const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _E* _L2, _To*& _Mid2) const +#else +MyCodeCvt::result MyCodeCvt::do_out(_St& _State, + const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _To* _L2, _To*& _Mid2) const +#endif +{ + return noconv; +} + +MyCodeCvt::result MyCodeCvt::do_unshift( _St& _State, + _To* _F2, _To* _L2, _To*& _Mid2) const +{ + return noconv; +} + +#ifdef MSVC +int MyCodeCvt::do_length(_St& _State, const _To* _F1, + const _To* _L1, size_t _N2) const _THROW0() +#else +int MyCodeCvt::do_length(const _St& _State, const _To* _F1, + const _To* _L1, size_t _N2) const _THROW0() +#endif + +{ + return (_N2 < (size_t)(_L1 - _F1)) ? _N2 : _L1 - _F1; +} + +bool MyCodeCvt::do_always_noconv() const _THROW0() +{ + return true; +} + +int MyCodeCvt::do_max_length() const _THROW0() +{ + return 2; +} + +int MyCodeCvt::do_encoding() const _THROW0() +{ + return 2; +} + +#endif \ No newline at end of file diff --git a/plugins/Boltun/Engine/MyCodeCvt.h b/plugins/Boltun/Engine/MyCodeCvt.h new file mode 100644 index 0000000000..b4508c66de --- /dev/null +++ b/plugins/Boltun/Engine/MyCodeCvt.h @@ -0,0 +1,59 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef MYCODECVT_H +#define MYCODECVT_H + +#include +#include +#include + +typedef std::codecvt MyCodeCvtBase; + +class MyCodeCvt + : public MyCodeCvtBase +{ +public: + typedef wchar_t _E; + typedef char _To; + typedef std::mbstate_t _St; + explicit MyCodeCvt( size_t _R=0 ); +protected: + virtual result do_in(_St& _State, const _To* _F1, const _To* _L1, const _To*& _Mid1, + _E* F2 , _E* _L2 , _E*& _Mid2) const; +#ifdef MSVC + virtual result do_out(_St& _State, const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _E* _L2 , _To*& _Mid2) const; +#else + virtual result do_out(_St& _State, const _E* _F1, const _E* _L1, const _E*& _Mid1, + _To* F2, _To* _L2 , _To*& _Mid2) const; +#endif + virtual result do_unshift(_St& _State, _To* _F2, _To* _L2, _To*& _Mid2) const; +#ifdef MSVC + virtual int do_length(_St& _State, const _To* _F1, const _To* _L1, size_t _N2) const _THROW0(); +#else + virtual int do_length(const _St& _State, const _To* _F1, const _To* _L1, size_t _N2) const _THROW0(); +#endif + virtual bool do_always_noconv() const _THROW0(); + virtual int do_max_length() const _THROW0(); + virtual int do_encoding() const _THROW0(); +} ; + +#endif /* MYCODECVT_H */ \ No newline at end of file diff --git a/plugins/Boltun/Engine/PerContactData.h b/plugins/Boltun/Engine/PerContactData.h new file mode 100644 index 0000000000..14b17784b9 --- /dev/null +++ b/plugins/Boltun/Engine/PerContactData.h @@ -0,0 +1,173 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef PerContactDataH +#define PerContactDataH + +#include +#include +#include + +#include "CriticalSection.h" + +static std::map perContactDataObjects; + +template +class PerContactData +{ + template + struct InternalData + { + CriticalSection lock; + Data *data; + time_t time; + inline InternalData(const Source& src) + :time(0) + { + data = new Data(src); + } + + inline InternalData() + :data(NULL) + { + assert(false); + } + + inline ~InternalData() + { + delete data; + } + }; + CriticalSection mapLock; + unsigned timerID; + std::map* > datas; + typedef typename std::map* >::iterator mapIt; + const Source& source; + void CleanupData(); + template + friend VOID CALLBACK RunTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); +public: + PerContactData(const Source& src); + ~PerContactData(); + Data* GetData(ContactHandle Contact); + void PutData(ContactHandle Contact); +}; + +template +PerContactData::PerContactData(const Source& src) + :source(src), timerID(0) +{ +} + +template +PerContactData::~PerContactData() +{ + mapLock.Enter(); + if (timerID) + { + KillTimer(NULL, timerID); + perContactDataObjects.erase(timerID); + } + while (!datas.empty()) + { + while (!(*datas.begin()).second->lock.TryEnter()) + { + mapLock.Leave(); + Sleep(10); + mapLock.Enter(); + } + //Now we know exactly that no-one onws a contact lock + InternalData* data = (*datas.begin()).second; + data->lock.Leave(); + delete data; + datas.erase(datas.begin()); + } + mapLock.Leave(); +} + +template +Data* PerContactData::GetData(ContactHandle Contact) +{ + mapLock.Enter(); + mapIt it; + if ((it = datas.find(Contact)) == datas.end()) + it = datas.insert(make_pair(Contact, new InternalData(source))).first; + (*it).second->lock.Enter(); + (*it).second->time = 0; + Data* data = (*it).second->data; + mapLock.Leave(); + return data; +} + +template +void PerContactData::PutData(ContactHandle Contact) +{ + mapLock.Enter(); + datas[Contact]->lock.Leave(); + ::time(&(datas[Contact]->time)); + if (!timerID) + { + timerID = SetTimer(NULL, 0, 30000, RunTimerProc); + assert(timerID); + perContactDataObjects[timerID] = this; + } + mapLock.Leave(); +} + +template +void PerContactData::CleanupData() +{ + mapLock.Enter(); + time_t now; + time(&now); + for (mapIt it = datas.begin(); it != datas.end(); ) + { + if ((*it).second->time) //it's being in use + { + int diff = (int)difftime(now, (*it).second->time); + if (diff >= 30*60) //half of an hour + { + mapIt tmp = it; + it++; + delete (*tmp).second; + datas.erase(tmp); + } + else + it++; + } + else + it++; + } + if (timerID && datas.empty()) //timerID may become NULL before locking, so should check + { + KillTimer(NULL, timerID); + perContactDataObjects.erase(timerID); + } + mapLock.Leave(); +} + +template +VOID CALLBACK RunTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + PerContactData* val = (PerContactData*)perContactDataObjects[idEvent]; + val->CleanupData(); +} + +#endif /* PerContactDataH */ \ No newline at end of file diff --git a/plugins/Boltun/Engine/TalkEngine.cpp b/plugins/Boltun/Engine/TalkEngine.cpp new file mode 100644 index 0000000000..a9625dffd2 --- /dev/null +++ b/plugins/Boltun/Engine/TalkEngine.cpp @@ -0,0 +1,609 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#include "TalkEngine.h" +#include +#include + +#ifdef _DEBUG + +//#define DEBUG_PREFIXES +//#define DEBUG_SHOW_LEVEL +//#define DEBUG_SHOW_VARIANTS +//#define DEBUG_SHOW_SOLUTION_REASON + +#endif + +//Enabling next define will make a bot more stupid: +//#define EXCLUDE_SPECIAL_WORDS + +#ifdef DEBUG_SHOW_VARIANTS +extern void AddBotMessage(tstring s); +#endif + +using namespace std; + +void TalkBot::UpdateStartChar(tstring& str) +{ + if (!makeLowercase) + return; + size_t l = str.length(); + if (l) + { + //Answers starting with ' ' must remain unchanged. + if (str[0] == _T(' ')) + { + str = str.substr(1); + return; + } + for (size_t i = 0; i < l; i++) + { + TCHAR cl = (TCHAR)CharLower((LPTSTR)(void*)(long)str[i]); + TCHAR cu = (TCHAR)CharUpper((LPTSTR)(void*)(long)str[i]); + if (i != l - 1) + { + //Do not react to BLONDE ANSWERS + TCHAR ncl = (TCHAR)CharLower((LPTSTR)(void*)(long)str[i + 1]); + TCHAR ncu = (TCHAR)CharUpper((LPTSTR)(void*)(long)str[i + 1]); + if (ncl != ncu && str[i + 1] == ncu) + break; + } + if (cl != cu) + { + str[i] = cl; + break; + } + } + } +} + +TalkBot::TalkBot(const Mind& goodMind) + :mind(goodMind), beSilent(false), makeLowercase(false), + understandAlways(false) +{ + contactDatas = new PerContactData(mind); +} + +TalkBot::~TalkBot() +{ + delete contactDatas; +} + +tstring TalkBot::GetInitMessage(void* contact) +{ + ContactData* d = contactDatas->GetData(contact); + tstring s = d->initial.GetString(); + contactDatas->PutData(contact); + return s; +} + +tstring TalkBot::ReplaceAliases(const tstring &message) +{ + const TCHAR dividers[] = _T(" \t\n\r,./?\\|;:'\"~!#^&*()_-+=[{]}\1"); + tstring sentence = message; + tstring result; + int len = sentence.length(); + vector words; + map sm; + //Find smiles + for (size_t i = 0; i < sentence.length() - 1; i++) + { + unsigned max = sentence.length() - i; + if (max > mind.GetData()->maxSmileLen) + max = mind.GetData()->maxSmileLen; + for (unsigned j = max; j > 0; j--) + { + tstring item = sentence.substr(i, j); + if (mind.GetData()->smiles.find(item) + != mind.GetData()->smiles.end()) + { + sm[i] = item; + sentence.replace(i, j, _T("\1")); + break; + } + } + } + len = sentence.length(); + bool hadQuestionSigns = false; + int it = 0; + while (it != len) + { + while (it != len && _tcschr(dividers, sentence[it])) + { + if (sentence[it] == _T('?')) + hadQuestionSigns = true; + map::iterator smit; + if (sentence[it] == '\1') + { + smit = sm.find(it); + result.append((*smit).second); + } + else + result.push_back(sentence[it]); + it++; + } + if (it == len) + break; + int start = it; + while (true) + { + while (it != len && !_tcschr(dividers, sentence[it])) + it++; + if (it == len || sentence[it] != _T('-')) + break; + //If we have-a-word-with-minus, we shouldn't split it + if (_tcschr(dividers, sentence[it + 1])) + break; + it += 2; + } + tstring str = sentence.substr(start, it - start); + map::const_iterator al = mind.GetData()->aliases.find(str); + if (al != mind.GetData()->aliases.end()) + result.append((*al).second); + else + result.append(str); + } + return result; +} + +tstring TalkBot::AllReplies(const tstring &incomingMessage, ContactData* contactData, Level &maxValue, std::multimap &mm) +{ + tstring res; + //Part 1 + if (FindExact(contactData, incomingMessage, mind.GetData()->widelyUsed, res)) //widelyUsed + { + return res; + } + //Part 2 + if (FindExact(contactData, incomingMessage, mind.GetData()->study, res)) //study + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE, _T("(study_all) ")+res)); +#else + mm.insert(make_pair(LOOKSLIKE, res)); +#endif + maxValue = LOOKSLIKE; + } + //Part 3 + vector sentences; + SplitSectences(incomingMessage, sentences); + ValueChooser<> ch(sentences, true); //Using random order of sentences. + while ((res = ch.GetString()) != _T("")) + { + //Part 4 + if (FindExact(contactData, res, mind.GetData()->widelyUsed, res)) //widelyUsed + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(BEST, _T("(widelyused_sent) ")+res)); +#else + mm.insert(make_pair(BEST, res)); +#endif + if (maxValue > BEST) + maxValue = BEST; + } + //Part 5 + if (FindExact(contactData, res, mind.GetData()->study, res)) //study + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE, _T("(study_sent) ")+res)); +#else + mm.insert(make_pair(LOOKSLIKE, res)); +#endif + if (maxValue > LOOKSLIKE) + maxValue = LOOKSLIKE; + } + //Part 6 + vector keywords, otherwords; + bool isQuestion; + SplitAndSortWords(res, keywords, otherwords, isQuestion); + //Part 7, 8 + res = _T(""); + FindByKeywords(contactData, keywords, res/*, ures*/, isQuestion); //keywords + if (res != _T("")) + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE, _T("(keywords) ")+res)); +#else + mm.insert(make_pair(LOOKSLIKE, res)); +#endif + if (maxValue > LOOKSLIKE) + maxValue = LOOKSLIKE; + } +/* if (ures != _T("")) + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(LOOKSLIKE2, _T("(keywords_unstrict) ")+ures)); +#else + mm.insert(make_pair(LOOKSLIKE2, ures)); +#endif + if (maxValue > LOOKSLIKE2) + maxValue = LOOKSLIKE2; + }*/ + //Part 9 + if (FindByOthers(contactData, otherwords, res, isQuestion)) //specialEscapes + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(BAD, _T("(otherwords) ")+res)); +#else + mm.insert(make_pair(BAD, res)); +#endif + if (maxValue > BAD) + maxValue = BAD; + } + } + if (!beSilent) + { + //Part 10 + if (FindAny(contactData->escape, res)) //escape + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(FAIL, _T("(escape) ") + res)); +#else + mm.insert(make_pair(FAIL, res)); +#endif + if (maxValue > FAIL) + maxValue = FAIL; + } + //Part 11 + if (!understandAlways && FindAny(contactData->failure, res)) //failure + { +#ifdef DEBUG_PREFIXES + mm.insert(make_pair(FAIL, _T("(failure) ") + res)); +#else + mm.insert(make_pair(FAIL, res)); +#endif + if (maxValue > FAIL) + maxValue = FAIL; + } + } + return tstring(); +} + +TalkBot::MessageInfo* TalkBot::Reply(void* contact, tstring incomingMessage, bool saveChoice) +{ + TCHAR* str = new TCHAR[incomingMessage.length()+1]; + _tcscpy(str, incomingMessage.c_str()); + CharLower(str); + incomingMessage = str; + delete str; + ContactData* contactData = contactDatas->GetData(contact); + + if (incomingMessage == contactData->lastMessage && GetTickCount() < contactData->lastMessageTime + 30*60*1000) + { + MessageInfo *info; + //only 2-3 repeats + if (contactData->repeatCount < 2 || contactData->repeatCount == 2 && (rand() % 2)) + { + const vector& v = mind.GetData()->repeats; + tstring res = v[rand() % v.size()]; +#ifdef DEBUG_PREFIXES + info = new MessageInfo(incomingMessage, _T("(repeat_norm) ") + res); +#else + info = new MessageInfo(incomingMessage, res); +#endif + } + else +#ifdef DEBUG_PREFIXES + info = new MessageInfo(incomingMessage, _T("(repeat_silence)")); +#else + info = new MessageInfo(incomingMessage, _T("")); +#endif + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; + } + + multimap mm; + Level maxValue = NOTHING; + + tstring res = AllReplies(incomingMessage, contactData, maxValue, mm); + if (!res.empty()) + { + UpdateStartChar(res); +#ifdef DEBUG_PREFIXES + MessageInfo *info = new MessageInfo(incomingMessage, _T("(widelyused_all) ") + res); +#else + MessageInfo *info = new MessageInfo(incomingMessage, res); +#endif + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; + } + + incomingMessage = ReplaceAliases(incomingMessage); + + res = AllReplies(incomingMessage, contactData, maxValue, mm); + if (!res.empty()) + { + UpdateStartChar(res); +#ifdef DEBUG_PREFIXES + MessageInfo *info = new MessageInfo(incomingMessage, _T("(widelyused_all) ") + res); +#else + MessageInfo *info = new MessageInfo(incomingMessage, res); +#endif + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; + } + + //Also does Part 12 + tstring final = ChooseResult(contactData, maxValue, mm); + MessageInfo *info = new MessageInfo(incomingMessage, final); + UpdateStartChar(final); + if (saveChoice) + RecordAnswer(contactData, *info); + contactDatas->PutData(contact); + return info; +} + +bool TalkBot::FindExact(ContactData* contactData, const tstring &incomingMessage, + const multimap& map, tstring& res) +{ + int max = map.count(incomingMessage); + if (!max) + { + TCHAR c = incomingMessage[incomingMessage.length() - 1]; + if (c != _T('?') && c != _T('.') && c != _T('!')) + return FindExact(contactData, incomingMessage + _T('.'), map, res); + return false; + } + pair range = map.equal_range(incomingMessage); + for (mm_cit it = range.first; it != range.second; it++) + contactData->chooser.AddChoice((*it).second); + res = contactData->chooser.Choose(); + return true; +} + +void TalkBot::AnswerGiven(void* contact, const TalkBot::MessageInfo& info) +{ + ContactData* contactData = contactDatas->GetData(contact); + RecordAnswer(contactData, info); + contactDatas->PutData(contact); +} + +void TalkBot::RecordAnswer(ContactData *contactData, const TalkBot::MessageInfo& info) +{ + contactData->chooser.SaveChoice(info.Answer); + if (contactData->lastMessage == info.Question) + contactData->repeatCount++; + else + contactData->repeatCount = 0; + contactData->lastMessageTime = GetTickCount(); + contactData->lastMessage = info.Question; +} + +bool TalkBot::FindAny(ValueChooser<> &ch, tstring& res) +{ + if (!ch.GetContainer().size()) + return false; + res = ch.GetString(); + return true; +} + +void TalkBot::SplitSectences(const tstring &incomingMessage, vector& vec) +{ + //FIXME: (THINK ABOUT IT:-) )these chars not always mark the end of sentence. + const TCHAR symbols[] = _T(".?!"); + int it = 0, len = incomingMessage.length(); + while (it != len) + { + while (it != len && _istspace(incomingMessage[it])) + it++; + int start = it; + while (it != len) + { + if (_tcschr(symbols, incomingMessage[it++])) + { + //Test for a :-! smile + if (it > 2 && incomingMessage[it-1] == _T('!') + && incomingMessage[it-2] == _T('-') + && incomingMessage[it-3] == _T(':')) + continue; + while (it != len && _tcschr(symbols, incomingMessage[it])) + it++; + break; + } + } + vec.insert(vec.end(), incomingMessage.substr(start, it - start)); + } +} + +#ifdef _DEBUG +tstring LevelToStr(TalkBot::Level target) +{ + tstring lev; + switch (target) + { + case TalkBot::BEST: lev = _T("BEST(0)"); break; + case TalkBot::LOOKSLIKE: lev = _T("LOOKSLIKE(1)"); break; + case TalkBot::BAD: lev = _T("BAD(2)"); break; + case TalkBot::FAIL: lev = _T("FAIL(3)"); break; + case TalkBot::NOTHING: lev = _T("NOTHING(4)"); break; + } + return lev; +} +#endif + +tstring TalkBot::ChooseResult(ContactData* contactData, Level maxValue, const multimap &mm) +{ +#ifdef DEBUG_SHOW_VARIANTS + AddBotMessage(_T(">>Availabe:")); + for (multimap::iterator it = mm.begin(); it != mm.end(); it++) + AddBotMessage(LevelToStr((*it).first) + _T(": ") + (*it).second); + AddBotMessage(_T(">>Result:")); +#endif + if (maxValue == NOTHING) + return _T(""); + Level target = maxValue; + int num = mm.count(target); +/* if (!num) + { + target = maxValue; + num = mm.count(target); + }*/ + typedef multimap::const_iterator lt_cit; + pair range = mm.equal_range(target); + for (lt_cit it = range.first; it != range.second; it++) + contactData->chooser.AddChoice((*it).second); +#ifdef DEBUG_SHOW_LEVEL + tstring lev = LevelToStr(target); + return lev + _T(": ") + contactData->chooser.Choose(); +#else + return contactData->chooser.Choose(); +#endif +} + +void TalkBot::FindByKeywords(ContactData* contactData, const vector &keywords, tstring& res/*, tstring& ures*/, + bool isQuestion) +{ + if (keywords.size() == 0) + return; + const multimap &keys = isQuestion ? mind.GetData()->qkeywords : + mind.GetData()->keywords; + for (multimap::const_iterator it = keys.begin(); it != keys.end(); it++) + { + float prio; + if ((*it).first.MatchesAll(keywords/*, strict*/, prio)) +#ifdef DEBUG_SHOW_SOLUTION_REASON + contactData->chooser.AddChoice((tstring)(*it).first + _T(": - ") + (*it).second, prio); +#else + contactData->chooser.AddChoice((*it).second, prio); +#endif + } + res = contactData->chooser.Choose(); +} + +bool TalkBot::FindByOthers(ContactData* contactData, const vector &otherwords, tstring& res, bool isQuestion) +{ + //vector results; + const multimap &specs = isQuestion ? mind.GetData()->qspecialEscapes : + mind.GetData()->specialEscapes; + for (multimap::const_iterator it = specs.begin(); + it != specs.end(); it++) + if ((*it).first.MatchesAny(otherwords)) + { +#ifdef DEBUG_SHOW_SOLUTION_REASON + contactData->chooser.AddChoice((tstring)(*it).first + _T(": - ") + (*it).second); +#else + contactData->chooser.AddChoice((*it).second); +#endif + } + res = contactData->chooser.Choose(); + if (res.empty()) + return false; + return true; +} + +const Mind& TalkBot::GetMind() const +{ + return mind; +} + +void TalkBot::SplitAndSortWords(tstring sentence, vector& keywords, + vector& otherwords, bool& isQuestion) +{ + const TCHAR dividers[] = _T(" \t\n\r,./?\\|;:'\"~!#^&*()_-+=[{]}"); + int len = sentence.length(); + vector words; + map sm; + //Find smiles + for (size_t i = 0; i < sentence.length() - 1; i++) + { + unsigned max = sentence.length() - i; + if (max > mind.GetData()->maxSmileLen) + max = mind.GetData()->maxSmileLen; + for (unsigned j = max; j > 0; j--) + { + tstring item = sentence.substr(i, j); + if (mind.GetData()->smiles.find(item) + != mind.GetData()->smiles.end()) + { + sm[i] = item; + sentence.replace(i, j, _T(" ")); + break; + } + } + } + len = sentence.length(); + bool hadQuestionSigns = false; + int it = 0; + while (it != len) + { + while (it != len && _tcschr(dividers, sentence[it])) + { + if (sentence[it] == _T('?')) + hadQuestionSigns = true; + map::iterator smit; + if (_istspace(sentence[it]) && (smit = sm.find(it)) != sm.end()) + words.push_back((*smit).second); + it++; + } + if (it == len) + break; + hadQuestionSigns = false; + int start = it; + while (true) + { + while (it != len && !_tcschr(dividers, sentence[it])) + it++; + if (it == len || sentence[it] != _T('-')) + break; + //If we have-a-word-with-minus, we shouldn't split it + if (_tcschr(dividers, sentence[it + 1])) + break; + it += 2; + } + tstring str = sentence.substr(start, it - start); + words.push_back(str); + } + isQuestion = hadQuestionSigns; + for (vector::iterator it = words.begin(); it != words.end(); it++) + { + if (!isQuestion) + { + if (mind.GetData()->question.find(*it) != mind.GetData()->question.end()) + isQuestion = true; + } + if (mind.GetData()->special.find(*it) != mind.GetData()->special.end()) + otherwords.push_back(*it); +#ifdef EXCLUDE_SPECIAL_WORDS + else +#endif + keywords.push_back(*it); + } +} + +void TalkBot::SetSilent(const bool isSilent) +{ + beSilent = isSilent; +} + +void TalkBot::SetLowercase(const bool isLowercase) +{ + makeLowercase = isLowercase; +} + +void TalkBot::SetUnderstandAlways(const bool understandAlways) +{ + this->understandAlways = understandAlways; +} \ No newline at end of file diff --git a/plugins/Boltun/Engine/TalkEngine.h b/plugins/Boltun/Engine/TalkEngine.h new file mode 100644 index 0000000000..364f4193d1 --- /dev/null +++ b/plugins/Boltun/Engine/TalkEngine.h @@ -0,0 +1,112 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef TalkEngineH +#define TalkEngineH + +#include "Mind.h" +#include "ValueChooser.h" +#include "PerContactData.h" +#include "UnrecentChooser.h" + +class TalkBot +{ +public: + struct MessageInfo + { + private: + tstring Question; + MessageInfo(tstring q, tstring a) + :Question(q), Answer(a) + { + } + public: + tstring Answer; + MessageInfo(tstring q) + :Question(q) + { + } + friend class TalkBot; + }; +private: + typedef enum + { + BEST, LOOKSLIKE/*, LOOKSLIKE2*/, BAD, FAIL, NOTHING + } Level; + friend tstring LevelToStr(TalkBot::Level target); + + struct ContactData + { + ValueChooser<> initial; + //ValueChooser > question; + //ValueChooser > special; + ValueChooser<> escape; + ValueChooser<> failure; + UnRecentChooser chooser; + tstring lastMessage; + long long lastMessageTime; + int repeatCount; + inline ContactData(const Mind& mind) + :initial(mind.GetData()->initial), + //question(mind.GetData()->question), + //special(mind.GetData()->special), + escape(mind.GetData()->escape), + failure(mind.GetData()->failure), + repeatCount(0) + { + } + }; + + PerContactData* contactDatas; + const Mind mind; + bool beSilent; + bool makeLowercase; + bool understandAlways; + void UpdateStartChar(tstring& str); + typedef std::multimap::const_iterator mm_cit; + bool FindExact(ContactData* contactData, const tstring &incomingMessage, + const std::multimap& map, tstring& res); + bool FindAny(ValueChooser<> &ch, tstring& res); + void FindByKeywords(ContactData* contactData, const std::vector &keywords, tstring& res/*, tstring& ures*/, bool isQuestion); + bool FindByOthers(ContactData* contactData, const std::vector &otherwords, tstring& res, bool isQuestion); + tstring AllReplies(const tstring &incomingMessage, ContactData* contactData, Level &maxValue, std::multimap &mm); + tstring ReplaceAliases(const tstring &message); + tstring ChooseResult(ContactData* contactData, Level maxValue, const std::multimap &mm); + void RecordAnswer(ContactData *contactData, const TalkBot::MessageInfo& info); +#ifdef _DEBUG +public: +#endif + void SplitSectences(const tstring &incomingMessage, std::vector& vec); + void SplitAndSortWords(tstring sentence, std::vector& keywords, + std::vector& otherwords, bool& isQuestion); +public: + TalkBot(const Mind& goodMind); + ~TalkBot(); + const Mind& GetMind() const; + void SetSilent(const bool isSilent); + void SetLowercase(const bool isLowercase); + void SetUnderstandAlways(const bool understandAlways); + //const MindData *GetData(); + tstring GetInitMessage(void* contact); + MessageInfo* Reply(void* contact, const tstring incomingMessage, bool saveChoice); + void AnswerGiven(void* contact, const MessageInfo& info); +}; + +#endif diff --git a/plugins/Boltun/Engine/UnrecentChooser.cpp b/plugins/Boltun/Engine/UnrecentChooser.cpp new file mode 100644 index 0000000000..069d84f377 --- /dev/null +++ b/plugins/Boltun/Engine/UnrecentChooser.cpp @@ -0,0 +1,100 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#include "UnrecentChooser.h" + +using namespace std; + +UnRecentChooser::UnRecentChooser() + :last(-1), min(-1), newItemsPrio(-1), maxOldPrio(-1) +{ +} + +void UnRecentChooser::AddChoice(tstring value, float prio) +{ + if (items.count(value) != 0) + { + int val = items[value]; + oldItems.insert(make_pair(val, value)); + oldPrios.insert(make_pair(value, prio)); + if (min > val || min == -1) + min = val; + if (maxOldPrio < prio) + maxOldPrio = prio; + } + else + { + if (prio > newItemsPrio) + { + newItems.push_back(value); + newItemsPrio = prio; + } + } +} + +tstring UnRecentChooser::Choose() +{ + tstring res; + //Find answer + if (newItemsPrio != -1) + { + int num = rand() % newItems.size(); + res = newItems[num]; + } + else + if (min == -1) + res = _T(""); + else + { + float minprio = maxOldPrio / 1.5F; + while (oldPrios[oldItems[min]] < minprio) + min++; + res = oldItems[min]; + } + //Clean items + min = -1; + newItemsPrio = -1; + maxOldPrio = -1; + oldItems.clear(); + oldPrios.clear(); + newItems.clear(); + return res; +} + +void UnRecentChooser::SaveChoice(tstring choice) +{ + //Add answer + if (items.find(choice) != items.end()) + { + for (vector::iterator it = itemsList.begin(); it != itemsList.end(); it++) + if (*it == choice) + { + itemsList.erase(it); + break; + } + } + items[choice] = ++last; + itemsList.push_back(choice); + if (itemsList.size() > maxItems) + { + items.erase(*itemsList.begin()); + itemsList.erase(itemsList.begin()); + } +} \ No newline at end of file diff --git a/plugins/Boltun/Engine/UnrecentChooser.h b/plugins/Boltun/Engine/UnrecentChooser.h new file mode 100644 index 0000000000..91a961e307 --- /dev/null +++ b/plugins/Boltun/Engine/UnrecentChooser.h @@ -0,0 +1,47 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef UnRecentChooserH +#define UnRecentChooserH + +#include +#include +#include +#include "tstring.h" + +class UnRecentChooser +{ + std::map items; + std::vector itemsList; + std::vector newItems; + float newItemsPrio, maxOldPrio; + std::map oldItems; + std::map oldPrios; + size_t last; + int min; + static const size_t maxItems = 100; +public: + UnRecentChooser(); + void AddChoice(tstring value, float prio = 1.0); + tstring Choose(); + void SaveChoice(tstring choice); +}; + +#endif /* UnRecentChooserH */ \ No newline at end of file diff --git a/plugins/Boltun/Engine/ValueChooser.h b/plugins/Boltun/Engine/ValueChooser.h new file mode 100644 index 0000000000..3fb1510609 --- /dev/null +++ b/plugins/Boltun/Engine/ValueChooser.h @@ -0,0 +1,88 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef StringChooserH +#define StringChooserH + +#include +#include + +template > +class ValueChooser +{ +private: + int freeNumbers; + bool *numbers; + const container data; + bool notifyOnReset; +public: + ValueChooser(const container& vec, bool NotifyOnReset = false) + :data(vec), notifyOnReset(NotifyOnReset) + { + //randomize(); + numbers = NULL; + UpdateLength(); + } + + ~ValueChooser() + { + delete numbers; + } + + void UpdateLength() + { + delete numbers; //normal if numbers == NULL + numbers = new bool[data.size()]; + Reset(); + } + + void Reset() + { + for (size_t i = 0; i < data.size(); i++) + numbers[i] = false; + freeNumbers = data.size(); + } + + typename container::value_type GetString() + { + if (!freeNumbers) + { + Reset(); + if (notifyOnReset) + return _T(""); + } + int result; + while (numbers[result = rand() % data.size()]) + ; + freeNumbers--; + numbers[result] = true; + return data[result]; + } + + container GetContainer() const; +}; + +template +container ValueChooser::GetContainer() const +{ + return data; +} + +#endif diff --git a/plugins/Boltun/Engine/WordsList.cpp b/plugins/Boltun/Engine/WordsList.cpp new file mode 100644 index 0000000000..5e5d0c37a5 --- /dev/null +++ b/plugins/Boltun/Engine/WordsList.cpp @@ -0,0 +1,169 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#include "WordsList.h" + +using namespace std; + +WordsList::WordsList(const tstring &data/*, bool allowUnstrict*/) +{ + Parse(data/*, allowUnstrict*/); +} + +WordsList::operator tstring() const +{ + tstring res; + //if (unstrict) + // res = _T("~"); + set::const_iterator it = words.begin(); + if (!words.empty()) + while (true) + { + res += *it; + it++; + if (it != words.end()) + res += _T(" "); + else + break; + } + res += isQuestion ? _T("?") : _T("."); + return res; +} + +WordsList& WordsList::operator= (const tstring& s) +{ + Parse(s); + return *this; +}; + +void WordsList::Parse(tstring s/*, bool allowUnstrict*/) +{ + isQuestion = false; + /*if (allowUnstrict && s.length() && s[0] == _T('~')) + { + s = s.substr(1, s.npos); + unstrict = true; + } + else + unstrict = false;*/ + int len = s.length() - 1; + while (len != -1 && _istspace(s[len])) + len--; + if (len < 0) + return; + if (s[len] == '?') + isQuestion = true; + else + if (s[len] != '.') + return; + s.resize(len); + int it = 0; + while (it != len) + { + while (it != len && _istspace(s[it])) + it++; + if (it == len) + break; + int start = it; + while (it != len && !_istspace(s[it])) + it++; + words.insert(s.substr(start, it - start)); + } +} + +bool WordsList::MatchesAll(const vector& s/*, bool& WasStrict*/, float& priority) const +{ + std::set temp; + //WasStrict = true; + for (vector::const_iterator it = s.begin(); it != s.end(); it++) + { +/* if (words.find(*it) == words.end()) + if (unstrict) + { + WasStrict = false; + continue; + } + else + return false; + temp.insert((*it));*/ + if (words.find(*it) != words.end()) + temp.insert((*it)); + } + if (temp.size() != words.size()) + return false; + priority = words.size() * words.size() / (float)s.size(); + return temp.size() == words.size(); +} + +bool WordsList::MatchesAny(const vector& s) const +{ + for (vector::const_iterator it = s.begin(); it != s.end(); it++) + if (words.find(*it) != words.end()) + return true; + return false; +} + +vector WordsList::ConsistsOf(const set& list) const +{ + vector res; + for (set::const_iterator it = words.begin(); it != words.end(); it++) + if (list.find(*it) == list.end()) + res.push_back(*it); + return res; +} + +vector WordsList::DoesntIncludeAny(const set& list) const +{ + vector res; + for (set::const_iterator it = words.begin(); it != words.end(); it++) + if (list.find(*it) != list.end()) + res.push_back(*it); + return res; +} + +bool WordsList::operator<(const WordsList& value) const +{ + return (tstring)*this < (tstring)value; +} + +bool WordsList::operator!=(const WordsList& value) const +{ + return (tstring)*this != (tstring)value; +} + +bool WordsList::operator==(const WordsList& value) const +{ + return (tstring)*this == (tstring)value; +} + +size_t WordsList::Size() const +{ + return words.size(); +} + +bool WordsList::IsQuestion() const +{ + return isQuestion; +} + +bool WordsList::IsEmpty() const +{ + return words.size() == 0; +} \ No newline at end of file diff --git a/plugins/Boltun/Engine/WordsList.h b/plugins/Boltun/Engine/WordsList.h new file mode 100644 index 0000000000..bd74b2007b --- /dev/null +++ b/plugins/Boltun/Engine/WordsList.h @@ -0,0 +1,56 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef WordsListH +#define WordsListH + +#include +#include +#include +#include "tchar.h" +#include "tstring.h" + +class WordsList +{ + WordsList(); + void Parse(tstring s/*, bool allowUnstrict = false*/); + //bool unstrict; +#ifdef _DEBUG +public: +#endif + std::set words; + bool isQuestion; +public: + WordsList(const tstring &data/*, bool allowUnstrict = false*/); + operator tstring() const; + bool MatchesAll(const std::vector& s/*, bool& WasStrict*/, float& priority) const; + bool MatchesAny(const std::vector& s) const; + std::vector ConsistsOf(const std::set& list) const; + std::vector DoesntIncludeAny(const std::set& list) const; + WordsList& operator= (const tstring& s); + bool operator<(const WordsList& value) const; + bool operator==(const WordsList& value) const; + bool operator!=(const WordsList& value) const; + bool IsQuestion() const; + bool IsEmpty() const; + size_t Size() const; +}; + +#endif diff --git a/plugins/Boltun/Engine/boltun.mindw b/plugins/Boltun/Engine/boltun.mindw new file mode 100644 index 0000000000..a6f9f2103d Binary files /dev/null and b/plugins/Boltun/Engine/boltun.mindw differ diff --git a/plugins/Boltun/Engine/tstring.h b/plugins/Boltun/Engine/tstring.h new file mode 100644 index 0000000000..e21984a12c --- /dev/null +++ b/plugins/Boltun/Engine/tstring.h @@ -0,0 +1,34 @@ +//*********************************************************** +// Copyright 2008 Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef TSTRING_H +#define TSTRING_H + +#include +#include + +#ifndef TCHAR +#define TCHAR _TCHAR +#endif + +typedef std::basic_string, + std::allocator > tstring; + +#endif diff --git a/plugins/Boltun/TODO.txt b/plugins/Boltun/TODO.txt new file mode 100644 index 0000000000..6ea2151d2d --- /dev/null +++ b/plugins/Boltun/TODO.txt @@ -0,0 +1,35 @@ +TODO list: + +-------------------------------------------------------- +Release-critical: + +- Add study capability to engine + +Done: +- Add reaction for duplicate phrases. +- Add aliases. +- Check for critical section double enter +- Multicontact talk support in engine +- Add "Start talking" option to cantact menu. +- Check bot warning. +- Add "be silent, not stupid" to options +- Add start answers with a little letter. +- Add README about bot algorithm. +- Add README for mind file format. +- Add "don't use "don't understand"" option +- Division between question and non-question sentenses +- Empty keywords or specials should not be loaded +- Check "-" +- Check :-) on "" +- Add answer-on status info to the readme. +- Make AI options dependent. +- Update mind.txt with UpdateStartChar +- Sort keywords matches by priority +- Use chooser everywhere + +-------------------------------------------------------- +Future: +- Speed-up loading +- Load mind from UTF8 files +- Expert mode support +- Add different choises of reaction for message series. diff --git a/plugins/Boltun/actionQueue.cpp b/plugins/Boltun/actionQueue.cpp new file mode 100644 index 0000000000..7040778c85 --- /dev/null +++ b/plugins/Boltun/actionQueue.cpp @@ -0,0 +1,256 @@ +//*********************************************************** +// Copyright 2003-2008 Alexander S. Kiselev, Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#include "actionQueue.h" +#include "config.h" +#include "boltun.h" +#include "Engine/tstring.h" +#include "Engine/TalkEngine.h" + +#include +#include +#include +#include "Engine/CriticalSection.h" +#ifdef _DEBUG +#include +#endif + +#define MIRANDA_VER 0x0700 +#include "newpluginapi.h" +#include "m_database.h" +#include "m_system.h" +#include "m_protosvc.h" + +using namespace std; + +extern TalkBot* bot; + +typedef void (*ActionHandler)(HANDLE hContact, const TalkBot::MessageInfo *inf); + +typedef struct _QueueElement { + HANDLE hContact; + const TalkBot::MessageInfo *inf; + ActionHandler Handler; + bool Sticky; + int TimeOffset; + _QueueElement(HANDLE contact, ActionHandler handler, int timeOffset, const TalkBot::MessageInfo *info = NULL, bool sticky = false) + :hContact(contact), Handler(handler), TimeOffset(timeOffset), inf(info), Sticky(sticky) + { + } +} QueueElement; + +static list actionQueue; +static set typingContacts; +UINT_PTR timerID = 0; + +CriticalSection cs; +CriticalSection typingContactsLock; + +void UpdateTimer(); + +VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + cs.Enter(); + QueueElement q = actionQueue.front(); + actionQueue.pop_front(); + UpdateTimer(); + cs.Leave(); + q.Handler(q.hContact, q.inf); +} + +void UpdateTimer() +{ + if (timerID) + KillTimer(NULL, timerID); + if (actionQueue.size()) + timerID = SetTimer(NULL, 0, actionQueue.front().TimeOffset, TimerProc); + else + timerID = 0; +} + +static bool NotifyTyping(HANDLE hContact) +{ + int res = DBGetContactSettingByte(hContact, "SRMsg", "SupportTyping", 2); + if (res == 2) + res = DBGetContactSettingByte(NULL, "SRMsg", "DefaultTyping", 1); + return res != 0; +} + +static char *MsgServiceName(HANDLE hContact) +{ +#ifdef _UNICODE + char szServiceName[100]; + char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto == NULL) + return PSS_MESSAGE; + + mir_snprintf(szServiceName, sizeof(szServiceName), "%s%sW", szProto, PSS_MESSAGE); + if (ServiceExists(szServiceName)) + return PSS_MESSAGE "W"; +#endif + return PSS_MESSAGE; +} + +static void TimerAnswer(HANDLE hContact, const TalkBot::MessageInfo* info) +{ + DBEVENTINFO ldbei; + int size = info->Answer.length() + 1; + int bufsize = size; + char* msg; +#ifdef UNICODE + bufsize *= sizeof(TCHAR) + 1; + msg = new char[bufsize]; + //msg[size - 1] = '\0'; + + if (!WideCharToMultiByte(CP_ACP, 0, info->Answer.c_str(), -1, msg, size, + NULL, NULL)) + FillMemory(msg, size - 1, '-'); //In case of fault return "----" in ANSI part + CopyMemory(msg + size, info->Answer.c_str(), size * 2); +#else + msg = respItem->szMes; +#endif + + CallContactService(hContact, MsgServiceName(hContact), PREF_TCHAR, (LPARAM)msg); + + ZeroMemory(&ldbei, sizeof(ldbei)); + ldbei.cbSize = sizeof(ldbei); + //FIXME: Error may happen + ldbei.cbBlob = bufsize; + ldbei.pBlob = (PBYTE)(void*)msg; + ldbei.eventType = EVENTTYPE_MESSAGE; + ldbei.flags = DBEF_SENT; + ldbei.szModule = BOLTUN_NAME; + ldbei.timestamp = (DWORD)time(NULL); + + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&ldbei); + bot->AnswerGiven(hContact, *info); + delete info; +#ifdef UNICODE + delete msg; +#endif + typingContactsLock.Enter(); + typingContacts.erase(hContact); + typingContactsLock.Leave(); +} + +static void StartTyping(HANDLE hContact, const TalkBot::MessageInfo*) +{ + CallService(MS_PROTO_SELFISTYPING, (WPARAM)hContact, + (LPARAM)PROTOTYPE_SELFTYPING_ON); + typingContactsLock.Enter(); + typingContacts.insert(hContact); + typingContactsLock.Leave(); +} + +void DoAnswer(HANDLE hContact, const TalkBot::MessageInfo *info, bool sticky = false) +{ + if (info->Answer[0] == _T('\0')) + return; + int waitTime, thinkTime = 0; + int defWaitTime = Config.AnswerPauseTime * 1000; + if (Config.PauseDepends) + waitTime = defWaitTime * info->Answer.length() / 25; + else + waitTime = defWaitTime; + if (Config.PauseRandom) + { + //Let it be up to 4 times longer. + waitTime = waitTime * (rand() % 300) / 100 + waitTime; + } + if (waitTime == 0) + waitTime = 50; //it's essential, because otherwise message will be added later + //then its response, that will cause incorrect ordering of + //messages in the opened history (reopening will + //help, but anyway it's no good) + if (NotifyTyping(hContact) && Config.AnswerThinkTime) + { + thinkTime = Config.AnswerThinkTime * 1000; + if (Config.PauseRandom) + { + //Let it be up to 4 times longer. + thinkTime = thinkTime * (rand() % 300) / 100 + thinkTime; + } + } + cs.Enter(); + //Check if this contact's timer handler is now waiting for a cs. + bool needTimerRearrange = false; + if (!actionQueue.empty() && actionQueue.front().hContact == hContact) + { + needTimerRearrange = true; + KillTimer(NULL, timerID); + cs.Leave(); + cs.Enter(); + } + if (!actionQueue.empty()) + { + list::iterator it = actionQueue.end(); + it--; + while (true) + { + if ((*it).hContact == hContact) + { + if ((*it).Sticky) + break; + list::iterator tmp = it; + if (tmp != actionQueue.begin()) + tmp--; + actionQueue.erase(it); + it = tmp; + if (actionQueue.empty()) + break; + } + if (it == actionQueue.begin()) + break; + it--; + } + } + typingContactsLock.Enter(); + if (typingContacts.find(hContact) != typingContacts.end()) + { + CallService(MS_PROTO_SELFISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_SELFTYPING_OFF); + typingContacts.erase(hContact); + } + typingContactsLock.Leave(); + if (actionQueue.empty()) + needTimerRearrange = true; + if (thinkTime) + actionQueue.push_back(QueueElement(hContact, StartTyping, thinkTime, NULL, sticky)); + actionQueue.push_back(QueueElement(hContact, TimerAnswer, waitTime, info, sticky)); + if (needTimerRearrange) + UpdateTimer(); + cs.Leave(); +} + +void AnswerToContact(HANDLE hContact, const TCHAR* messageToAnswer) +{ + if (Config.TalkWarnContacts && DBGetContactSettingByte(hContact, BOLTUN_KEY, + DB_CONTACT_WARNED, FALSE) == FALSE) + { + DoAnswer(hContact, new TalkBot::MessageInfo((const TCHAR*)Config.WarnText), true); + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_WARNED, TRUE); + } + else + DoAnswer(hContact, bot->Reply(hContact, messageToAnswer, false)); +} + +void StartChatting(HANDLE hContact) +{ + DoAnswer(hContact, new TalkBot::MessageInfo(bot->GetInitMessage(hContact)), true); +} diff --git a/plugins/Boltun/actionQueue.h b/plugins/Boltun/actionQueue.h new file mode 100644 index 0000000000..78f6ce5f9e --- /dev/null +++ b/plugins/Boltun/actionQueue.h @@ -0,0 +1,30 @@ +//*********************************************************** +// Copyright 2003-2008 Alexander S. Kiselev, Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef ACTIONQUEUE_H +#define ACTIONQUEUE_H + +#include + +void AnswerToContact(HANDLE hContact, const TCHAR* messageToAnswer); + +void StartChatting(HANDLE hContact); + +#endif /* ACTIONQUEUE_H */ \ No newline at end of file diff --git a/plugins/Boltun/boltun.cpp b/plugins/Boltun/boltun.cpp new file mode 100644 index 0000000000..e0f85661b0 --- /dev/null +++ b/plugins/Boltun/boltun.cpp @@ -0,0 +1,718 @@ +//*********************************************************** +// Copyright 2003-2008 Alexander S. Kiselev, Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#define MIRANDA_VER 0x0700 + +#include "Engine/TalkEngine.h" + +#include +#include +#include + +#include "newpluginapi.h" +#include "m_clist.h" +#include "m_skin.h" +#include "m_database.h" +#include "m_system.h" +#include "m_protosvc.h" +#include "m_options.h" +#include "m_langpack.h" +#include "resource.h" + +#include "resource.h" + +#include "boltun.h" +#include "config.h" +#include "actionQueue.h" + +//#define DEBUG_LOAD_TIME + +struct MM_INTERFACE mmi; + +TalkBot* bot = NULL; + + +#define MAX_WARN_TEXT 1024 +#define MAX_MIND_FILE 1024 + +HINSTANCE hInst; +PLUGINLINK *pluginLink; +BOOL blInit = FALSE; +UINT pTimer = 0; +TCHAR *path; + +PLUGININFO pluginInfo={ + sizeof(PLUGININFO), + BOLTUN_NAME, + PLUGIN_MAKE_VERSION(0,0,3,0), + PLUGIN_DESCRIPTION, + "Alexander S. Kiselev, Valentin Pavlyuchenko", + "Valentin.Pavlyuchenko@gmail.com", + " 2003-2008 Alexander S. Kiselev A.K.A. KAS, Valentin Pavlyuchenko", + "http://miranda-im.org", + UNICODE_AWARE, + 0 +}; + +static HANDLE hEventDbEventAdded; +static HANDLE hEventOptInitialise; +static HANDLE hEventPrebuild; +static HANDLE hMenuItemAutoChat; +static HANDLE hMenuItemNotToChat; +static HANDLE hMenuItemStartChatting; + +#ifdef UNICODE +#define MIND_DIALOG_FILTER _T("%s (*.mindw)\1*.mindw\1%s (*.*)\1*.*\1") +#else +#define MIND_DIALOG_FILTER "%s (*.mind)\1*.mind\1%s (*.*)\1*.*\1" +#endif + +#ifdef DEBUG_LOAD_TIME +#include +#endif + +void UpdateEngine() +{ + if (bot) + { + bot->SetSilent(Config.EngineStaySilent); + bot->SetLowercase(Config.EngineMakeLowerCase); + bot->SetUnderstandAlways(Config.EngineUnderstandAlways); + } +} + +TCHAR* GetFullName(const TCHAR* filename) +{ + size_t flen = _tcslen(filename); + TCHAR* fullname = const_cast(filename); + if (!_tcschr(filename, _T(':'))) + { + size_t plen = _tcslen(path); + fullname = new TCHAR[plen+flen+1]; + fullname[0] = NULL; + _tcscat(fullname, path); + _tcscat(fullname, filename); + } + return fullname; +} + +static bool LoadMind(const TCHAR* filename, int &line) +{ + TCHAR* fullname = GetFullName(filename); + HCURSOR newCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)); + HCURSOR oldCur = SetCursor(newCur); +#ifdef DEBUG_LOAD_TIME + unsigned __int64 t = __rdtsc(); +#endif + Mind* mind = new Mind(); + line = -1; + try + { + mind->Load(fullname); + } + catch(Mind::CorruptedMind c) + { + line = c.line; + delete mind; + if (fullname != filename) + delete[] fullname; + SetCursor(oldCur); + return false; + } + catch(...) + { + delete mind; + if (fullname != filename) + delete[] fullname; + SetCursor(oldCur); + return false; + } + if (fullname != filename) + delete[] fullname; + +#ifdef DEBUG_LOAD_TIME + t = __rdtsc() - t; + char dest[101]; + sprintf_s(dest, 100, "%I64d ticks\n", t / 3200000); + MessageBoxA(NULL, dest, NULL, 0); + //exit(0); +#endif + SetCursor(oldCur); + HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDR_SMILES), _T("SMILES")); + if (!hRes) + { + delete mind; + return false; + } + DWORD size = SizeofResource(hInst, hRes); + if (!size) + { + delete mind; + return false; + } + HGLOBAL hGlob = LoadResource(hInst, hRes); + if (!hGlob) + { + delete mind; + return false; + } + void *data = LockResource(hGlob); + if (!data) + { + FreeResource(hGlob); + delete mind; + return false; + } + bool res = true; + try + { + mind->LoadSmiles(data, size); + } + catch(...) + { + res = false; + } + UnlockResource(data); + FreeResource(hGlob); + if (!res) + { + delete mind; + return false; + } + if (bot) + delete bot; + bot = new TalkBot(*mind); + delete mind; + UpdateEngine(); + return true; +} + +/*static bool SaveMind(const TCHAR* filename) +{ + if (!bot) + return false; + bot->GetMind().Save(filename); + return true; +}*/ + +static bool BoltunAutoChat(HANDLE hContact) +{ + if (DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT + , FALSE) == TRUE) + return false; + + if (Config.TalkWithEverybody) + return true; + + if (Config.TalkEveryoneWhileAway) + { + int status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); + if (status == ID_STATUS_AWAY || + status == ID_STATUS_DND || + status == ID_STATUS_NA || + status == ID_STATUS_OCCUPIED || + status == ID_STATUS_ONTHEPHONE || + status == ID_STATUS_OUTTOLUNCH) + return true; + } + + if ((DBGetContactSettingByte(hContact,"CList","NotOnList",0) == 1) && + Config.TalkWithNotInList) + return true; + + if (DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, + FALSE) == TRUE) + return true; + + return false; +} + +static int MessageEventAdded(WPARAM wParam, LPARAM lParam) +{ + //DBEVENTINFO ldbei; + HANDLE hContact = (HANDLE)wParam; + if (!BoltunAutoChat(hContact)) + return 0; + + DBEVENTINFO dbei; + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = 0; + + dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, lParam, 0); + if (dbei.cbBlob == -1) + return 0; + + dbei.pBlob = (PBYTE)malloc(dbei.cbBlob); + if (dbei.pBlob == NULL) + return 0; + + CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei); + if (dbei.flags & DBEF_SENT || dbei.flags & DBEF_READ || dbei.eventType != EVENTTYPE_MESSAGE) + return 0; + DBEVENTGETTEXT egt; + egt.codepage = CP_ACP; + egt.datatype = DBVT_TCHAR; + egt.dbei = &dbei; + TCHAR* s = (TCHAR*)(void*)CallService(MS_DB_EVENT_GETTEXT, 0, (LPARAM)&egt); + free(dbei.pBlob); + if (Config.MarkAsRead) + CallService(MS_DB_EVENT_MARKREAD, wParam, lParam); + + AnswerToContact(hContact, s); + mir_free(s); + return 0; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} + +void UpdateEverybodyCheckboxes(HWND hwndDlg) +{ + bool Enable = !IsDlgButtonChecked(hwndDlg, IDC_EVERYBODY) == BST_CHECKED; + HWND wnd; + wnd = GetDlgItem(hwndDlg, IDC_NOTINLIST); + EnableWindow(wnd, Enable); + wnd = GetDlgItem(hwndDlg, IDC_AUTOAWAY); + EnableWindow(wnd, Enable); +} + +static int CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + BOOL bTranslated = FALSE; + static bool loading = true; + switch (uMsg) + { + case WM_INITDIALOG: + loading = true; + TranslateDialogDefault(hwndDlg); + CheckDlgButton(hwndDlg, IDC_EVERYBODY, Config.TalkWithEverybody ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_NOTINLIST, Config.TalkWithNotInList ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_AUTOAWAY, Config.TalkEveryoneWhileAway ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_WARN, Config.TalkWarnContacts ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_MARKREAD, Config.MarkAsRead ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_PAUSEDEPENDS, Config.PauseDepends ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_PAUSERANDOM, Config.PauseRandom ? BST_CHECKED : BST_UNCHECKED); + SendDlgItemMessage(hwndDlg, IDC_WAITTIME, EM_SETLIMITTEXT, 3, 0); + SetDlgItemInt(hwndDlg, IDC_WAITTIME, Config.AnswerPauseTime, FALSE); + SendDlgItemMessage(hwndDlg, IDC_THINKTIME, EM_SETLIMITTEXT, 3, 0); + SetDlgItemInt(hwndDlg, IDC_THINKTIME, Config.AnswerThinkTime, FALSE); + SendDlgItemMessage(hwndDlg, IDC_WARNTXT, EM_SETLIMITTEXT, MAX_WARN_TEXT, 0); + SetDlgItemText(hwndDlg, IDC_WARNTXT, Config.WarnText); + UpdateEverybodyCheckboxes(hwndDlg); + loading = false; + return TRUE; + case WM_COMMAND: + if (LOWORD(wParam) == IDC_EVERYBODY && HIWORD(wParam) == BN_CLICKED) + UpdateEverybodyCheckboxes(hwndDlg); + if (!loading) + { + bool notify = true; + switch (LOWORD(wParam)) + { + case IDC_WARNTXT: + case IDC_WAITTIME: + case IDC_THINKTIME: + if (HIWORD(wParam) != EN_CHANGE) + notify = false; + break; + } + if (notify) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + case WM_NOTIFY: + { + NMHDR* nmhdr = (NMHDR*)lParam; + switch (nmhdr->code) + { + case PSN_APPLY: + case PSN_KILLACTIVE: + { + Config.TalkWithEverybody = IsDlgButtonChecked(hwndDlg, IDC_EVERYBODY) == BST_CHECKED ? TRUE : FALSE; + Config.TalkWithNotInList = IsDlgButtonChecked(hwndDlg, IDC_NOTINLIST) == BST_CHECKED ? TRUE : FALSE; + Config.TalkEveryoneWhileAway = IsDlgButtonChecked(hwndDlg, IDC_AUTOAWAY) == BST_CHECKED ? TRUE : FALSE; + Config.TalkWarnContacts = IsDlgButtonChecked(hwndDlg, IDC_WARN) == BST_CHECKED ? TRUE : FALSE; + Config.MarkAsRead = IsDlgButtonChecked(hwndDlg, IDC_MARKREAD) == BST_CHECKED ? TRUE : FALSE; + Config.PauseDepends = IsDlgButtonChecked(hwndDlg, IDC_PAUSEDEPENDS) == BST_CHECKED ? TRUE : FALSE; + Config.PauseRandom = IsDlgButtonChecked(hwndDlg, IDC_PAUSERANDOM) == BST_CHECKED ? TRUE : FALSE; + Config.AnswerPauseTime = GetDlgItemInt(hwndDlg, IDC_WAITTIME, &bTranslated, FALSE); + if(!bTranslated) + Config.AnswerPauseTime = 2; + Config.AnswerThinkTime = GetDlgItemInt(hwndDlg, IDC_THINKTIME, &bTranslated, FALSE); + if(!bTranslated) + Config.AnswerThinkTime = 4; + TCHAR c[MAX_WARN_TEXT]; + bTranslated = GetDlgItemText(hwndDlg, IDC_WARNTXT, c, MAX_WARN_TEXT); + if(bTranslated) + Config.WarnText = c; + else + Config.WarnText = TranslateTS(DEFAULT_WARN_TEXT); + } + return TRUE; + } + break; + } + break; + } + return 0; +} + +void UpdateUnderstandAlwaysCheckbox(HWND hwndDlg) +{ + bool Enable = !IsDlgButtonChecked(hwndDlg, IDC_ENGINE_SILENT) == BST_CHECKED; + HWND wnd; + wnd = GetDlgItem(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS); + EnableWindow(wnd, Enable); +} + +static int CALLBACK EngineDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WORD param; + BOOL bTranslated = FALSE; + static bool loading = true; + static int changeCount = 0; + switch (uMsg) + { + case WM_INITDIALOG: + loading = true; + TranslateDialogDefault(hwndDlg); + CheckDlgButton(hwndDlg, IDC_ENGINE_SILENT, Config.EngineStaySilent ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ENGINE_LOWERCASE, Config.EngineMakeLowerCase ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS, Config.EngineUnderstandAlways ? BST_CHECKED : BST_UNCHECKED); + SetDlgItemText(hwndDlg, IDC_MINDFILE, Config.MindFileName); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTNSAVE), blInit); + UpdateUnderstandAlwaysCheckbox(hwndDlg); + loading = false; + return TRUE; + case WM_COMMAND: + param = LOWORD(wParam); + if (param == IDC_ENGINE_SILENT && HIWORD(wParam) == BN_CLICKED) + UpdateUnderstandAlwaysCheckbox(hwndDlg); + OPENFILENAME ofn; + switch(param) + { + case IDC_BTNPATH: + { + const size_t fileNameSize = 5000; + TCHAR *filename = new TCHAR[fileNameSize]; + TCHAR *fullname = GetFullName(Config.MindFileName); + _tcscpy(filename, fullname); + if (fullname != Config.MindFileName) + delete[] fullname; + + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = GetParent(hwndDlg); + + TCHAR* mind = TranslateTS(MIND_FILE_DESC); + TCHAR* anyfile = TranslateTS(ALL_FILES_DESC); + size_t l = _tcslen(MIND_DIALOG_FILTER) + + _tcslen(mind) + _tcslen(anyfile); + TCHAR *filt = new TCHAR[l]; + wsprintf(filt, MIND_DIALOG_FILTER, mind, anyfile); + for (size_t i = 0; i < l; i++) + if (filt[i] == '\1') + filt[i] = '\0'; + ofn.lpstrFilter = filt; + + ofn.lpstrFile = filename; + ofn.nMaxFile = fileNameSize; + ofn.Flags = OFN_FILEMUSTEXIST; + ofn.lpstrInitialDir = path; + if(!GetOpenFileName(&ofn)) + { + delete filename; + delete[] filt; + break; + } + delete[] filt; + TCHAR* origf = filename; + TCHAR* f = filename; + TCHAR* p = path; + while (*p && *f) + { + TCHAR p1 = (TCHAR)CharLower((TCHAR*)(long)*p++); + TCHAR f1 = (TCHAR)CharLower((TCHAR*)(long)*f++); + if (p1 != f1) + break; + } + if (!*p) + filename = f; + Config.MindFileName = filename; + SetDlgItemText(hwndDlg, IDC_MINDFILE, filename); + delete origf; + } + case IDC_BTNRELOAD: + { + const TCHAR *c = Config.MindFileName; + int line; + bTranslated = blInit = LoadMind(c, line); + if(!bTranslated) + { + TCHAR* message = new TCHAR[5000]; + wsprintf(message, TranslateTS(FAILED_TO_LOAD_BASE), line, c); + MessageBox(NULL, message, TranslateTS(BOLTUN_ERROR), MB_ICONERROR|MB_TASKMODAL|MB_OK); + delete[] message; + } + break; + } + default: + if (!loading) + { + if (param == IDC_MINDFILE/* && HIWORD(wParam) != EN_CHANGE*/) + break; + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + break; + case WM_NOTIFY: + { + NMHDR* nmhdr = (NMHDR*)lParam; + switch (nmhdr->code) + { + case PSN_APPLY: + case PSN_KILLACTIVE: + { + Config.EngineStaySilent = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_SILENT) == BST_CHECKED ? TRUE : FALSE; + Config.EngineMakeLowerCase = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_LOWERCASE) == BST_CHECKED ? TRUE : FALSE; + Config.EngineUnderstandAlways = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS) == BST_CHECKED ? TRUE : FALSE; + UpdateEngine(); + TCHAR c[MAX_MIND_FILE]; + bTranslated = GetDlgItemText(hwndDlg, IDC_MINDFILE, c, MAX_MIND_FILE); + if (bTranslated) + Config.MindFileName = c; + else + Config.MindFileName = DEFAULT_MIND_FILE; + } + return TRUE; + } + break; + } + break; + } + return 0; +} + +static int MessageOptInit(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = 910000000; + odp.hInstance = hInst; + odp.pszGroup = BOLTUN_GROUP; + odp.pszTitle = BOLTUN_NAME; + odp.pfnDlgProc = MainDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_MAIN); + odp.pszTab = TAB_GENERAL; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + odp.pfnDlgProc = EngineDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_ENGINE); + odp.pszTab = TAB_ENGINE; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + return 0; +} + +static int ContactClick(WPARAM wParam, LPARAM lParam, BOOL clickNotToChat) +{ + HANDLE hContact = (HANDLE)wParam; + + BOOL boltunautochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, FALSE); + BOOL boltunnottochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, FALSE); + + if (clickNotToChat) + { + boltunnottochat = !boltunnottochat; + if(boltunnottochat) + { + boltunautochat = FALSE; + } + } + else + { + boltunautochat = !boltunautochat; + if(boltunautochat) + { + boltunnottochat = FALSE; + } + else + { + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_WARNED, FALSE); + } + } + + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, (BYTE)boltunautochat); + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, (BYTE)boltunnottochat); + + return 0; +} + +static int ContactClickAutoChat(WPARAM wParam, LPARAM lParam) +{ + return ContactClick(wParam, lParam, 0); +} + +static int ContactClickNotToChat(WPARAM wParam, LPARAM lParam) +{ + return ContactClick(wParam, lParam, 1); +} + +static int ContactClickStartChatting(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + StartChatting(hContact); + return 0; +} + +static int MessagePrebuild(WPARAM wParam, LPARAM lParam) +{ + CLISTMENUITEM clmi; + HANDLE hContact = (HANDLE)wParam; + + if (!blInit || (DBGetContactSettingByte(hContact,"CList","NotOnList",0) == 1)) + { + ZeroMemory(&clmi, sizeof(clmi)); + clmi.cbSize = sizeof(clmi); + clmi.flags = CMIM_FLAGS | CMIF_GRAYED; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemAutoChat, (LPARAM)&clmi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemNotToChat, (LPARAM)&clmi); + } + else + { + BOOL boltunautochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, FALSE); + BOOL boltunnottochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, FALSE); + ZeroMemory(&clmi, sizeof(clmi)); + clmi.cbSize = sizeof(clmi); + clmi.flags = CMIM_FLAGS | CMIM_ICON | (boltunautochat ? CMIF_CHECKED : 0); + clmi.hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE((boltunautochat ? IDI_TICK : IDI_NOTICK)) ); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemAutoChat, (LPARAM)&clmi); + + clmi.flags = CMIM_FLAGS | CMIM_ICON | (boltunnottochat ? CMIF_CHECKED : 0); + clmi.hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE((boltunnottochat ? IDI_TICK : IDI_NOTICK)) ); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemNotToChat, (LPARAM)&clmi); + } + return 0; +} + +extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) +{ + pluginLink = link; + + mmi.cbSize=sizeof(struct MM_INTERFACE); + CallService(MS_SYSTEM_GET_MMI,0,(LPARAM)&mmi); + + path = new TCHAR[MAX_PATH]; + int len = GetModuleFileName(hInst, path, MAX_PATH); + if (len > MAX_PATH) + { + delete[] path; + TCHAR *path = new TCHAR[len]; + int len2 = GetModuleFileName(hInst, path, len); + if (len2 != len) + { + delete[] path; + return false; + } + } + *(_tcsrchr(path, _T('\\'))+1) = _T('\0'); + + /*initialize miranda hooks and services on options dialog*/ + hEventOptInitialise = HookEvent(ME_OPT_INITIALISE, MessageOptInit); + /*initialize miranda hooks and services*/ + hEventDbEventAdded = HookEvent(ME_DB_EVENT_ADDED, MessageEventAdded); + hEventPrebuild = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, MessagePrebuild); + + CreateServiceFunction(SERV_CONTACT_AUTO_CHAT, ContactClickAutoChat); + CreateServiceFunction(SERV_CONTACT_NOT_TO_CHAT, ContactClickNotToChat); + CreateServiceFunction(SERV_CONTACT_START_CHATTING, ContactClickStartChatting); + { + CLISTMENUITEM mi; + + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.position = -50010002; //TODO: check the warning + mi.flags = 0; + mi.hIcon = NULL; + mi.pszContactOwner = NULL; + mi.pszName = BOLTUN_AUTO_CHAT; + mi.pszService = SERV_CONTACT_AUTO_CHAT; + hMenuItemAutoChat = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi); + + mi.position = -50010001; //TODO: check the warning + mi.pszName = BOLTUN_NOT_TO_CHAT; + mi.pszService = SERV_CONTACT_NOT_TO_CHAT; + hMenuItemNotToChat = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi); + + mi.flags = CMIF_NOTOFFLINE; + mi.position = -50010000; //TODO: check the warning + mi.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_RECVMSG)); + mi.pszName = BOLTUN_START_CHATTING; + mi.pszService = SERV_CONTACT_START_CHATTING; + hMenuItemStartChatting = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi); + } + int line; + blInit = LoadMind(Config.MindFileName, line); + if(!blInit) + { + TCHAR path[2000]; + wsprintf(path, TranslateTS(FAILED_TO_LOAD_BASE), line, (const TCHAR*)Config.MindFileName); + MessageBox(NULL, path, TranslateTS(BOLTUN_ERROR), MB_ICONERROR|MB_TASKMODAL|MB_OK); + } + /*record for Uninstall plugin*/ + DBWriteContactSettingString(NULL, "Uninstall", BOLTUN_NAME, BOLTUN_KEY); + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + if (pTimer) + KillTimer(NULL, pTimer); + if(blInit) + { +#if 0 //No need to save, we don't have studying algorithm + if(Config.MindFileName && !SaveMind(Config.MindFileName)) + { +//This causes errors with development core when calling MessageBox. +//It seems that it's now a Boltun problem. +//So in case of saving error we will remain silent +#if 0 + TCHAR path[MAX_PATH]; + wsprintf(path, TranslateTS(FAILED_TO_SAVE_BASE), (const TCHAR*)Config.MindFileName); + TCHAR* err = TranslateTS(BOLTUN_ERROR); + MessageBox(NULL, path, err, MB_ICONERROR|MB_TASKMODAL|MB_OK);*/ +#endif + } +#endif + delete bot; + } + delete[] path; + return 0; +} diff --git a/plugins/Boltun/boltun.h b/plugins/Boltun/boltun.h new file mode 100644 index 0000000000..6063dc2310 --- /dev/null +++ b/plugins/Boltun/boltun.h @@ -0,0 +1,80 @@ +//*********************************************************** +// Copyright 2003-2008 Alexander S. Kiselev, Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef _BOLTUN_H +#define _BOLTUN_H + +//Should use different keys in UNICODE and ANSI builds, because usage of plugin +//with old (another) configs will cause crashes. +#ifdef _UNICODE +#define BOLTUN_KEY "BoltunW" +#else +#define BOLTUN_KEY "Boltun" +#endif + +//Service names +#define SERV_CONTACT_AUTO_CHAT "Boltun/ContactAutoChat" +#define SERV_CONTACT_NOT_TO_CHAT "Boltun/ContactNotToChat" +#define SERV_CONTACT_START_CHATTING "Boltun/ContactStartChatting" + +//Database keys +#define DB_CONTACT_BOLTUN_NOT_TO_CHAT "BoltunNotToChat" +#define DB_CONTACT_BOLTUN_AUTO_CHAT "BoltunAutoChat" +#define DB_CONTACT_WARNED "Warned" + +//Plugin group in settings +#define BOLTUN_GROUP "Message sessions" + +//Filename depends on UNICODE +#ifdef UNICODE +#define DEFAULT_MIND_FILE _T("boltun.mindw") +#else +#define DEFAULT_MIND_FILE _T("boltun.mind") +#endif + +//=============================================== +// These are strings for translation: +//=============================================== + +//Plugin name +#define BOLTUN_NAME "Boltun" + +#define PLUGIN_DESCRIPTION "Boltun, the chat bot in the russian language." + +#define MIND_FILE_DESC _T("Mind Files") +#define ALL_FILES_DESC _T("All Files") + +//UI strings +#define BOLTUN_AUTO_CHAT "Boltun/Auto Chat" +#define BOLTUN_NOT_TO_CHAT "Boltun/Not to Chat" +#define BOLTUN_START_CHATTING "Boltun/Start Chatting" + +#define DEFAULT_WARN_TEXT _T("Hello. I'm Boltun! I'll talk to you, while my owner is away. Please write without mistakes!") + +// Error messages +#define BOLTUN_ERROR _T("Boltun Error") +#define FAILED_TO_LOAD_BASE _T("Failed to load base of remarks. Error at line %d of %s. (Or few lines before).") +#define FAILED_TO_SAVE_BASE _T("Failed to save base of remarks to %s") + +//Settings tab names +#define TAB_GENERAL "General Settings" +#define TAB_ENGINE "Engine Settings" + +#endif /*_BOLTUN_H*/ diff --git a/plugins/Boltun/config.cpp b/plugins/Boltun/config.cpp new file mode 100644 index 0000000000..a59fc89d56 --- /dev/null +++ b/plugins/Boltun/config.cpp @@ -0,0 +1,159 @@ +//*********************************************************** +// Copyright 2003-2008 Alexander S. Kiselev, Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#include "config.h" + +#include +#include +#include + +#include "newpluginapi.h" +#include "m_database.h" +#include "m_langpack.h" +#include "boltun.h" + +//Database keys +#define DB_EVERYBODY "Everybody" +#define DB_NOT_IN_LIST "NotInList" +#define DB_AUTOAWAY "AutoAway" +#define DB_WARN "Warn" +#define DB_MARK_READ "MarkRead" +#define DB_WAIT_TIME "WaitTime" +#define DB_THINK_TIME "ThinkTime" +#define DB_PAUSE_DEPENDS "PauseDepends" +#define DB_PAUSE_RANDOM "PauseRandom" +#define DB_WARN_TEXT "WarnText" +#define DB_MIND_FILE_NAME "MindFileName" +#define DB_ENGINE_SILENT "SilentEngine" +#define DB_ENGINE_LOWERCASE "MakeLowerCase" +#define DB_ENGINE_UNDERSTAND_ALWAYS "UnderstandAlways" + +inline TCHAR* GetString(char* key, const TCHAR* def) +{ + DBVARIANT dbv; + TCHAR* val; + if(!DBGetContactSettingTString(NULL, BOLTUN_KEY, key, &dbv)) + { + size_t len = wcslen(dbv.ptszVal) + 1; + val = new TCHAR[len]; + _tcscpy_s(val, len, dbv.ptszVal); + DBFreeVariant(&dbv); + } + else + { + size_t len = wcslen(def) + 1; + val = new TCHAR[len]; + _tcscpy_s(val, len, def); + } + return val; +} + +inline const TCHAR* SetString(char* key, const TCHAR* value) +{ + size_t len = _tcslen(value) + 1; + TCHAR* val = new TCHAR[len]; + _tcscpy_s(val, len, value); + DBWriteContactSettingTString(NULL, BOLTUN_KEY, key, val); + return val; +} + +#define BUILDETTERS(x, str, def) \ + const bool BoltunConfig::Get##x() { \ + return DBGetContactSettingDword(NULL, BOLTUN_KEY, str, def) != 0; } \ + const bool BoltunConfig::Set##x(const bool value) { \ + DBWriteContactSettingDword(NULL, BOLTUN_KEY, str, value); \ + return value; } + +#define BUILDINTETTERS(x, str, def) \ + const int BoltunConfig::Get##x() { \ + return DBGetContactSettingDword(NULL, BOLTUN_KEY, str, def); } \ + const int BoltunConfig::Set##x(const int value) { \ + DBWriteContactSettingDword(NULL, BOLTUN_KEY, str, value); \ + return value; } + +#define BUILDSTRETTERS(x, str, def) \ + const TCHAR* BoltunConfig::Get##x() { \ + return GetString(str, def); } \ + const TCHAR* BoltunConfig::Set##x(const TCHAR* value) { \ + return SetString(str, value); } + +#define BUILDINIT(x) \ + x(&BoltunConfig::Get##x, &BoltunConfig::Set##x) + +BUILDETTERS(TalkWithNotInList, DB_NOT_IN_LIST, false); +BUILDETTERS(TalkWithEverybody, DB_EVERYBODY, false); +BUILDETTERS(TalkWarnContacts, DB_WARN, false); +BUILDETTERS(TalkEveryoneWhileAway, DB_AUTOAWAY, false); +BUILDETTERS(MarkAsRead, DB_MARK_READ, true); +BUILDINTETTERS(AnswerPauseTime, DB_WAIT_TIME, 2); +BUILDINTETTERS(AnswerThinkTime, DB_THINK_TIME, 4); +BUILDETTERS(PauseDepends, DB_PAUSE_DEPENDS, TRUE); +BUILDETTERS(PauseRandom, DB_PAUSE_RANDOM, TRUE); +BUILDSTRETTERS(WarnText, DB_WARN_TEXT, TranslateTS(DEFAULT_WARN_TEXT)); +BUILDSTRETTERS(MindFileName, DB_MIND_FILE_NAME, DEFAULT_MIND_FILE); +BUILDETTERS(EngineStaySilent, DB_ENGINE_SILENT, FALSE); +BUILDETTERS(EngineMakeLowerCase, DB_ENGINE_LOWERCASE, FALSE); +BUILDETTERS(EngineUnderstandAlways, DB_ENGINE_UNDERSTAND_ALWAYS, FALSE); + +BoltunConfig::BoltunConfig() + :BUILDINIT(TalkWithEverybody), + BUILDINIT(TalkWithNotInList), + BUILDINIT(TalkWarnContacts), + BUILDINIT(TalkEveryoneWhileAway), + BUILDINIT(MarkAsRead), + BUILDINIT(AnswerPauseTime), + BUILDINIT(AnswerThinkTime), + BUILDINIT(PauseDepends), + BUILDINIT(PauseRandom), + BUILDINIT(WarnText), + BUILDINIT(MindFileName), + BUILDINIT(EngineStaySilent), + BUILDINIT(EngineMakeLowerCase), + BUILDINIT(EngineUnderstandAlways) +{ + TalkWithEverybody.SetOwner(this); + TalkWithNotInList.SetOwner(this); + TalkWarnContacts.SetOwner(this); + TalkEveryoneWhileAway.SetOwner(this); + MarkAsRead.SetOwner(this); + AnswerPauseTime.SetOwner(this); + AnswerThinkTime.SetOwner(this); + PauseDepends.SetOwner(this); + PauseRandom.SetOwner(this); + WarnText.SetOwner(this); + MindFileName.SetOwner(this); + EngineStaySilent.SetOwner(this); + EngineMakeLowerCase.SetOwner(this); + EngineUnderstandAlways.SetOwner(this); +} + +BoltunConfig::~BoltunConfig() +{ +} + +class _BoltunConfigInit +{ +public: + BoltunConfig cfg; +}; + +_BoltunConfigInit inst; + +BoltunConfig &Config = inst.cfg; \ No newline at end of file diff --git a/plugins/Boltun/config.h b/plugins/Boltun/config.h new file mode 100644 index 0000000000..c5bb20e700 --- /dev/null +++ b/plugins/Boltun/config.h @@ -0,0 +1,157 @@ +//*********************************************************** +// Copyright 2003-2008 Alexander S. Kiselev, Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +class BoltunConfig; + +template +class Property +{ +public: + typedef const T (__thiscall BaseClass::*Getter)(); + typedef const T (__thiscall BaseClass::*Setter)(const T); +private: + const Getter getter; + const Setter setter; + BaseClass* owner; + bool cacheValid; + T cached; +public: + Property(Getter g, Setter s) + :getter(g), setter(s), cacheValid(false) + { + } + + void SetOwner(BaseClass* o) + { + owner = o; + } + + inline operator const T() + { + if (cacheValid) + return cached; + cached = (owner->*getter)(); + cacheValid = true; + return cached; + } + + inline const T operator= (const T& value) + { + cacheValid = true; + return (owner->*setter)(cached = value); + } +}; + +template +class PtrProperty +{ +public: + typedef const T* (__thiscall BaseClass::*Getter)(); + typedef const T* (__thiscall BaseClass::*Setter)(const T*); +private: + const Getter getter; + const Setter setter; + BaseClass* owner; + bool cacheValid; + const T* cached; +public: + PtrProperty(Getter g, Setter s) + :getter(g), setter(s), cacheValid(false), cached(NULL) + { + } + + ~PtrProperty() + { + delete cached; + } + + void SetOwner(BaseClass* o) + { + owner = o; + } + + inline operator const T*() + { + if (cacheValid) + return cached; + cached = (owner->*getter)(); + cacheValid = true; + return cached; + } + + inline const T* operator= (const T* value) + { + cacheValid = true; + delete cached; + cached = (owner->*setter)(value); + return cached; + } +}; + +class _BoltunConfigInit; + +#define BUILDDEFETTERS(x, typ) \ + const typ Get##x(); \ + const typ Set##x(const typ value); + +class BoltunConfig +{ + BUILDDEFETTERS(TalkWithEverybody, bool); + BUILDDEFETTERS(TalkWithNotInList, bool); + BUILDDEFETTERS(TalkWarnContacts, bool); + BUILDDEFETTERS(TalkEveryoneWhileAway, bool); + BUILDDEFETTERS(MarkAsRead, bool); + BUILDDEFETTERS(AnswerPauseTime, int); + BUILDDEFETTERS(AnswerThinkTime, int); + BUILDDEFETTERS(PauseDepends, bool); + BUILDDEFETTERS(PauseRandom, bool); + BUILDDEFETTERS(WarnText, TCHAR*); + BUILDDEFETTERS(MindFileName, TCHAR*); + BUILDDEFETTERS(EngineStaySilent, bool); + BUILDDEFETTERS(EngineMakeLowerCase, bool); + BUILDDEFETTERS(EngineUnderstandAlways, bool); + BoltunConfig(); + ~BoltunConfig(); + friend class _BoltunConfigInit; +public: + Property TalkWithEverybody; + Property TalkWithNotInList; + Property TalkWarnContacts; + Property TalkEveryoneWhileAway; + Property MarkAsRead; + Property AnswerPauseTime; + Property AnswerThinkTime; + Property PauseDepends; + Property PauseRandom; + PtrProperty WarnText; + PtrProperty MindFileName; + Property EngineStaySilent; + Property EngineMakeLowerCase; + Property EngineUnderstandAlways; +}; + +extern BoltunConfig &Config; + +#endif /* _CONFIG_H */ \ No newline at end of file diff --git a/plugins/Boltun/lang_pack.txt b/plugins/Boltun/lang_pack.txt new file mode 100644 index 0000000000..79b33c35f6 --- /dev/null +++ b/plugins/Boltun/lang_pack.txt @@ -0,0 +1,64 @@ +[Boltun] + +[Boltun, the chat bot in the russian language.] +, - . +[All Files] + +[Mind Files] + +[Boltun/Auto Chat] +/ +[Boltun/Not to Chat] +/ +[Boltun/Start Chatting] +/ +[Hello. I'm Boltun! I'll talk to you, while my owner is away. Please write without mistakes!] +. ! , . , ! +[Boltun Error] + +[Failed to load base of remarks. Error at line %d of %s. (Or few lines before).] + . %d %s. ( ). +[Failed to save base of remarks to %s] + %s +[Boltun Autochat everybody] + +[Boltun Autochat everybody not in contact list] + , +[Boltun Autochat everybody while away] + , +[Warn contacts Boltun is chatting] + +[Mark replied messages as read] + +[sec] + +[Warning text] + +[Time before the answer] + +[Typing time depends on message length (in chars)] + ( ) +[Typing time (for a message of 4 words):] + ( 4- ): +[Thinking time:] + : +[Typing and thinking time can be much longer] + +[Engine] + +[Base of remarks] + +[Save] + +[Reload] + +[Stay silent, if have no good aswers] +, +[Start answers with a lowercase letter] + . +[General Settings] + +[Engine Settings] + "" +[Don't use "I don't understand"-like answers] + " ?" \ No newline at end of file diff --git a/plugins/Boltun/mind.txt b/plugins/Boltun/mind.txt new file mode 100644 index 0000000000..01dcd6e5ba --- /dev/null +++ b/plugins/Boltun/mind.txt @@ -0,0 +1,142 @@ + . + +============================================================== + . + UNICODE . + : + +1) : + +"" +"" + +2) : + + (" ") +"" + + , + ('?' - , '.' - ). + '~', . + +3) : + + {" "} +"" + +4) : + + [""] +"" + +5) - : + + +"" + +6) : + + +" " + +7) : + + +" " + +8) ( ): + + +" " + +9) ( , 7): + + +" " + +10) + +@"" +" " + +11) + + +" ." + +============================================================== + + : + + , . + : + +0) ( ), 30 . +- - (11). 2-3 + . 30 +, . , +. + +1) (4) . + . , + . + + (4), . + +. 0 - . + +2) (1) 1). + 1. + +3) . +'.' '!' '?', '!' ':-!'. + + : + + 4) (4) . + 0. + + 5) (1). 1. + + 6) . + , ( "))" ). + : . + , , + (5). + , (6). + + 7) (2). + . 1. + . + + 8) (3). - (6). + , + . + ( , ). , . + 2. + +, , + . + + 9 10 , ", " +(aka " ") . + +9) (7). 3. + +10) (9). (9) - + " ". 3. + + , 9 10 . + + (10) + 1-10 . + + . + , +( 30 ). + (, ), +. + + , + . , . + . \ No newline at end of file diff --git a/plugins/Boltun/readme.txt b/plugins/Boltun/readme.txt new file mode 100644 index 0000000000..f20c3ec466 --- /dev/null +++ b/plugins/Boltun/readme.txt @@ -0,0 +1,124 @@ + 0.3.0 Unicode Alpha 7 + +08.01.2009. + + . + "beta" + +================================================ + + : + +readme.txt - +boltunw.dll - +boltun.mindw - +lang_pack.txt - . +mind.txt - . + +================================================ + +: + + boltunw.dll boltun.mindw Plugins . + lang_pack.txt . + +================================================ + + : + + : +" " - +" , " - , +" , " - , "" " " +" " - . +" " - , , . . +" " - , . +" " - , . +" ( )" - . " " 25 . +" " - , . +" " - 4- . + + : +" " - , . + "..." - . + "" - , . + "" - . +", " - , . +" " - . , , . +" " ?"" - . + +================================================ + + : + +08.01.2009: +- +- . +- ( !!!!). + +04.01.2009: +- +- +- + +30.09.2008: +- , . +- (.. ). + +29.09.2008: +- . +- . + +28.09.2008: +- . +- . +- , . + +19.09.2008: +- . + +14.09.2008: +- . + +13.09.2008: +- . +- , . +- , . +- . + +12.09.2008: +- , MRA. + +10.08.2008: +- " " +- , . +- "" . +- . +- ", " +- " " +- . +- . +- . +- . +- . +- . +- "-". +- , . +- . +- . + +28.07.2008: +- ( , ). +- Unicode ( ) +- "" , . +- " " . +- "" . +- +- , ( ). +- - ( ...). , Unicode-. + +================================================ + +: + +valentin.pavlyuchenko@gmail.com \ No newline at end of file diff --git a/plugins/Boltun/res/boltun.ico b/plugins/Boltun/res/boltun.ico new file mode 100644 index 0000000000..e6e619f9f2 Binary files /dev/null and b/plugins/Boltun/res/boltun.ico differ diff --git a/plugins/Boltun/res/smiles.dat b/plugins/Boltun/res/smiles.dat new file mode 100644 index 0000000000..10bd2b0d5b Binary files /dev/null and b/plugins/Boltun/res/smiles.dat differ diff --git a/plugins/Boltun/resource.h b/plugins/Boltun/resource.h new file mode 100644 index 0000000000..b4fa069c0e --- /dev/null +++ b/plugins/Boltun/resource.h @@ -0,0 +1,46 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Boltun.rc +// +#define IDM_HIDE 0x0010 +#define IDD_MAIN 101 +#define IDI_MAINBOLTUN 102 +#define IDD_ENGINE 103 +#define IDR_SMILES 105 +#define IDI_TICK 106 +#define IDI_NOTICK 107 +#define IDI_RECVMSG 108 +#define IDC_EVERYBODY 1000 +#define IDC_NOTINLIST 1001 +#define IDC_AUTOAWAY 1002 +#define IDC_WARN 1003 +#define IDC_MARKREAD 1004 +#define IDC_LWAITTIME 1005 +#define IDC_WAITTIME 1006 +#define IDC_LSEC 1007 +#define IDC_LWARN 1008 +#define IDC_WARNTXT 1009 +#define IDC_PLUGINRM 1010 +#define IDC_TXTREPLICPATH 1011 +#define IDC_MINDFILE 1012 +#define IDC_BTNPATH 1013 +#define IDC_BTNSAVE 1014 +#define IDC_BTNRELOAD 1015 +#define IDC_PAUSEDEPENDS 1016 +#define IDC_PAUSERANDOM 1017 +#define IDC_THINKTIME 1018 +#define IDC_LSEC2 1019 +#define IDC_ENGINE_SILENT 1020 +#define IDC_ENGINE_LOWERCASE 1021 +#define IDC_ENGINE_UNDERSTAND_ALWAYS 1022 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1023 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/plugins/CountryFlags/Info_Src.txt b/plugins/CountryFlags/Info_Src.txt new file mode 100644 index 0000000000..5c1b19be88 --- /dev/null +++ b/plugins/CountryFlags/Info_Src.txt @@ -0,0 +1,32 @@ + +Country Flags Plugin 0.1.0.3 for Miranda IM 0.7+ +------------------------------------------------------------------------ + Source Code + +Reminder: +'Country Flags' is released under the terms of the +GNU General Public License. +See 'Flags-License.txt' for more details. +'Country Flags' is copyright 2006-2007 by H. Herkenrath. + +Please notify me of any changes that improve +'Country Flags' or add new features. +If you have any questions on the code, feel free +to contact me at my email address. + + H. Herkenrath (hrathh at users.sourceforge.net) + + +Notes +------------------------------------------------------------------------ +The following files need to be changed to bump the version number: + +Info_Src.txt (1 place) +version.h (4 places) +m_flags.h (1 place) +m_flags.inc (1 place) +docs\Flags-Readme.txt (3 places) +docs\Flags-Translation.txt (2 or 3 places) +docs\Flags-Developer.txt (1 place) + + diff --git a/plugins/CountryFlags/License_Appendix.txt b/plugins/CountryFlags/License_Appendix.txt new file mode 100644 index 0000000000..c590c3f5fb --- /dev/null +++ b/plugins/CountryFlags/License_Appendix.txt @@ -0,0 +1,64 @@ + +Excecpt of GNU General Public License (Appendix): + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/plugins/CountryFlags/countrylistext.c b/plugins/CountryFlags/countrylistext.c new file mode 100644 index 0000000000..50978fdb97 --- /dev/null +++ b/plugins/CountryFlags/countrylistext.c @@ -0,0 +1,345 @@ +/* +Miranda IM Country Flags Plugin +Copyright (C) 2006-2007 H. Herkenrath + +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 (Flags-License.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "flags.h" + +static HANDLE hServiceGetList,hServiceGetByNumber; + +/************************* Services *******************************/ + +static struct CountryListEntry countries[]={ + {0 ,"Unspecified"}, + {9999,"Other"}, + {0xFFFF,"Unknown"}, + {93 ,"Afghanistan"}, + {355 ,"Albania"}, + {213 ,"Algeria"}, + {684 ,"American Samoa"}, + {376 ,"Andorra"}, + {244 ,"Angola"}, + {101 ,"Anguilla"}, + {102 ,"Antigua and Barbuda"}, + //{5902,"Antilles"}, /* removed */ + {54 ,"Argentina"}, + {374 ,"Armenia"}, + {297 ,"Aruba"}, + {247 ,"Ascension Island"}, + {61 ,"Australia"}, + {6721,"Australian Antarctic Territory"}, /* was missing */ + {43 ,"Austria"}, + {994 ,"Azerbaijan"}, + {103 ,"Bahamas"}, + {973 ,"Bahrain"}, + {880 ,"Bangladesh"}, + {104 ,"Barbados"}, + {120 ,"Barbuda"}, + {375 ,"Belarus"}, + {32 ,"Belgium"}, + {501 ,"Belize"}, + {229 ,"Benin"}, + {105 ,"Bermuda"}, + {975 ,"Bhutan"}, + {591 ,"Bolivia"}, + {387 ,"Bosnia and Herzegovina"}, + {267 ,"Botswana"}, + {55 ,"Brazil"}, + {106 ,"British Virgin Islands"}, + {673 ,"Brunei"}, + {359 ,"Bulgaria"}, + {226 ,"Burkina Faso"}, + {257 ,"Burundi"}, + {855 ,"Cambodia"}, + {237 ,"Cameroon"}, + {107 ,"Canada"}, + {178 ,"Canary Islands"}, + {238 ,"Cape Verde Islands"}, + {108 ,"Cayman Islands"}, + {236 ,"Central African Republic"}, + {235 ,"Chad"}, + {56 ,"Chile, Republic of"}, + {86 ,"China"}, + {672 ,"Christmas Island"}, + {6101,"Cocos-Keeling Islands"}, + //{6102,"Cocos (Keeling) Islands"}, /* removed */ + {57 ,"Colombia"}, + {2691,"Comoros"}, + {243 ,"Congo, Democratic Republic of (Zaire)"}, + {242 ,"Congo, Republic of the"}, + {682 ,"Cook Islands"}, + {506 ,"Costa Rica"}, + {225 ,"Cote d'Ivoire (Ivory Coast)"}, + {385 ,"Croatia"}, + {53 ,"Cuba"}, + {357 ,"Cyprus"}, + {420 ,"Czech Republic"}, + {45 ,"Denmark"}, + {246 ,"Diego Garcia"}, + {253 ,"Djibouti"}, + {109 ,"Dominica"}, + {110 ,"Dominican Republic"}, + {593 ,"Ecuador"}, + {20 ,"Egypt"}, + {503 ,"El Salvador"}, + {240 ,"Equatorial Guinea"}, + {291 ,"Eritrea"}, + {372 ,"Estonia"}, + {251 ,"Ethiopia"}, + {500 ,"Falkland Islands (Malvinas)"}, /* was "Falkland Islands" */ + {298 ,"Faroe Islands"}, /* was "Faeroe Islands" */ + {679 ,"Fiji"}, + {358 ,"Finland"}, + {33 ,"France"}, + {5901,"French Antilles"}, + {594 ,"French Guiana"}, + {689 ,"French Polynesia"}, + {241 ,"Gabon"}, + {220 ,"Gambia"}, + {995 ,"Georgia"}, + {49 ,"Germany"}, + {233 ,"Ghana"}, + {350 ,"Gibraltar"}, + {30 ,"Greece"}, + {299 ,"Greenland"}, + {111 ,"Grenada"}, + {590 ,"Guadeloupe"}, + {671 ,"Guam, US Territory of"}, + {5399,"Guantanamo Bay"}, /* was missing */ + {502 ,"Guatemala"}, + {224 ,"Guinea"}, + {245 ,"Guinea-Bissau"}, + {592 ,"Guyana"}, + {509 ,"Haiti"}, + {504 ,"Honduras"}, + {852 ,"Hong Kong"}, + {36 ,"Hungary"}, + {354 ,"Iceland"}, + {91 ,"India"}, + {62 ,"Indonesia"}, + {98 ,"Iran (Islamic Republic of)"}, + {964 ,"Iraq"}, + {353 ,"Ireland"}, + {972 ,"Israel"}, + {39 ,"Italy"}, + {112 ,"Jamaica"}, + {81 ,"Japan"}, + {962 ,"Jordan"}, + {705 ,"Kazakhstan"}, + {254 ,"Kenya"}, + {686 ,"Kiribati"}, + {850 ,"Korea, North"}, + {82 ,"Korea, South"}, + {965 ,"Kuwait"}, + {706 ,"Kyrgyzstan"}, + {856 ,"Laos"}, + {371 ,"Latvia"}, + {961 ,"Lebanon"}, + {266 ,"Lesotho"}, + {231 ,"Liberia"}, + {218 ,"Libyan Arab Jamahiriya"}, + {4101,"Liechtenstein"}, + {370 ,"Lithuania"}, + {352 ,"Luxembourg"}, + {853 ,"Macau"}, + {389 ,"Macedonia (F.Y.R.O.M.)"}, + {261 ,"Madagascar"}, + {265 ,"Malawi"}, + {60 ,"Malaysia"}, + {960 ,"Maldives"}, + {223 ,"Mali"}, + {356 ,"Malta"}, + {692 ,"Marshall Islands"}, + {596 ,"Martinique"}, + {222 ,"Mauritania"}, + {230 ,"Mauritius"}, + {269 ,"Mayotte Island"}, + {52 ,"Mexico"}, + {691 ,"Micronesia, Federated States of"}, + {373 ,"Moldova, Republic of"}, + {377 ,"Monaco"}, + {976 ,"Mongolia"}, + {382 ,"Montenegro, Republic of"}, /* was "Yugoslavia - Montenegro" */ + {113 ,"Montserrat"}, + {212 ,"Morocco"}, + {258 ,"Mozambique"}, + {95 ,"Myanmar"}, + {264 ,"Namibia"}, + {674 ,"Nauru"}, + {977 ,"Nepal"}, + {31 ,"Netherlands"}, + {599 ,"Netherlands Antilles"}, + {114 ,"Nevis"}, + {687 ,"New Caledonia"}, + {64 ,"New Zealand"}, + {505 ,"Nicaragua"}, + {227 ,"Niger"}, + {234 ,"Nigeria"}, + {683 ,"Niue"}, + {6722,"Norfolk Island"}, + {47 ,"Norway"}, + {968 ,"Oman"}, + {92 ,"Pakistan"}, + {680 ,"Palau"}, + {507 ,"Panama"}, + {675 ,"Papua New Guinea"}, + {595 ,"Paraguay"}, + {51 ,"Peru"}, + {63 ,"Philippines"}, + {48 ,"Poland"}, + {351 ,"Portugal"}, + {121 ,"Puerto Rico"}, + {974 ,"Qatar"}, + {262 ,"Reunion Island"}, + {40 ,"Romania"}, + {6701,"Rota Island"}, + {7 ,"Russia"}, + {250 ,"Rwanda"}, + {290 ,"Saint Helena"}, + {115 ,"Saint Kitts"}, + {1141,"Saint Kitts and Nevis"}, + {122 ,"Saint Lucia"}, + {508 ,"Saint Pierre and Miquelon"}, + {116 ,"Saint Vincent and the Grenadines"}, + {670 ,"Saipan Island (Northern Mariana Islands)"}, /* was "Saipan Island" */ + {685 ,"Samoa"}, /* was "Western Samoa" */ + {378 ,"San Marino"}, + {239 ,"Sao Tome and Principe"}, + {966 ,"Saudi Arabia"}, + {442 ,"Scotland"}, + {221 ,"Senegal"}, + {381 ,"Serbia, Republic of"}, /* was "Yugoslavia" */ + {248 ,"Seychelles"}, + {232 ,"Sierra Leone"}, + {65 ,"Singapore"}, + {421 ,"Slovakia"}, + {386 ,"Slovenia"}, + {677 ,"Solomon Islands"}, + {252 ,"Somalia"}, + {27 ,"South Africa"}, + {34 ,"Spain"}, + {94 ,"Sri Lanka"}, + {249 ,"Sudan"}, + {597 ,"Suriname"}, + {268 ,"Swaziland"}, + {46 ,"Sweden"}, + {41 ,"Switzerland"}, + {963 ,"Syrian Arab Republic"}, + {886 ,"Taiwan"}, + {708 ,"Tajikistan"}, + {255 ,"Tanzania"}, + {66 ,"Thailand"}, + {6702,"Tinian Island"}, + {228 ,"Togo"}, + {690 ,"Tokelau"}, + {676 ,"Tonga"}, + {117 ,"Trinidad and Tobago"}, + {216 ,"Tunisia"}, + {90 ,"Turkey"}, + {709 ,"Turkmenistan"}, + {118 ,"Turks and Caicos Islands"}, + {688 ,"Tuvalu"}, + {256 ,"Uganda"}, + {380 ,"Ukraine"}, + {971 ,"United Arab Emirates"}, + {44 ,"United Kingdom"}, + {598 ,"Uruguay"}, + {1 ,"USA"}, + {711 ,"Uzbekistan"}, + {678 ,"Vanuatu"}, + {379 ,"Vatican City"}, + {58 ,"Venezuela"}, + {84 ,"Vietnam"}, + {123 ,"Virgin Islands (USA)"}, + {441 ,"Wales"}, + {681 ,"Wallis and Futuna Islands"}, + {967 ,"Yemen"}, + //{3811,"Yugoslavia - Serbia"}, /* removed */ + {260 ,"Zambia"}, + {263 ,"Zimbabwe"}, +}; + +static int ServiceGetCountryByNumber(WPARAM wParam,LPARAM lParam) +{ + int i; + UNREFERENCED_PARAMETER(lParam); + for(i=0; i24) hash^=(szStr[i]>>(32-shift))&0x7F; + shift=(shift+5)&0x1F; + } + return hash; +#endif +} + +void InitCountryListExt(void) +{ + /* hack to replace built-in country list */ + DestroyServiceFunction((HANDLE)NameHashFunction(MS_UTILS_GETCOUNTRYLIST)); + DestroyServiceFunction((HANDLE)NameHashFunction(MS_UTILS_GETCOUNTRYBYNUMBER)); + hServiceGetList=CreateServiceFunction(MS_UTILS_GETCOUNTRYLIST,ServiceGetCountryList); + hServiceGetByNumber=CreateServiceFunction(MS_UTILS_GETCOUNTRYBYNUMBER,ServiceGetCountryByNumber); +} + +void UninitCountryListExt(void) +{ + DestroyServiceFunction(hServiceGetList); + DestroyServiceFunction(hServiceGetByNumber); +} diff --git a/plugins/CountryFlags/docs/Flags-Developer.txt b/plugins/CountryFlags/docs/Flags-Developer.txt new file mode 100644 index 0000000000..68c51a6d7c --- /dev/null +++ b/plugins/CountryFlags/docs/Flags-Developer.txt @@ -0,0 +1,48 @@ + +Country Flags 0.1.0.3 for Miranda IM 0.7+ +------------------------------------------------------------------------ + Developer Information + + Contents: ------------------------------- + | Translation, Services (API), + | Debug Symbols, Coding Language, Rebase Info + +Translation +----------------- + The translation string listing can be found in + 'Flags-Translation.txt'. + +Services (API) +----------------- + For more information about which service functions are offered by + 'Country Flags' and about how they can be used by your plugin, + please refer to 'm_flags.h'. + If you would like to use Delphi/Pascal please refer to 'm_flags.inc'. + + Please redirect any questions or extension whishes to me by e-mail: + hrathh at users.sourceforge.net + +Debug Symbols +----------------- + Debug symbols are also available for debugging purposes. + Copy the PDB-files in the SDK-zip into the same directory as the + corresponding DLL-files. + To debug crashes the supplied MAP-file file might be helpful. + +Coding Language +----------------- + 'Country Flags' was written using Microsoft Visual C++ 6.0 SP6 + and the Microsoft Platform SDK shipped along with it. + +Rebase Info +----------------- + 'Country Flags' has set its base address to: + 0x24200000 + + Please avoid using this base address for your plugins because it will + slow down the startup of Miranda IM. + + Using Microsoft Visual C++, the base address can be configured at: + 'Project' -> 'Settings' -> 'Linker' -> 'Output' -> 'Base Address' + +H. Herkenrath (hrathh at users.sourceforge.net) diff --git a/plugins/CountryFlags/docs/Flags-License.txt b/plugins/CountryFlags/docs/Flags-License.txt new file mode 100644 index 0000000000..a726a52df1 --- /dev/null +++ b/plugins/CountryFlags/docs/Flags-License.txt @@ -0,0 +1,278 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. diff --git a/plugins/CountryFlags/docs/Flags-Readme.txt b/plugins/CountryFlags/docs/Flags-Readme.txt new file mode 100644 index 0000000000..d6a2182fc6 --- /dev/null +++ b/plugins/CountryFlags/docs/Flags-Readme.txt @@ -0,0 +1,140 @@ + +Country Flags 0.1.0.3 +------------------------------------------------------------------------ + Plugin for Miranda IM 0.7 and + + + Plugin Info: ---------------------------- + | Version: 0.1.0.3 + | Filename: flags.dll + | Author: H. Herkenrath (hrathh at users.sourceforge.net) + | Description: Service offering misc country utilities as + | flag icons and a IP-to-Country database. + + Contents: ------------------------------- + | Features, Requirements, Usage, Installation, + | Bugs and Wishes, Version History, License and Copyright + +Features +---------------------- + + Provides country utility services for other plugins (Flag Icons, IP-To-Country) + + Shows country flags as extra images on contact list + + Shows country flags as status icons on message windows + + Flag icon can be hidden if no country can be determined + + Flag icon is automatically refreshed when user details are updated + + Unicode compatible + + Automatic installation of all files, just unzip into Plugins directory + +Requirements +---------------------- + -> Miranda IM 0.7+: + Miranda IM is needed in version 0.7 or greater. + +Usage +---------------------- + Country Flags Provider does not add much functionality by itself. + It offers services for other plugins to use. + + To show country flags on your contact list or + on your message window open the options and go here: + 'Contact List' -> 'Country Flags' + + The country flag icons can be viewed here: + 'Customize' -> 'Icons' + +Installation +---------------------- + Find 'miranda32.exe' on your computer. + + Just copy all the contents of the zip-file as they are into the 'Plugins' directory + in the Miranda IM folder. + 'Country Flags' will detect the files and move them into the appropriate + directories on it's first run. + + You can also do all the installation by hand, if you want to: + + Main Plugin: Copy the file 'flags.dll' into the 'Plugins' directory + in the Miranda IM folder. + + The Unicode version of the plugin will only work on Windows NT/2000/XP, + Windows Server 2003, Windows Vista or later with an installed + Unicode version of Miranda IM. + To use it on Windows 95/98/Me, please download the ANSI version of the plugin. + + Documentation: The txt-files should be moved along with the SDK-zip into the + 'Docs' directory in the Miranda IM folder. + + That's it! + +Bugs and Wishes +---------------------- + Feel free to mail me your wishes about 'Language Pack Manager' and tell + me all the bugs you may find. + My email address is: hrathh at users.sourceforge.net + +Version History +---------------------- + 0.1.0.3 - really fixed those nasty crashes + - lightning-like speed due to buffered IP-database access + - option to turn-off usage of ip-to-country database + 0.1.0.2 - another try to fix those crashes + - refreshs icons on user details update + - optionally shows nothing if no country can be determined for a contact + 0.1.0.1 - try to fix those extraimg crashes + - fixed: implemented extra image column selector properly + - fixed: heavy crash on Unicode startup + (search on garbage might cross page-boundary) + - rewritten flags as status icons + - reimplemented country lookup + - added map-file to SDK package + 0.1.0.0 - Initial release + +License and Copyright +---------------------- + 'Country Flags' is released under the terms of the + GNU General Public License. + See 'Flags-License.txt' for more details. + + Copyright (c) 2006-2007 by H. Herkenrath. All rights reserved. + + This service includes the IP-to-Country Database + provided by WebHosting.info (http://www.webhosting.info), + available from http://ip-to-country.webhosting.info. + Copyright (c) 2003 Direct Information Pvt. Ltd. All rights Reserved. + Included Version: 05-03-2007, will be updated regularly. + + The included Huffman encodig algorithm is + Copyright (c) 2003-2006 Marcus Geelnard. + + The included default flag icons are public domain. + Flag Icons - http://www.famfamfam.com (created by Mark James) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +H. Herkenrath (hrathh at users.sourceforge.net) diff --git a/plugins/CountryFlags/docs/Flags-Translation.txt b/plugins/CountryFlags/docs/Flags-Translation.txt new file mode 100644 index 0000000000..15c1728c0d --- /dev/null +++ b/plugins/CountryFlags/docs/Flags-Translation.txt @@ -0,0 +1,74 @@ +Country Flags 0.1.0.3 for Miranda IM 0.7+ +------------------------------------------------------------------------ + Translator Information + + Contents: ------------------------------- + | General Info, String Listing + +General Info +----------------------------- + 'Country Flags' can be translated using Miranda IM + language files. + + Put the following strings in a file called 'langpack_.txt' + in the Miranda IM directory and translate them into your + language. + If you need more info on Miranda IM language files visit: + http://miranda.svn.sourceforge.net/viewvc/*checkout*/miranda/trunk/miranda/i18n/readme.txt + +String Listing +----------------------------- + +; --- Plugin: Country Flags 0.1.0.3 (German) --- +; Translation by hrathh +; Please report any mistakes or missing strings in here. + +[Country Flags] +Lnderflaggen +[Service offering misc country utilities as flag icons and a IP-to-Country database.] +Bietet verschiedene lnderspezifische Dienste wie Flaggensymbole und IP-to-Country. +[Country Flags Plugin] +Lnderflaggen-Plugin +[The Country Flags Plugin can not be loaded. It requires Miranda IM %hs or later.] +Der Lnderflaggen-Plugin kann nicht geladen werden. Er bentigt Miranda IM %hs oder neuer. + +; Countries +; Most country names are the same as used in miranda32.exe, +; except the following corrections: +[Australian Antarctic Territory] +Australisches Antarktis-Territorium +[Falkland Islands (Malvinas)] +Falklandinseln (Malwinen) +[Faroe Islands] +Frer-Inseln +[Guantanamo Bay] +Guantanamo-Bucht +[Montenegro, Republic of] +Montenegro +[Saipan Island (Northern Mariana Islands)] +Saipan Insel (Nrdliche Marianen) +;[Samoa] +[Serbia, Republic of] +Serbien + +; Options +;[Contact List] +;[Country Flags] +[Show country flag as &status icon on message window] +Zeige Lnderflagge in der Statuszeile im Nachrichtenfenster +[Show country flag as &extra image on contact list] +Zeige Lnderflagge als Spalte in der &Kontaktliste +[In following contact list &column:] +Verwende folgende &Spalte: +[Advanced #%u] +Erweitert #%u +[Use &IP-to-country database for country detection] +IP-Datenbank zur Bestimmung des Landes verwenden +[Use &unknown flag if the country can not be determined] +"Unbekannt" anzeigen, wenn Land nicht bestimmbar + + +; --- + + +H. Herkenrath (hrathh at users.sourceforge.net) diff --git a/plugins/CountryFlags/extraimg.c b/plugins/CountryFlags/extraimg.c new file mode 100644 index 0000000000..cd50cc2ccb --- /dev/null +++ b/plugins/CountryFlags/extraimg.c @@ -0,0 +1,495 @@ +/* +Miranda IM Country Flags Plugin +Copyright (C) 2006-1007 H. Herkenrath + +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 (Flags-License.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "flags.h" + +/* Services */ +static HANDLE hServiceDetectContactOrigin; +/* Extra Image */ +static HANDLE hHookExtraRebuild,hHookExtraApply; +/* Status Icon */ +static HANDLE hHookMsgWndEvent,hHookIconsChanged; +/* Options */ +static HANDLE hHookOptInit,hHookSettingChanged; +/* Misc */ +extern HINSTANCE hInst; +extern int nCountriesCount; +extern struct CountryListEntry *countries; +static HANDLE hHookModulesLoaded; + +/************************* Services *******************************/ + +static int ServiceDetectContactOriginCountry(WPARAM wParam,LPARAM lParam) +{ + int countryNumber=0xFFFF; + char *pszProto; + UNREFERENCED_PARAMETER(lParam); + pszProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0); + /* ip detect */ + if(DBGetContactSettingByte(NULL,"Flags","UseIpToCountry",SETTING_USEIPTOCOUNTRY_DEFAULT)) + countryNumber=ServiceIpToCountry(DBGetContactSettingDword((HANDLE)wParam,pszProto,"RealIP",0),0); + /* fallback */ + if(countryNumber==0xFFFF) + countryNumber=DBGetContactSettingWord((HANDLE)wParam,pszProto,"Country",0); + if(countryNumber==0 || countryNumber==0xFFFF) + countryNumber=DBGetContactSettingWord((HANDLE)wParam,pszProto,"CompanyCountry",0); + return (countryNumber==0)?0xFFFF:countryNumber; +} + +/************************* Extra Image ****************************/ + +#define EXTRAIMAGE_REFRESHDELAY 100 /* time for which setting changes are buffered */ + +static HANDLE *phExtraImages; +static BYTE idExtraColumn; + +static void CALLBACK SetExtraImage(LPARAM lParam) +{ + IconExtraColumn iec; + int countryNumber,index; + if(DBGetContactSettingByte(NULL,"Flags","ShowExtraImgFlag",SETTING_SHOWEXTRAIMGFLAG_DEFAULT)) { + /* get contact's country */ + iec.hImage=INVALID_HANDLE_VALUE; + countryNumber=ServiceDetectContactOriginCountry((WPARAM)lParam,0); + /* get icon */ + if(phExtraImages!=NULL) /* too early? */ + if(countryNumber!=0xFFFF || DBGetContactSettingByte(NULL,"Flags","UseUnknownFlag",SETTING_USEUNKNOWNFLAG_DEFAULT)) { + index=CountryNumberToIndex(countryNumber); + /* icon not yet loaded? */ + if(phExtraImages[index]==INVALID_HANDLE_VALUE) { + HICON hIcon; + hIcon=LoadFlagIcon(countryNumber); + if(hIcon!=NULL) phExtraImages[index]=(HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON,(WPARAM)hIcon,0); + CallService(MS_SKIN2_RELEASEICON,(WPARAM)hIcon,0); /* does NULL check */ + } + iec.hImage=phExtraImages[index]; + } + /* choose column */ + iec.cbSize=sizeof(iec); + iec.ColumnType=idExtraColumn; + CallService(MS_CLIST_EXTRA_SET_ICON,(WPARAM)lParam,(LPARAM)&iec); + } +} + +// always call in context of main thread +static void RemoveExtraImages(void) +{ + IconExtraColumn iec; + register HANDLE hContact; + /* choose column */ + iec.cbSize=sizeof(iec); + iec.ColumnType=idExtraColumn; + iec.hImage=INVALID_HANDLE_VALUE; + /* enum all contacts */ + hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); + while(hContact!=NULL) { + /* invalidate icon */ + CallService(MS_CLIST_EXTRA_SET_ICON,(WPARAM)hContact,(LPARAM)&iec); + hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0); + } +} + +// always call in context of main thread +static void EnsureExtraImages(void) +{ + register HANDLE hContact; + BYTE idMaxExtraCol,idExtraColumnNew; + /* choose column */ + idMaxExtraCol=(BYTE)CallService(MS_CLUI_GETCAPS,0,CLUIF2_EXTRACOLUMNCOUNT); /* 1-based count */ + if(idMaxExtraCol==(BYTE)CallService(MS_CLUI_GETCAPS,0,CLUIF2_USEREXTRASTART)) /* same flags if not present */ + idMaxExtraCol=EXTRA_ICON_ADV2; /* zero if not present */ + idExtraColumnNew=DBGetContactSettingRangedByte(NULL,"Flags","ExtraImgFlagColumn",SETTING_EXTRAIMGFLAGCOLUMN_DEFAULT,1,idMaxExtraCol); + /* clear previous column */ + if(idExtraColumnNew!=idExtraColumn) RemoveExtraImages(); + idExtraColumn=idExtraColumnNew; + /* enum all contacts */ + hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); + while(hContact!=NULL) { + CallFunctionBuffered(SetExtraImage,(LPARAM)hContact,TRUE,EXTRAIMAGE_REFRESHDELAY); + hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0); + } +} + +static void CALLBACK UpdateExtraImages(LPARAM lParam) +{ + UNREFERENCED_PARAMETER(lParam); + if(DBGetContactSettingByte(NULL,"Flags","ShowExtraImgFlag",SETTING_SHOWEXTRAIMGFLAG_DEFAULT)) + EnsureExtraImages(); + else RemoveExtraImages(); +} + +static int ExtraListRebuild(WPARAM wParam,LPARAM lParam) +{ + BYTE idMaxExtraCol; + int i; + UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(lParam); + OutputDebugStringA("REBUILD EXTRA\n"); + /* invalidate icons */ + if(phExtraImages!=NULL) + for(i=0;iuType) { + case MSG_WINDOW_EVT_OPENING: + case MSG_WINDOW_EVT_CLOSE: + { int countryNumber; + if(msgwe->hContact==NULL || !ServiceExists(MS_MSG_ADDICON)) break; /* sanity check */ + countryNumber=ServiceDetectContactOriginCountry((WPARAM)msgwe->hContact,0); + if(DBGetContactSettingByte(NULL,"Flags","ShowStatusIconFlag",SETTING_SHOWSTATUSICONFLAG_DEFAULT)) { + if(msgwe->uType==MSG_WINDOW_EVT_OPENING) SetStatusIcon(msgwe->hContact,countryNumber); + else UnsetStatusIcon(msgwe->hContact,countryNumber); + } + /* ensure it is hidden, RemoveStatusIcons() only enums currently opened ones */ + else UnsetStatusIcon(msgwe->hContact,countryNumber); + } + } + return 0; +} + +static void CALLBACK UpdateStatusIcons(LPARAM lParam) +{ + MessageWindowInputData msgwi; /* input */ + MessageWindowData msgw; /* output */ + BOOL fShow; + int countryNumber; + UNREFERENCED_PARAMETER(lParam); + + msgwi.cbSize=sizeof(msgwi); + msgw.cbSize=sizeof(msgw); + msgwi.uFlags=MSG_WINDOW_UFLAG_MSG_BOTH; + /* enum all opened message windows */ + fShow=DBGetContactSettingByte(NULL,"Flags","ShowStatusIconFlag",SETTING_SHOWSTATUSICONFLAG_DEFAULT); + msgwi.hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); + while(msgwi.hContact!=NULL) { + /* is a message window opened for this contact? */ + if(!CallService(MS_MSG_GETWINDOWDATA,(WPARAM)&msgwi,(LPARAM)&msgw) && msgw.uState&MSG_WINDOW_STATE_EXISTS) { + countryNumber=ServiceDetectContactOriginCountry((WPARAM)msgwi.hContact,0); + if(fShow) SetStatusIcon(msgwi.hContact,countryNumber); + else UnsetStatusIcon(msgwi.hContact,countryNumber); + } + msgwi.hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)msgw.hContact,0); + } +} + +static int StatusIconsChanged(WPARAM wParam,LPARAM lParam) +{ + UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(lParam); + if(ServiceExists(MS_MSG_ADDICON)) + if(DBGetContactSettingByte(NULL,"Flags","ShowStatusIconFlag",SETTING_SHOWSTATUSICONFLAG_DEFAULT)) + CallFunctionBuffered(UpdateStatusIcons,0,FALSE,STATUSICON_REFRESHDELAY); + return 0; +} + +/************************* Options ************************************/ + +#define M_ENABLE_SUBCTLS (WM_APP+1) + +static int CALLBACK ExtraImgOptDlgProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + UNREFERENCED_PARAMETER(wParam); + switch(msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + /* init checkboxes */ + { BOOL val; + /* Status Icon */ + if(ServiceExists(MS_MSG_ADDICON)) val=DBGetContactSettingByte(NULL,"Flags","ShowStatusIconFlag",SETTING_SHOWSTATUSICONFLAG_DEFAULT)!=0; + else EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK_SHOWSTATUSICONFLAG),val=FALSE); + CheckDlgButton(hwndDlg,IDC_CHECK_SHOWSTATUSICONFLAG,val); + /* Extra Image */ + if(ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) val=DBGetContactSettingByte(NULL,"Flags","ShowExtraImgFlag",SETTING_SHOWEXTRAIMGFLAG_DEFAULT)!=0; + else EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK_SHOWEXTRAIMGFLAG),val=FALSE); + CheckDlgButton(hwndDlg,IDC_CHECK_SHOWEXTRAIMGFLAG,val); + /* Unknown Flag */ + val=DBGetContactSettingByte(NULL,"Flags","UseUnknownFlag",SETTING_USEUNKNOWNFLAG_DEFAULT)!=0; + CheckDlgButton(hwndDlg,IDC_CHECK_USEUNKNOWNFLAG,val); + /* IP-to-country */ + val=DBGetContactSettingByte(NULL,"Flags","UseIpToCountry",SETTING_USEIPTOCOUNTRY_DEFAULT)!=0; + CheckDlgButton(hwndDlg,IDC_CHECK_USEIPTOCOUNTRY,val); + } + /* init combobox */ + { HWND hwndCombo; + TCHAR szItem[64]; + BYTE idColumn,idSavedColumn; + BYTE idMaxExtraCol,idAdvExtraColStart; + int index; + hwndCombo=GetDlgItem(hwndDlg,IDC_COMBO_EXTRAIMGFLAGCOLUMN); + idSavedColumn=DBGetContactSettingByte(NULL,"Flags","ExtraImgFlagColumn",SETTING_EXTRAIMGFLAGCOLUMN_DEFAULT); + idMaxExtraCol=(BYTE)CallService(MS_CLUI_GETCAPS,0,CLUIF2_EXTRACOLUMNCOUNT); /* 1-based count */ + idAdvExtraColStart=(BYTE)CallService(MS_CLUI_GETCAPS,0,CLUIF2_USEREXTRASTART); /* 1-based id */ + /* init */ + SendMessage(hwndCombo,CB_SETLOCALE,(LCID)CallService(MS_LANGPACK_GETLOCALE,0,0),0); /* for sort order */ + SendMessage(hwndCombo,CB_INITSTORAGE,idMaxExtraCol-idAdvExtraColStart+3,(idMaxExtraCol-idAdvExtraColStart+3)*SIZEOF(szItem)); + /* Advanced #1,#2 */ + { const BYTE columnIds[]={EXTRA_ICON_ADV1,EXTRA_ICON_ADV2}; + for(idColumn=0;idColumncode) { + case PSN_APPLY: /* setting change hook will pick these up */ + DBWriteContactSettingByte(NULL,"Flags","UseUnknownFlag",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_CHECK_USEUNKNOWNFLAG)!=0)); + DBWriteContactSettingByte(NULL,"Flags","UseIpToCountry",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_CHECK_USEIPTOCOUNTRY)!=0)); + /* Status Icon */ + if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHECK_SHOWSTATUSICONFLAG))) + DBWriteContactSettingByte(NULL,"Flags","ShowStatusIconFlag",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_CHECK_SHOWSTATUSICONFLAG)!=0)); + /* Extra Image */ + if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHECK_SHOWEXTRAIMGFLAG))) + DBWriteContactSettingByte(NULL,"Flags","ShowExtraImgFlag",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_CHECK_SHOWEXTRAIMGFLAG)!=0)); + { int index; + index=SendDlgItemMessage(hwndDlg,IDC_COMBO_EXTRAIMGFLAGCOLUMN,CB_GETCURSEL,0,0); + if(index!=LB_ERR) DBWriteContactSettingByte(NULL,"Flags","ExtraImgFlagColumn",(BYTE)SendDlgItemMessage(hwndDlg,IDC_COMBO_EXTRAIMGFLAGCOLUMN,CB_GETITEMDATA,index,0)); + } + return TRUE; + } + break; + } + return FALSE; +} + +static int ExtraImgOptInit(WPARAM wParam,LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + static UINT expertOnlyControls[]={IDC_CHECK_USEIPTOCOUNTRY}; + UNREFERENCED_PARAMETER(lParam); + ZeroMemory(&odp,sizeof(odp)); + odp.cbSize=sizeof(odp); + odp.hInstance=hInst; + odp.pszTemplate=MAKEINTRESOURCEA(IDD_OPT_EXTRAIMG); + odp.position=900000002; + odp.ptszGroup=_T("Contact List"); /* autotranslated */ + odp.ptszTitle=_T("Country Flags"); /* autotranslated */ + odp.ptszTab=_T("Country Flags"); /* autotranslated, can be made a tab */ + odp.flags=ODPF_BOLDGROUPS|ODPF_TCHAR; + odp.pfnDlgProc=ExtraImgOptDlgProc; + odp.expertOnlyControls=expertOnlyControls; + odp.nExpertOnlyControls=SIZEOF(expertOnlyControls); + CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp); + return 0; +} + +static int ExtraImgSettingChanged(WPARAM wParam,LPARAM lParam) +{ + DBCONTACTWRITESETTING *dbcws=(DBCONTACTWRITESETTING*)lParam; + if((HANDLE)wParam==NULL) { + if(!lstrcmpA(dbcws->szModule,"Flags")) { + /* Extra Image */ + if(!lstrcmpA(dbcws->szSetting,"ShowExtraImgFlag") || + !lstrcmpA(dbcws->szSetting,"ExtraImgFlagColumn") || + !lstrcmpA(dbcws->szSetting,"UseUnknownFlag") || + !lstrcmpA(dbcws->szSetting,"UseIpToCountry")) + if(ServiceExists(MS_CLIST_EXTRA_SET_ICON)) + CallFunctionBuffered(UpdateExtraImages,0,FALSE,EXTRAIMAGE_REFRESHDELAY); + /* Status Icon */ + if(!lstrcmpA(dbcws->szSetting,"ShowStatusIconFlag") || + !lstrcmpA(dbcws->szSetting,"UseUnknownFlag") || + !lstrcmpA(dbcws->szSetting,"UseIpToCountry")) + if(ServiceExists(MS_MSG_ADDICON)) + CallFunctionBuffered(UpdateStatusIcons,0,FALSE,STATUSICON_REFRESHDELAY); + } + } + /* user details update */ + else if(!lstrcmpA(dbcws->szSetting,"RealIP") || + !lstrcmpA(dbcws->szSetting,"Country") || + !lstrcmpA(dbcws->szSetting,"CompanyCountry")) { + /* Extra Image */ + if(ServiceExists(MS_CLIST_EXTRA_SET_ICON)) + CallFunctionBuffered(SetExtraImage,(LPARAM)wParam,TRUE,EXTRAIMAGE_REFRESHDELAY); + /* Status Icon */ + if(ServiceExists(MS_MSG_ADDICON)) + CallFunctionBuffered(UpdateStatusIcons,0,FALSE,STATUSICON_REFRESHDELAY); + } + return 0; +} + +/************************* Misc ***********************************/ + +static int ExtraImgModulesLoaded(WPARAM wParam,LPARAM lParam) +{ + UNREFERENCED_PARAMETER(wParam); + UNREFERENCED_PARAMETER(lParam); + /* Options */ + if(ServiceExists("DBEditorpp/RegisterSingleModule")) + CallService("DBEditorpp/RegisterSingleModule",(WPARAM)"Flags",0); + /* Extra Image */ + if(ServiceExists(MS_CLIST_EXTRA_SET_ICON)) { + int i; + BYTE idMaxExtraCol; + phExtraImages=(HANDLE*)mir_alloc(nCountriesCount*sizeof(HANDLE)); + /* invalidate icons */ + if(phExtraImages!=NULL) + for(i=0;i +#define NONAMELESSUNION +#include /* for ImageList functions */ +#define NOWIN2K +#include +#define MIRANDA_VER 0x0700 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define FLAGS_NOHELPERFUNCTIONS +#include "m_flags.h" +#include "resource.h" + +#if defined(_MSC_VER) && !defined(FASTCALL) + #define FASTCALL __fastcall +#else + #define FASTCALL +#endif +#if defined(_DEBUG) + #undef FASTCALL + #define FASTCALL +#endif + +/* countrylistext.c */ +void InitCountryListExt(void); +void UninitCountryListExt(void); + +/* huffman.c */ +#ifdef HUFFMAN_ENCODE + int Huffman_Compress(unsigned char *in,unsigned char *out,unsigned int insize ); +#endif +void Huffman_Uncompress(unsigned char *in,unsigned char *out,unsigned int insize,unsigned int outsize); + +/* icons.c */ +HICON FASTCALL LoadFlagIcon(int countryNumber); +int FASTCALL CountryNumberToIndex(int countryNumber); +void InitIcons(void); +void UninitIcons(void); + +/* ip2country.c */ +int ServiceIpToCountry(WPARAM wParam,LPARAM lParam); +void InitIpToCountry(void); +void UninitIpToCountry(void); + +/* extraimg.c */ +void InitExtraImg(void); +void UninitExtraImg(void); + +/* utils.c */ +typedef void (CALLBACK *BUFFEREDPROC)(LPARAM lParam); +#ifdef _DEBUG + void _CallFunctionBuffered(BUFFEREDPROC pfnBuffProc,const char *pszProcName,LPARAM lParam,BOOL fAccumulateSameParam,UINT uElapse); + #define CallFunctionBuffered(proc,param,acc,elapse) _CallFunctionBuffered(proc,#proc,param,acc,elapse) +#else + void _CallFunctionBuffered(BUFFEREDPROC pfnBuffProc,LPARAM lParam,BOOL fAccumulateSameParam,UINT uElapse); + #define CallFunctionBuffered(proc,param,acc,elapse) _CallFunctionBuffered(proc,param,acc,elapse) +#endif +void PrepareBufferedFunctions(void); +void KillBufferedFunctions(void); diff --git a/plugins/CountryFlags/flags.sln b/plugins/CountryFlags/flags.sln new file mode 100644 index 0000000000..1903a8eb95 --- /dev/null +++ b/plugins/CountryFlags/flags.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flags", "flags.vcxproj", "{0966244A-B8FD-FF88-DA2F-6A8332BCD82F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Bin Converter|Win32 = Bin Converter|Win32 + Debug Unicode|Win32 = Debug Unicode|Win32 + Debug|Win32 = Debug|Win32 + Release Unicode|Win32 = Release Unicode|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Bin Converter|Win32.ActiveCfg = Bin Converter|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Bin Converter|Win32.Build.0 = Bin Converter|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Debug|Win32.ActiveCfg = Debug|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Debug|Win32.Build.0 = Debug|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Release|Win32.ActiveCfg = Release|Win32 + {0966244A-B8FD-FF88-DA2F-6A8332BCD82F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/CountryFlags/flags.vcxproj b/plugins/CountryFlags/flags.vcxproj new file mode 100644 index 0000000000..18ab33ade6 --- /dev/null +++ b/plugins/CountryFlags/flags.vcxproj @@ -0,0 +1,408 @@ + + + + + Bin Converter + Win32 + + + Debug Unicode + Win32 + + + Debug + Win32 + + + Release Unicode + Win32 + + + Release + Win32 + + + + + + + + + DynamicLibrary + false + MultiByte + + + DynamicLibrary + false + Unicode + true + + + DynamicLibrary + false + MultiByte + true + + + DynamicLibrary + false + MultiByte + + + DynamicLibrary + false + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + true + + + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + true + + + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + false + true + + + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + false + true + + + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + true + + + + MultiThreadedDebug + Default + false + Disabled + true + Level4 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + _DEBUG;UNICODE;WIN32;_WINDOWS;_USRDLL;STRICT;FLAGS_EXPORTS;%(PreprocessorDefinitions) + _MBCS;NO_STRICT;%(UndefinePreprocessorDefinitions) + true + $(IntDir)$(TargetName).pch + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\temp/Debug/Unicode\flags.tlb + true + Win32 + + + 0x0809 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + _DEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + + + true + + + true + true + true + Console + uuid.lib;OLDNAMES;%(IgnoreSpecificDefaultLibraries) + flags.def + $(IntDir)$(TargetName).lib + 0x24200000 + comctl32.lib;%(AdditionalDependencies) + /mapinfo:lines /mapinfo:lines + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level4 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + BINCONV;HUFFMAN_ENCODE;_DEBUG;WIN32;_WINDOWS;_USRDLL;STRICT;FLAGS_EXPORTS;%(PreprocessorDefinitions) + NO_STRICT;%(UndefinePreprocessorDefinitions) + true + $(IntDir)$(TargetName).pch + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\temp/BinConv\flags.tlb + true + Win32 + + + 0x0809 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + true + + + true + true + true + Console + uuid.lib;OLDNAMES;%(IgnoreSpecificDefaultLibraries) + flags.def + $(IntDir)$(TargetName).lib + 0x25000000 + comctl32.lib;%(AdditionalDependencies) + /mapinfo:lines + + + + + MultiThreadedDLL + OnlyExplicitInline + true + true + Full + true + Level4 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + NDEBUG;WIN32;_WINDOWS;_USRDLL;STRICT;ASSOCMGR_EXPORTS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + NO_STRICT;%(UndefinePreprocessorDefinitions) + true + /opt:nowin98 + $(IntDir)$(TargetName).pch + true + Size + + + true + NDEBUG;%(PreprocessorDefinitions) + .\temp/Release/ANSI\flags.tlb + false + Win32 + + + 0x0809 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + NDEBUG;%(PreprocessorDefinitions) + + + true + + + true + true + true + Console + uuid.lib;OLDNAMES;%(IgnoreSpecificDefaultLibraries) + flags.def + $(IntDir)$(TargetName).lib + true + 0x24200000 + comctl32.lib;%(AdditionalDependencies) + /ignore:4078 + true + true + + + + + MultiThreadedDLL + OnlyExplicitInline + true + true + Full + true + Level4 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + NDEBUG;UNICODE;WIN32;_WINDOWS;_USRDLL;STRICT;ASSOCMGR_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + _MBCS;NO_STRICT;%(UndefinePreprocessorDefinitions) + true + $(IntDir)$(TargetName).pch + /opt:nowin98 + Size + + + true + NDEBUG;%(PreprocessorDefinitions) + .\temp/Release/Unicode\flags.tlb + false + Win32 + + + 0x0809 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + + + true + + + true + true + true + Console + uuid.lib;OLDNAMES;%(IgnoreSpecificDefaultLibraries) + flags.def + $(IntDir)$(TargetName).lib + true + 0x24200000 + comctl32.lib;%(AdditionalDependencies) + /ignore:4078 + true + true + + + + + MultiThreadedDebug + Default + false + Disabled + true + Level4 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + _DEBUG;WIN32;_WINDOWS;_USRDLL;STRICT;FLAGS_EXPORTS;%(PreprocessorDefinitions) + NO_STRICT;%(UndefinePreprocessorDefinitions) + true + $(IntDir)$(TargetName).pch + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\temp/Debug/ANSI\flags.tlb + true + Win32 + + + 0x0809 + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + true + + + true + true + true + Console + uuid.lib;OLDNAMES;%(IgnoreSpecificDefaultLibraries) + flags.def + $(IntDir)$(TargetName).lib + 0x24200000 + comctl32.lib;%(AdditionalDependencies) + /mapinfo:lines + + + + + /opt:nowin98 /opt:nowin98 + /opt:ref /opt:nowin98 /opt:ref /opt:nowin98 + + + /opt:nowin98 /opt:nowin98 + /opt:ref /opt:nowin98 /opt:ref /opt:nowin98 + + + /opt:nowin98 /opt:nowin98 + /opt:ref /opt:nowin98 /opt:ref /opt:nowin98 + + + /opt:nowin98 /opt:nowin98 + /opt:ref /opt:nowin98 /opt:ref /opt:nowin98 + + + /opt:nowin98 /opt:nowin98 + /opt:ref /opt:nowin98 /opt:ref /opt:nowin98 + + + /opt:nowin98 /opt:nowin98 + /opt:ref /opt:nowin98 /opt:ref /opt:nowin98 + + + /opt:nowin98 /opt:nowin98 + /opt:ref /opt:nowin98 /opt:ref /opt:nowin98 + + + + + + + + + + + + + + + + + + + + + + + + + + Document + + + + + + + Document + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/CountryFlags/flags.vcxproj.filters b/plugins/CountryFlags/flags.vcxproj.filters new file mode 100644 index 0000000000..c06f9db005 --- /dev/null +++ b/plugins/CountryFlags/flags.vcxproj.filters @@ -0,0 +1,138 @@ + + + + + {2e34a165-959f-4051-80ea-a8e9d3ffe09a} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {d5658bf6-af27-43e5-b3f8-4bc19ac22032} + h;hpp;hxx;hm;inl + + + {d26bc05b-c5a5-4dfc-88a9-1c9e7da444ad} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {71089b54-009a-4229-868a-c90b5e0b350e} + txt + + + {0b81b17c-89f3-4558-a861-4385827dddb3} + *.h + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Resource Files + + + Resource Files + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + SDK + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + Documentation + + + Documentation + + + Documentation + + + Documentation + + + Documentation + + + Documentation + + + Documentation + + + \ No newline at end of file diff --git a/plugins/CountryFlags/huffman.c b/plugins/CountryFlags/huffman.c new file mode 100644 index 0000000000..f05e82113e --- /dev/null +++ b/plugins/CountryFlags/huffman.c @@ -0,0 +1,506 @@ +/************************************************************************* +* Name: huffman.c +* Author: Marcus Geelnard +* Description: Huffman coder/decoder implementation. +* Reentrant: Yes +* +* This is a very straight forward implementation of a Huffman coder and +* decoder. +* +* Primary flaws with this primitive implementation are: +* - Slow bit stream implementation +* - Maximum tree depth of 32 (the coder aborts if any code exceeds a +* size of 32 bits). If I'm not mistaking, this should not be possible +* unless the input buffer is larger than 2^32 bytes, which is not +* supported by the coder anyway (max 2^32-1 bytes can be specified with +* an unsigned 32-bit integer). +* +* On the other hand, there are a few advantages of this implementation: +* - The Huffman tree is stored in a very compact form, requiring only +* 10 bits per symbol (for 8 bit symbols), meaning a maximum of 320 +* bytes overhead. +* - The code should be fairly easy to follow, if you are familiar with +* how the Huffman compression algorithm works. +* +* Possible improvements (probably not worth it): +* - Partition the input data stream into blocks, where each block has +* its own Huffman tree. With variable block sizes, it should be +* possible to find locally optimal Huffman trees, which in turn could +* reduce the total size. +* - Allow for a few different predefined Huffman trees, which could +* reduce the size of a block even further. +*------------------------------------------------------------------------- +* Copyright (c) 2003-2006 Marcus Geelnard +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would +* be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not +* be misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source +* distribution. +* +* Marcus Geelnard +* marcus.geelnard at home.se +*************************************************************************/ + + +/************************************************************************* +* Types used for Huffman coding +*************************************************************************/ + +typedef struct { + unsigned char *BytePtr; + unsigned int BitPos; +} huff_bitstream_t; + +typedef struct { + int Symbol; + unsigned int Count; + unsigned int Code; + unsigned int Bits; +} huff_sym_t; + +typedef struct huff_encodenode_struct huff_encodenode_t; + +struct huff_encodenode_struct { + huff_encodenode_t *ChildA, *ChildB; + int Count; + int Symbol; +}; + +typedef struct huff_decodenode_struct huff_decodenode_t; + +struct huff_decodenode_struct { + huff_decodenode_t *ChildA, *ChildB; + int Symbol; +}; + + +/************************************************************************* +* Constants for Huffman decoding +*************************************************************************/ + +/* The maximum number of nodes in the Huffman tree is 2^(8+1)-1 = 511 */ +#define MAX_TREE_NODES 511 + + +/************************************************************************* +* _Huffman_InitBitstream() - Initialize a bitstream. +*************************************************************************/ + +static void _Huffman_InitBitstream( huff_bitstream_t *stream, + unsigned char *buf ) +{ + stream->BytePtr = buf; + stream->BitPos = 0; +} + + +/************************************************************************* +* _Huffman_ReadBit() - Read one bit from a bitstream. +*************************************************************************/ + +static unsigned int _Huffman_ReadBit( huff_bitstream_t *stream ) +{ + unsigned int x, bit; + unsigned char *buf; + + /* Get current stream state */ + buf = stream->BytePtr; + bit = stream->BitPos; + + /* Extract bit */ + x = (*buf & (1<<(7-bit))) ? 1 : 0; + bit = (bit+1) & 7; + if( !bit ) + { + ++ buf; + } + + /* Store new stream state */ + stream->BitPos = bit; + stream->BytePtr = buf; + + return x; +} + + +/************************************************************************* +* _Huffman_Read8Bits() - Read eight bits from a bitstream. +*************************************************************************/ + +static unsigned int _Huffman_Read8Bits( huff_bitstream_t *stream ) +{ + unsigned int x, bit; + unsigned char *buf; + + /* Get current stream state */ + buf = stream->BytePtr; + bit = stream->BitPos; + + /* Extract byte */ + x = (*buf << bit) | (buf[1] >> (8-bit)); + ++ buf; + + /* Store new stream state */ + stream->BytePtr = buf; + + return x; +} + + +/************************************************************************* +* _Huffman_WriteBits() - Write bits to a bitstream. +*************************************************************************/ + +#ifdef HUFFMAN_ENCODE +static void _Huffman_WriteBits( huff_bitstream_t *stream, unsigned int x, + unsigned int bits ) +{ + unsigned int bit, count; + unsigned char *buf; + unsigned int mask; + + /* Get current stream state */ + buf = stream->BytePtr; + bit = stream->BitPos; + + /* Append bits */ + mask = 1 << (bits-1); + for( count = 0; count < bits; ++ count ) + { + *buf = (unsigned char)((*buf & (0xff^(1<<(7-bit)))) + + ((x & mask ? 1 : 0) << (7-bit))); + x <<= 1; + bit = (bit+1) & 7; + if( !bit ) + { + ++ buf; + } + } + + /* Store new stream state */ + stream->BytePtr = buf; + stream->BitPos = bit; +} +#endif + + +/************************************************************************* +* _Huffman_Hist() - Calculate (sorted) histogram for a block of data. +*************************************************************************/ + +#ifdef HUFFMAN_ENCODE +static void _Huffman_Hist( unsigned char *in, huff_sym_t *sym, + unsigned int size ) +{ + int k; + + /* Clear/init histogram */ + for( k = 0; k < 256; ++ k ) + { + sym[k].Symbol = k; + sym[k].Count = 0; + sym[k].Code = 0; + sym[k].Bits = 0; + } + + /* Build histogram */ + for( k = size; k; -- k ) + { + sym[*in ++].Count ++; + } +} +#endif + + +/************************************************************************* +* _Huffman_StoreTree() - Store a Huffman tree in the output stream and +* in a look-up-table (a symbol array). +*************************************************************************/ + +#ifdef HUFFMAN_ENCODE +static void _Huffman_StoreTree( huff_encodenode_t *node, huff_sym_t *sym, + huff_bitstream_t *stream, unsigned int code, unsigned int bits ) +{ + unsigned int sym_idx; + + /* Is this a leaf node? */ + if( node->Symbol >= 0 ) + { + /* Append symbol to tree description */ + _Huffman_WriteBits( stream, 1, 1 ); + _Huffman_WriteBits( stream, node->Symbol, 8 ); + + /* Find symbol index */ + for( sym_idx = 0; sym_idx < 256; ++ sym_idx ) + { + if( sym[sym_idx].Symbol == node->Symbol ) break; + } + + /* Store code info in symbol array */ + sym[sym_idx].Code = code; + sym[sym_idx].Bits = bits; + return; + } + else + { + /* This was not a leaf node */ + _Huffman_WriteBits( stream, 0, 1 ); + } + + /* Branch A */ + _Huffman_StoreTree( node->ChildA, sym, stream, (code<<1)+0, bits+1 ); + + /* Branch B */ + _Huffman_StoreTree( node->ChildB, sym, stream, (code<<1)+1, bits+1 ); +} +#endif + + +/************************************************************************* +* _Huffman_MakeTree() - Generate a Huffman tree. +*************************************************************************/ + +#ifdef HUFFMAN_ENCODE +static void _Huffman_MakeTree( huff_sym_t *sym, huff_bitstream_t *stream ) +{ + huff_encodenode_t nodes[MAX_TREE_NODES], *node_1, *node_2, *root; + unsigned int k, num_symbols, nodes_left, next_idx; + + /* Initialize all leaf nodes */ + num_symbols = 0; + for( k = 0; k < 256; ++ k ) + { + if( sym[k].Count > 0 ) + { + nodes[num_symbols].Symbol = sym[k].Symbol; + nodes[num_symbols].Count = sym[k].Count; + nodes[num_symbols].ChildA = (huff_encodenode_t *) 0; + nodes[num_symbols].ChildB = (huff_encodenode_t *) 0; + ++ num_symbols; + } + } + + /* Build tree by joining the lightest nodes until there is only + one node left (the root node). */ + root = (huff_encodenode_t *) 0; + nodes_left = num_symbols; + next_idx = num_symbols; + while( nodes_left > 1 ) + { + /* Find the two lightest nodes */ + node_1 = (huff_encodenode_t *) 0; + node_2 = (huff_encodenode_t *) 0; + for( k = 0; k < next_idx; ++ k ) + { + if( nodes[k].Count > 0 ) + { + if( !node_1 || (nodes[k].Count <= node_1->Count) ) + { + node_2 = node_1; + node_1 = &nodes[k]; + } + else if( !node_2 || (nodes[k].Count <= node_2->Count) ) + { + node_2 = &nodes[k]; + } + } + } + + /* Join the two nodes into a new parent node */ + root = &nodes[next_idx]; + root->ChildA = node_1; + root->ChildB = node_2; + root->Count = node_1->Count + node_2->Count; + root->Symbol = -1; + node_1->Count = 0; + node_2->Count = 0; + ++ next_idx; + -- nodes_left; + } + + /* Store the tree in the output stream, and in the sym[] array (the + latter is used as a look-up-table for faster encoding) */ + if( root ) + { + _Huffman_StoreTree( root, sym, stream, 0, 0 ); + } + else + { + /* Special case: only one symbol => no binary tree */ + root = &nodes[0]; + _Huffman_StoreTree( root, sym, stream, 0, 1 ); + } +} +#endif + + +/************************************************************************* +* _Huffman_RecoverTree() - Recover a Huffman tree from a bitstream. +*************************************************************************/ + +static huff_decodenode_t * _Huffman_RecoverTree( huff_decodenode_t *nodes, + huff_bitstream_t *stream, unsigned int *nodenum ) +{ + huff_decodenode_t * this_node; + + /* Pick a node from the node array */ + this_node = &nodes[*nodenum]; + *nodenum = *nodenum + 1; + + /* Clear the node */ + this_node->Symbol = -1; + this_node->ChildA = (huff_decodenode_t *) 0; + this_node->ChildB = (huff_decodenode_t *) 0; + + /* Is this a leaf node? */ + if( _Huffman_ReadBit( stream ) ) + { + /* Get symbol from tree description and store in lead node */ + this_node->Symbol = _Huffman_Read8Bits( stream ); + + return this_node; + } + + /* Get branch A */ + this_node->ChildA = _Huffman_RecoverTree( nodes, stream, nodenum ); + + /* Get branch B */ + this_node->ChildB = _Huffman_RecoverTree( nodes, stream, nodenum ); + + return this_node; +} + + + +/************************************************************************* +* PUBLIC FUNCTIONS * +*************************************************************************/ + + +/************************************************************************* +* Huffman_Compress() - Compress a block of data using a Huffman coder. +* in - Input (uncompressed) buffer. +* out - Output (compressed) buffer. This buffer must be 384 bytes +* larger than the input buffer. +* insize - Number of input bytes. +* The function returns the size of the compressed data. +*************************************************************************/ + +#ifdef HUFFMAN_ENCODE +int Huffman_Compress( unsigned char *in, unsigned char *out, + unsigned int insize ) +{ + huff_sym_t sym[256], tmp; + huff_bitstream_t stream; + unsigned int k, total_bytes, swaps, symbol; + + /* Do we have anything to compress? */ + if( insize < 1 ) return 0; + + /* Initialize bitstream */ + _Huffman_InitBitstream( &stream, out ); + + /* Calculate and sort histogram for input data */ + _Huffman_Hist( in, sym, insize ); + + /* Build Huffman tree */ + _Huffman_MakeTree( sym, &stream ); + + /* Sort histogram - first symbol first (bubble sort) */ + do + { + swaps = 0; + for( k = 0; k < 255; ++ k ) + { + if( sym[k].Symbol > sym[k+1].Symbol ) + { + tmp = sym[k]; + sym[k] = sym[k+1]; + sym[k+1] = tmp; + swaps = 1; + } + } + } + while( swaps ); + + /* Encode input stream */ + for( k = 0; k < insize; ++ k ) + { + symbol = in[k]; + _Huffman_WriteBits( &stream, sym[symbol].Code, + sym[symbol].Bits ); + } + + /* Calculate size of output data */ + total_bytes = (int)(stream.BytePtr - out); + if( stream.BitPos > 0 ) + { + ++ total_bytes; + } + + return total_bytes; +} +#endif + + +/************************************************************************* +* Huffman_Uncompress() - Uncompress a block of data using a Huffman +* decoder. +* in - Input (compressed) buffer. +* out - Output (uncompressed) buffer. This buffer must be large +* enough to hold the uncompressed data. +* insize - Number of input bytes. +* outsize - Number of output bytes. +*************************************************************************/ + +void Huffman_Uncompress( unsigned char *in, unsigned char *out, + unsigned int insize, unsigned int outsize ) +{ + huff_decodenode_t nodes[MAX_TREE_NODES], *root, *node; + huff_bitstream_t stream; + unsigned int k, node_count; + unsigned char *buf; + + /* Do we have anything to decompress? */ + if( insize < 1 ) return; + + /* Initialize bitstream */ + _Huffman_InitBitstream( &stream, in ); + + /* Recover Huffman tree */ + node_count = 0; + root = _Huffman_RecoverTree( nodes, &stream, &node_count ); + + /* Decode input stream */ + buf = out; + for( k = 0; k < outsize; ++ k ) + { + /* Traverse tree until we find a matching leaf node */ + node = root; + while( node->Symbol < 0 ) + { + /* Get next node */ + if( _Huffman_ReadBit( &stream ) ) + node = node->ChildB; + else + node = node->ChildA; + } + + /* We found the matching leaf node and have the symbol */ + *buf ++ = (unsigned char) node->Symbol; + } +} diff --git a/plugins/CountryFlags/icons.c b/plugins/CountryFlags/icons.c new file mode 100644 index 0000000000..9611eb0b78 --- /dev/null +++ b/plugins/CountryFlags/icons.c @@ -0,0 +1,284 @@ +/* +Miranda IM Country Flags Plugin +Copyright (C) 2006-1007 H. Herkenrath + +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 (Flags-License.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "flags.h" + +extern HINSTANCE hInst; +extern int nCountriesCount; +extern struct CountryListEntry *countries; +static HANDLE hServiceLoadIcon,hServiceCreateMergedIcon; + +/************************* Bitmap Access **************************/ + +static HANDLE *phIconHandles; + +static int FASTCALL CountryNumberToBitmapIndex(int countryNumber) +{ + /* country number indices (same order as in flags.bmp) */ + const int BitmapIndexMap[232]={ + 0, 1, 7, 20, 27, 30, 31, 32, 33, 34, 36, 39, 40, 41, 43, 44, 45, 46, 47, 48, + 49, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 81, 82, 84, 86, + 90, 91, 92, 93, 94, 95, 98, 101, 102, 103, 104, 105, 106, 107, 178, 108, 109, 110, 111, 112, + 113, 116, 117, 118, 121, 122, 123, 212, 213, 216, 218, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 257, 258, 260, 261, 263, 264, 265, 266, 267, 268, 269, 290, 291, + 297, 298, 299, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, 382, 385, 386, 387, 389, 420, 421, 441, 442, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 590, 591, 592, 593, 595, 596, 597, 598, 599, 670, 671, 672, 673, 674, 675, 676, + 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 705, 706, 708, 709, + 711, 850, 852, 853, 855, 856, 880, 886, 960, 961, 962, 963, 964, 965, 966, 967, 968, 971, 972, 973, + 974, 975, 976, 977, 994, 995,1141,2691,3811,4101,6101,6722 + }; + /* shared flags by multiple countries */ + switch(countryNumber) { + case 262: /* Reunion Island */ + case 594: /* French Guiana */ + case 5901: /* French Antilles */ + countryNumber=33; /* France */ + break; + case 120: /* Barbuda */ + countryNumber=102; /* Antigua and Barbuda */ + break; + case 6702: /* Tinian Island */ + case 6701: /* Rota Island */ + countryNumber=670; /* Saipan Island (Northern Mariana Islands) */ + break; + case 115: /* Saint Kitts */ + case 114: /* Nevis */ + countryNumber=1141; /* Saint Kitts and Nevis */ + break; + case 247: /* Ascension Island */ + countryNumber=44; /* United Kingdom */ + break; + case 6721: /* Australian Antarctic Territory */ + countryNumber=61; /* Australia */ + break; + case 5399: /* Guantanamo Bay */ + countryNumber=1; /* USA */ + } + /* binary search in index array */ + { int low=0,i,high; + high=SIZEOF(BitmapIndexMap)-1; + if(countryNumber<=BitmapIndexMap[high]) + while(low<=high) { + i=low+((high-low)/2); + /* never happens */ + if(i<0 || i>=SIZEOF(BitmapIndexMap)) DebugBreak(); + if(BitmapIndexMap[i]==countryNumber) return i; + if(countryNumber>BitmapIndexMap[i]) low=i+1; + else high=i-1; + } + } + /* Other,Unknown,Unspecified */ + return 0; +} + +// return value needs to be released using DestroyIcon() +// only operates on color icons, which isn't a problem here +static HICON FASTCALL ResizeIconCentered(HICON hIcon,int cx,int cy) +{ + HICON hResIcon=NULL; + ICONINFO icoi; + BITMAP bm; + register HDC hdc; + HBITMAP hbmPrev,hbm; + POINT pt; + hdc=CreateCompatibleDC(NULL); + if(hdc!=NULL) { + if(GetIconInfo(hIcon,&icoi)) { + if(GetObject(icoi.hbmColor,sizeof(bm),&bm) && bm.bmWidth<=cx && bm.bmHeight<=cy) { + pt.x=(cx-bm.bmWidth)/2; + pt.y=(cy-bm.bmHeight)/2; + hbmPrev=SelectObject(hdc,icoi.hbmColor); + if(hbmPrev!=NULL) { /* error on select? */ + hbm=icoi.hbmColor; + icoi.hbmColor=CreateCompatibleBitmap(hdc,cx,cy); + if(icoi.hbmColor!=NULL) + if(SelectObject(hdc,icoi.hbmColor)!=NULL) { /* error on select? */ + DeleteObject(hbm); /* delete prev color (XOR) */ + if(BitBlt(hdc,0,0,cx,cy,NULL,0,0,BLACKNESS)) /* transparency: AND=0, XOR=1 */ + if(DrawIconEx(hdc,pt.x,pt.y,hIcon,bm.bmWidth,bm.bmHeight,0,NULL,DI_IMAGE|DI_NOMIRROR)) { + if(SelectObject(hdc,icoi.hbmMask)!=NULL) { /* error on select? */ + hbm=icoi.hbmMask; + icoi.hbmMask=CreateBitmap(cx,cy,1,1,NULL); /* mono */ + if(icoi.hbmMask!=NULL) + if(SelectObject(hdc,icoi.hbmMask)!=NULL) { /* error on select? */ + DeleteObject(hbm); /* delete prev mask (AND) */ + if(BitBlt(hdc,0,0,cx,cy,NULL,0,0,WHITENESS)) /* transparency: AND=0, XOR=1 */ + if(DrawIconEx(hdc,pt.x,pt.y,hIcon,0,0,0,NULL,DI_MASK|DI_NOMIRROR)) { + SelectObject(hdc,hbmPrev); + hResIcon=CreateIconIndirect(&icoi); /* bitmaps must not be selected */ + } + } + } + } + } + SelectObject(hdc,hbmPrev); + } + } + DeleteObject(icoi.hbmColor); + DeleteObject(icoi.hbmMask); + } + DeleteDC(hdc); + } + return hResIcon; +} + +/************************* Utils **********************************/ + +HICON FASTCALL LoadFlagIcon(int countryNumber) +{ + char szId[20],*szCountry; + /* create identifier */ + szCountry=(char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,countryNumber,0); + if(szCountry==NULL) szCountry=(char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,countryNumber=0xFFFF,0); + wsprintfA(szId,(countryNumber==0xFFFF)?"%s0x%X":"%s%i","flags_",countryNumber); /* buffer safe */ + return (HICON)CallService(MS_SKIN2_GETICON,0,(LPARAM)szId); +} + +int FASTCALL CountryNumberToIndex(int countryNumber) +{ + int i,nf=0; + for(i=0;i=dwFrom) /* only search if wParam valid */ + while(low<=high) { + i=low+((high-low)/2); + /* never happens */ + if(i<0) DebugBreak(); + /* analyze record */ + id=GetDataRecord(data,i,&dwFrom,&dwTo); + if(dwFrom<=wParam && dwTo>=wParam) { LeaveRecordCache(); return id; } + if(wParam>dwTo) low=i+1; + else high=i-1; + } + LeaveRecordCache(); + } + return 0xFFFF; /* Unknown */ +} + +/************************* Bin Converter **************************/ + +#ifdef BINCONV +#include +#include + +struct { + const char *szMir; + const char *szCSV; +} static const differentCountryNames[]={ + {"British Virgin Islands","VIRGIN ISLANDS, BRITISH"}, + {"Brunei","BRUNEI DARUSSALAM"}, + {"Cape Verde Islands","CAPE VERDE"}, + {"Cocos-Keeling Islands","COCOS (KEELING) ISLANDS"}, + {"Chile, Republic of","CHILE"}, + {"Congo, Democratic Republic of (Zaire)","THE DEMOCRATIC REPUBLIC OF THE CONGO"}, + {"Congo, Republic of the","CONGO"}, + {"Cote d'Ivoire (Ivory Coast)","COTE D'IVOIRE"}, + {"Diego Garcia","BRITISH INDIAN OCEAN TERRITORY"}, + {"Guam, US Territory of","GUAM"}, + {"Iran (Islamic Republic of)","ISLAMIC REPUBLIC OF IRAN"}, + {"Korea, North","REPUBLIC OF KOREA"}, + {"Laos","LAO PEOPLE'S DEMOCRATIC REPUBLIC"}, + {"Reunion Island","REUNION"}, + {"Russia","RUSSIAN FEDERATION"}, + {"Saipan Island (Northern Mariana Islands)","NORTHERN MARIANA ISLANDS"}, + {"Tanzania","UNITED REPUBLIC OF TANZANIA"}, + {"USA","UNITED STATES"}, + {"Macau","MACAO"}, + {"Macedonia (F.Y.R.O.M.)","THE FORMER YUGOSLAV REPUBLIC OF MACEDONIA"}, + {"Micronesia, Federated States of","FEDERATED STATES OF MICRONESIA"}, + {"Mayotte Island","MAYOTTE"}, + {"Moldova, Republic of","REPUBLIC OF MOLDOVA"}, + {"Vietnam","VIET NAM"}, + {"Virgin Islands (USA)","VIRGIN ISLANDS, U.S."}, + {"Vatican City","HOLY SEE (VATICAN CITY STATE)"}, + {"Serbia, Republic of","SERBIA"}, + {"Montenegro, Republic of","MONTENEGRO"}, +}; + +#define ALLOC_STEP (800*1024) /* approx. size of data output */ + +struct ResizableByteBuffer { + BYTE *buf; + DWORD cbLength,cbAlloced; +}; + +static void AppendToByteBuffer(struct ResizableByteBuffer *buffer,const void *append,DWORD cbAppendSize) +{ + if(buffer->cbAlloced<=buffer->cbLength+cbAppendSize) { + BYTE* buf=(BYTE*)mir_realloc(buffer->buf,buffer->cbAlloced+ALLOC_STEP+cbAppendSize); + if(buf==NULL) return; + buffer->buf=buf; + buffer->cbAlloced+=ALLOC_STEP+cbAppendSize; + OutputDebugStringA("reallocating memory...\n"); /* all ascii */ + } + CopyMemory(&buffer->buf[buffer->cbLength],append,cbAppendSize); + buffer->cbLength+=cbAppendSize; +} + +static int EnumIpDataLines(const char *pszFileCSV,const char *pszFileOut) +{ + FILE *fp; + char line[1024],out[512],*pszFrom,*pszTo,*pszTwo,*pszCountry,*buf; + int i,j; + DWORD dwOut; + WORD wOut; + struct ResizableByteBuffer buffer; + + ZeroMemory(&buffer,sizeof(buffer)); + fp=fopen(pszFileCSV,"rt"); + if(fp!=NULL) { + OutputDebugStringA("Running IP data convert...\n"); /* all ascii */ + while(!feof(fp)) { + if(fgets(line,sizeof(line),fp)==NULL) break; + /* get line data */ + pszFrom=line+1; + pszTo=strchr(pszFrom,','); + *(pszTo-1)='\0'; pszTo+=2; + pszTwo=strchr(pszTo,','); + *(pszTwo-1)='\0'; pszTwo+=2; + pszCountry=strchr(pszTwo,',')+1; + pszCountry=strchr(pszCountry,',')+2; + buf=strchr(pszCountry,'"'); + *buf=pszTwo[2]='\0'; + /* corrections */ + if(!lstrcmpi(pszCountry,"ANTARCTICA")) continue; + if(!lstrcmpi(pszCountry,"TIMOR-LESTE")) continue; + if(!lstrcmpi(pszCountry,"PALESTINIAN TERRITORY, OCCUPIED")) + lstrcpy(pszCountry,"ISRAEL"); + else if(!lstrcmpi(pszCountry,"UNITED STATES MINOR OUTLYING ISLANDS")) + lstrcpy(pszCountry,"UNITED STATES"); + else if(!lstrcmpi(pszCountry,"SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS")) + lstrcpy(pszCountry,"UNITED KINGDOM"); + else if(!lstrcmpi(pszTwo,"JE")) /* map error */ + lstrcpy(pszCountry,"UNITED KINGDOM"); + else if(!lstrcmpi(pszTwo,"AX")) /* land Island belongs to Finland */ + lstrcpy(pszCountry,"FINLAND"); + else if(!lstrcmpi(pszTwo,"ME")) + lstrcpy(pszCountry,"MONTENEGRO"); + else if(!lstrcmpi(pszTwo,"RS") || !lstrcmpi(pszTwo,"CS")) + lstrcpy(pszCountry,"SERBIA"); + /* convert */ + for(i=0;i + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Englisch (GB) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE MOVEABLE PURE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#include \r\n" + "\0" +END + +3 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#include ""version.rc""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_FLAGS BITMAP DISCARDABLE "res/flags.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// BIN +// + +IDR_IPTOCOUNTRY BIN DISCARDABLE "res/ip-to-country.bin" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPT_EXTRAIMG DIALOGEX 0, 0, 223, 93 +STYLE DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg" +BEGIN + GROUPBOX "Country Flags",-1,3,0,220,93 + CONTROL "Show country flag as &status icon on message window", + IDC_CHECK_SHOWSTATUSICONFLAG,"Button",BS_AUTOCHECKBOX | + WS_GROUP | WS_TABSTOP,12,14,206,10 + CONTROL "Show country flag as &extra image on contact list", + IDC_CHECK_SHOWEXTRAIMGFLAG,"Button",BS_AUTOCHECKBOX | + WS_GROUP | WS_TABSTOP,12,27,206,10 + LTEXT "In following contact list &column:", + IDC_TEXT_EXTRAIMGFLAGCOLUMN,24,42,110,8 + COMBOBOX IDC_COMBO_EXTRAIMGFLAGCOLUMN,135,40,77,117, + CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + CONTROL "Use &unknown flag if the country can not be determined", + IDC_CHECK_USEUNKNOWNFLAG,"Button",BS_AUTOCHECKBOX | + WS_GROUP | WS_TABSTOP,12,77,206,10 + CONTROL "Use &IP-to-country database for country detection", + IDC_CHECK_USEIPTOCOUNTRY,"Button",BS_AUTOCHECKBOX | + WS_GROUP | WS_TABSTOP,12,64,206,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_OPT_EXTRAIMG, DIALOG + BEGIN + VERTGUIDE, 3 + VERTGUIDE, 12 + VERTGUIDE, 24 + VERTGUIDE, 218 + HORZGUIDE, 42 + HORZGUIDE, 52 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Englisch (GB) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/CountryFlags/utils.c b/plugins/CountryFlags/utils.c new file mode 100644 index 0000000000..d71b0acde3 --- /dev/null +++ b/plugins/CountryFlags/utils.c @@ -0,0 +1,162 @@ +/* +Miranda IM Country Flags Plugin +Copyright (C) 2006-1007 H. Herkenrath + +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 (Flags-License.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "flags.h" + +/************************* Buffered Functions *********************/ + +struct BufferedCallData { + DWORD startTick; + UINT uElapse; + BUFFEREDPROC pfnBuffProc; + LPARAM lParam; + #ifdef _DEBUG + const char *pszProcName; + #endif +}; + +static UINT idBufferedTimer; +static struct BufferedCallData *callList; +static int nCallListCount; + +// always gets called in main message loop +static void CALLBACK BufferedProcTimer(HWND hwnd,UINT msg,UINT idTimer,DWORD currentTick) +{ + int i; + struct BufferedCallData *buf; + UINT uElapsed,uElapseNext=USER_TIMER_MAXIMUM; + BUFFEREDPROC pfnBuffProc; + LPARAM lParam; + #ifdef _DEBUG + char szDbgLine[256]; + const char *pszProcName; + #endif + UNREFERENCED_PARAMETER(msg); + + for(i=0;i=callList[i].uElapse) { + /* call elapsed proc */ + pfnBuffProc=callList[i].pfnBuffProc; + lParam=callList[i].lParam; + #ifdef _DEBUG + pszProcName=callList[i].pszProcName; + #endif + /* resize storage array */ + if((i+1)startTick=GetTickCount(); + data->uElapse=uElapse; + data->lParam=lParam; + data->pfnBuffProc=pfnBuffProc; + #ifdef _DEBUG + { char szDbgLine[256]; + data->pszProcName=pszProcName; + mir_snprintf(szDbgLine,sizeof(szDbgLine),"buffered queue: %s(0x%X)\n",pszProcName,lParam); /* all ascii */ + OutputDebugStringA(szDbgLine); + if(!idBufferedTimer) { + mir_snprintf(szDbgLine,sizeof(szDbgLine),"next buffered timeout: %ums\n",uElapse); /* all ascii */ + OutputDebugStringA(szDbgLine); + } + } + #endif + /* set next timer */ + if(idBufferedTimer) uElapse=USER_TIMER_MINIMUM; /* will get recalculated */ + idBufferedTimer=SetTimer(NULL,idBufferedTimer,uElapse,BufferedProcTimer); +} + +// assumes to be called in context of main thread +void PrepareBufferedFunctions(void) +{ + idBufferedTimer=0; + nCallListCount=0; + callList=NULL; +} + +// assumes to be called in context of main thread +void KillBufferedFunctions(void) +{ + if(idBufferedTimer) KillTimer(NULL,idBufferedTimer); + nCallListCount=0; + mir_free(callList); /* does NULL check */ +} diff --git a/plugins/CountryFlags/version.h b/plugins/CountryFlags/version.h new file mode 100644 index 0000000000..b1c58f55cc --- /dev/null +++ b/plugins/CountryFlags/version.h @@ -0,0 +1,38 @@ +/* +Miranda IM Country Flags Plugin +Copyright (C) 2006-2007 H. Herkenrath + +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 (Flags-License.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#define NEEDED_MIRANDA_VERSION PLUGIN_MAKE_VERSION(0,7,0,10) +#define NEEDED_MIRANDA_VERSION_STR "0.7 alpha build #10" +#define PLUGIN_VERSION PLUGIN_MAKE_VERSION(0,1,0,3) +#define FILE_VERSION 0,1,0,3 + +#ifdef _DEBUG + #define FILE_VERSION_STR "0.1.0.4 alpha" +#else + #define FILE_VERSION_STR "0.1.0.3" +#endif + +#define PLUGIN_EMAIL "hrathh users.sourceforge.net" +#define PLUGIN_EMAIL_ATT_POS 7 /* position of the @-sign in the email adress above */ + +#ifdef _UNICODE + #define PLUGIN_WEBSITE "http://addons.miranda-im.org/details.php?action=viewfile&id=3463" +#else + #define PLUGIN_WEBSITE "http://addons.miranda-im.org/details.php?action=viewfile&id=3462" +#endif diff --git a/plugins/CountryFlags/version.rc b/plugins/CountryFlags/version.rc new file mode 100644 index 0000000000..8694503dee --- /dev/null +++ b/plugins/CountryFlags/version.rc @@ -0,0 +1,47 @@ +#ifndef _MAC + +#include + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION FILE_VERSION + PRODUCTVERSION FILE_VERSION + FILEFLAGSMASK 0x0L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "Licensed under the terms of the GNU General Public License" + VALUE "FileDescription", "Country Flags Plugin for Miranda IM" + VALUE "FileVersion", FILE_VERSION_STR + VALUE "InternalName", "CountryUtils" + VALUE "LegalCopyright", "Copyright 2006-2007 H. Herkenrath" + VALUE "OriginalFilename", "flags.dll" + VALUE "ProductName", "Country Flags" + VALUE "ProductVersion", FILE_VERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // !_MAC + + + + diff --git a/plugins/FavContacts/favcontacts.sln b/plugins/FavContacts/favcontacts.sln new file mode 100644 index 0000000000..4572aa3063 --- /dev/null +++ b/plugins/FavContacts/favcontacts.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "favcontacts", "favcontacts.vcxproj", "{2D0B4CB0-3ACA-4612-B745-FF3050E1500A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Win32 = Debug Unicode|Win32 + Release Unicode|Win32 = Release Unicode|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2D0B4CB0-3ACA-4612-B745-FF3050E1500A}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {2D0B4CB0-3ACA-4612-B745-FF3050E1500A}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {2D0B4CB0-3ACA-4612-B745-FF3050E1500A}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {2D0B4CB0-3ACA-4612-B745-FF3050E1500A}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/FavContacts/favcontacts.vcxproj b/plugins/FavContacts/favcontacts.vcxproj new file mode 100644 index 0000000000..8c99da3f7b --- /dev/null +++ b/plugins/FavContacts/favcontacts.vcxproj @@ -0,0 +1,131 @@ + + + + + Debug Unicode + Win32 + + + Release Unicode + Win32 + + + + {2D0B4CB0-3ACA-4612-B745-FF3050E1500A} + favcontacts + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FAVCONTACTS_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + comctl32.lib;%(AdditionalDependencies) + true + Windows + false + + + MachineX86 + + + + + Full + Size + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FAVCONTACTS_EXPORTS;%(PreprocessorDefinitions) + + + MultiThreadedDLL + false + + + Level3 + ProgramDatabase + + + comctl32.lib;%(AdditionalDependencies) + Windows + true + true + + + false + + + MachineX86 + $(IntDir)$(TargetName).lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/FavContacts/favcontacts.vcxproj.filters b/plugins/FavContacts/favcontacts.vcxproj.filters new file mode 100644 index 0000000000..81cec32c10 --- /dev/null +++ b/plugins/FavContacts/favcontacts.vcxproj.filters @@ -0,0 +1,76 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {190cde56-eadb-44f2-a0cd-1cb46fe8de29} + + + + + Source Files + + + Source Files + + + Source Files + + + http + + + http + + + http + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + http + + + http + + + http + + + + + Resource Files + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/plugins/FavContacts/res/favlist.ico b/plugins/FavContacts/res/favlist.ico new file mode 100644 index 0000000000..9b55cd0afa Binary files /dev/null and b/plugins/FavContacts/res/favlist.ico differ diff --git a/plugins/FavContacts/res/favorite.ico b/plugins/FavContacts/res/favorite.ico new file mode 100644 index 0000000000..4b0bff0f6b Binary files /dev/null and b/plugins/FavContacts/res/favorite.ico differ diff --git a/plugins/FavContacts/res/regular.ico b/plugins/FavContacts/res/regular.ico new file mode 100644 index 0000000000..6ddb31921a Binary files /dev/null and b/plugins/FavContacts/res/regular.ico differ diff --git a/plugins/FavContacts/res/userprefs.ico b/plugins/FavContacts/res/userprefs.ico new file mode 100644 index 0000000000..7028f10d03 Binary files /dev/null and b/plugins/FavContacts/res/userprefs.ico differ diff --git a/plugins/FavContacts/resource.h b/plugins/FavContacts/resource.h new file mode 100644 index 0000000000..4e3f557cf7 --- /dev/null +++ b/plugins/FavContacts/resource.h @@ -0,0 +1,39 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDI_FAVOURITE 101 +#define IDI_ICON1 102 +#define IDI_REGULAR 102 +#define IDD_DIALOG1 103 +#define IDD_LIST 103 +#define IDD_PROPPAGE_LARGE 107 +#define IDD_OPTIONS 107 +#define IDC_CLIST 1001 +#define IDC_CHK_SECONDLINE 1003 +#define IDC_CHK_AVATARS 1004 +#define IDC_CHK_AVATARBORDER 1005 +#define IDC_TXT_RADIUS 1007 +#define IDC_CHK_NOTRANSPARENTBORDER 1008 +#define IDC_CHK_CENTERHOTKEY 1009 +#define IDC_CHK_SYSCOLORS 1010 +#define IDC_CANVAS 1011 +#define IDC_CHK_DIMIDLE 1012 +#define IDC_CHK_GROUPS 1013 +#define IDC_CHK_GROUPCOLUMS 1014 +#define IDC_BTN_FONTS 1015 +#define IDC_TXT_RADIUS2 1016 +#define IDC_TXT_MAXRECENT 1016 +#define IDC_BTN_HOTKEYS 1018 +#define IDC_CHK_RIGHTAVATARS 1019 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1016 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/FavContacts/resource.rc b/plugins/FavContacts/resource.rc new file mode 100644 index 0000000000..a96aabaf04 --- /dev/null +++ b/plugins/FavContacts/resource.rc @@ -0,0 +1,166 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_FAVOURITE ICON "res\\favorite.ico" +IDI_REGULAR ICON "res\\regular.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 316, 251 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Customize",IDC_STATIC,5,5,149,241 + CONTROL "Show second line",IDC_CHK_SECONDLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,43,137,10 + CONTROL "Show avatars",IDC_CHK_AVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,56,137,10 + CONTROL "Draw avatar border",IDC_CHK_AVATARBORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,82,122,10 + RTEXT "Round corners by",IDC_STATIC,26,95,71,10,SS_CENTERIMAGE + EDITTEXT IDC_TXT_RADIUS,99,94,29,12,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER + LTEXT "px.",IDC_STATIC,132,95,16,10,SS_CENTERIMAGE + CONTROL "Hide for transparent avatars",IDC_CHK_NOTRANSPARENTBORDER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,40,108,108,10 + CONTROL "Use system colors and fonts",IDC_CHK_SYSCOLORS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,134,137,10 + CONTROL "Hotkey shows menu centered on screen",IDC_CHK_CENTERHOTKEY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,147,139,10 + LTEXT "Menu item preview:",IDC_STATIC,11,177,137,8 + CONTROL "",IDC_CANVAS,"Static",SS_OWNERDRAW,26,189,122,26 + GROUPBOX "Favourite Contacts",IDC_STATIC,161,5,150,241 + CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,167,17,138,223,WS_EX_CLIENTEDGE + CONTROL "Enable groups",IDC_CHK_GROUPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,17,137,10 + CONTROL "Multicolumn menu",IDC_CHK_GROUPCOLUMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,30,122,10 + CONTROL "Configure fonts and colors...",IDC_BTN_FONTS,"Hyperlink",WS_TABSTOP,11,229,137,11 + CONTROL "Set up menu hotkey...",IDC_BTN_HOTKEYS,"Hyperlink",WS_TABSTOP,11,218,137,11 + CONTROL "Align to the right",IDC_CHK_RIGHTAVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,69,122,10 + CONTROL "Dim idle contact icons",IDC_CHK_DIMIDLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,121,139,10 + RTEXT "Show",IDC_STATIC,12,160,34,10,SS_CENTERIMAGE + EDITTEXT IDC_TXT_MAXRECENT,50,159,29,12,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER + LTEXT "recent contacts",IDC_STATIC,84,160,65,10,SS_CENTERIMAGE +END + +IDD_LIST DIALOGEX 0, 0, 316, 183 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_BORDER | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + VERTGUIDE, 5 + VERTGUIDE, 11 + VERTGUIDE, 26 + VERTGUIDE, 148 + VERTGUIDE, 154 + VERTGUIDE, 161 + VERTGUIDE, 167 + VERTGUIDE, 305 + VERTGUIDE, 311 + HORZGUIDE, 5 + HORZGUIDE, 17 + HORZGUIDE, 229 + HORZGUIDE, 240 + HORZGUIDE, 246 + END + + IDD_LIST, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 309 + TOPMARGIN, 7 + BOTTOMMARGIN, 176 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Ukrainian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_UKR) +#ifdef _WIN32 +LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Ukrainian resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/FavContacts/src/contact_cache.cpp b/plugins/FavContacts/src/contact_cache.cpp new file mode 100644 index 0000000000..c61635cc26 --- /dev/null +++ b/plugins/FavContacts/src/contact_cache.cpp @@ -0,0 +1,231 @@ +#include "headers.h" +#include +#include + +int __cdecl CContactCache::OnDbEventAdded(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + HANDLE hEvent = (HANDLE)lParam; + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei); + if (dbei.eventType != EVENTTYPE_MESSAGE) return 0; + + float weight = GetEventWeight(time(NULL) - dbei.timestamp); + float q = GetTimeWeight(time(NULL) - m_lastUpdate); + m_lastUpdate = time(NULL); + if (!weight) return 0; + + Lock(); + bool found = false; + for (int i = 0; i < m_cache.getCount(); ++i) + { + m_cache[i].rate *= q; + if (m_cache[i].hContact == hContact) + { + found = true; + m_cache[i].rate += weight; + } + } + + if (!found) + { + TContactInfo *info = new TContactInfo; + info->hContact = hContact; + info->rate = weight; + m_cache.insert(info); + } else + { + qsort(m_cache.getArray(), m_cache.getCount(), sizeof(TContactInfo *), TContactInfo::cmp2); + } + + Unlock(); + return 0; +} + +float CContactCache::GetEventWeight(unsigned long age) +{ + const float ceil = 1000.f; + const float floor = 0.0001f; + const int depth = 60 * 60 * 24 * 30; + if (age > depth) return 0; + return exp(log(ceil) - age * (log(ceil) - log(floor)) / depth); +} + +float CContactCache::GetTimeWeight(unsigned long age) +{ + const float ceil = 1000.f; + const float floor = 0.0001f; + const int depth = 60 * 60 * 24 * 30; + if (age > depth) return 0; + return exp(age * (log(ceil) - log(floor)) / depth); +} + +CContactCache::CContactCache(): m_cache(50, TContactInfo::cmp) +{ + InitializeCriticalSection(&m_cs); + + int (__cdecl CContactCache::*pfn)(WPARAM, LPARAM); + pfn = &CContactCache::OnDbEventAdded; + m_hOnDbEventAdded = HookEventObj(ME_DB_EVENT_ADDED, *(MIRANDAHOOKOBJ *)&pfn, this); + + Rebuild(); +} + +CContactCache::~CContactCache() +{ + UnhookEvent(m_hOnDbEventAdded); + DeleteCriticalSection(&m_cs); +} + +void CContactCache::Rebuild() +{ + unsigned long timestamp = time(NULL); + m_lastUpdate = time(NULL); + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + TContactInfo *info = new TContactInfo; + info->hContact = hContact; + info->rate = 0; + + HANDLE hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0); + while (hEvent) + { + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if (!CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei)) + { + if (float weight = GetEventWeight(timestamp - dbei.timestamp)) + { + if (dbei.eventType == EVENTTYPE_MESSAGE) + info->rate += weight; + } else + { + break; + } + } + hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hEvent, 0); + } + + m_cache.insert(info); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } +} + +HANDLE CContactCache::get(int rate) +{ + if (rate >= 0 && rate < m_cache.getCount()) + return m_cache[rate].hContact; + return NULL; +} + +float CContactCache::getWeight(int rate) +{ + if (rate >= 0 && rate < m_cache.getCount()) + return m_cache[rate].rate; + return -1; +} + +static bool AppendInfo(TCHAR *buf, int size, HANDLE hContact, int info) +{ + CONTACTINFO ci = {0}; + ci.cbSize = sizeof(ci); + ci.hContact = hContact; + ci.dwFlag = info; +#if defined(UNICODE) || defined(_UNICODE) + ci.dwFlag |= CNF_UNICODE; +#endif + + bool ret = false; + + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci) && (ci.type == CNFT_ASCIIZ) && ci.pszVal) + { + if (*ci.pszVal && (lstrlen(ci.pszVal) < size-2)) + { + lstrcpy(buf, ci.pszVal); + ret = true; + } + mir_free(ci.pszVal); + } + + return ret; +} + +void CContactCache::TContactInfo::LoadInfo() +{ + if (infoLoaded) return; + TCHAR *p = info; + + p[0] = p[1] = 0; + + static const int items[] = { + CNF_FIRSTNAME, CNF_LASTNAME, CNF_NICK , CNF_CUSTOMNICK, CNF_EMAIL, CNF_CITY, CNF_STATE, + CNF_COUNTRY, CNF_PHONE, CNF_HOMEPAGE, CNF_ABOUT, CNF_UNIQUEID, CNF_MYNOTES, CNF_STREET, + CNF_CONAME, CNF_CODEPT, CNF_COCITY, CNF_COSTATE, CNF_COSTREET, CNF_COCOUNTRY + }; + + for (int i = 0; i < SIZEOF(items); ++i) + { + if (AppendInfo(p, SIZEOF(info) - (p - info), hContact, items[i])) + p += lstrlen(p) + 1; + } + *p = 0; + + infoLoaded = true; +} + +TCHAR *nb_stristr(TCHAR *str, TCHAR *substr) +{ + if (!substr || !*substr) return str; + if (!str || !*str) return NULL; + + TCHAR *str_up = NEWTSTR_ALLOCA(str); + TCHAR *substr_up = NEWTSTR_ALLOCA(substr); + + CharUpperBuff(str_up, lstrlen(str_up)); + CharUpperBuff(substr_up, lstrlen(substr_up)); + + TCHAR* p = _tcsstr(str_up, substr_up); + return p ? (str + (p - str_up)) : NULL; +} + +bool CContactCache::filter(int rate, TCHAR *str) +{ + if (!str || !*str) + return true; + m_cache[rate].LoadInfo(); + + HKL kbdLayoutActive = GetKeyboardLayout(GetCurrentThreadId()); + HKL kbdLayouts[10]; + int nKbdLayouts = GetKeyboardLayoutList(SIZEOF(kbdLayouts), kbdLayouts); + + TCHAR buf[256]; + BYTE keyState[256] = {0}; + + for (int iLayout = 0; iLayout < nKbdLayouts; ++iLayout) + { + if (kbdLayoutActive == kbdLayouts[iLayout]) + { + lstrcpy(buf, str); + } else + { + int i; + for (i = 0; str[i]; ++i) + { + UINT vk = VkKeyScanEx(str[i], kbdLayoutActive); + UINT scan = MapVirtualKeyEx(vk, 0, kbdLayoutActive); + ToUnicodeEx(vk, scan, keyState, buf+i, SIZEOF(buf)-i, 0, kbdLayouts[iLayout]); + } + buf[i] = 0; + } + + for (TCHAR *p = m_cache[rate].info; p && *p; p = p + lstrlen(p) + 1) + if (nb_stristr(p, buf)) + return true; + } + + return false; +} diff --git a/plugins/FavContacts/src/contact_cache.h b/plugins/FavContacts/src/contact_cache.h new file mode 100644 index 0000000000..905ba4b469 --- /dev/null +++ b/plugins/FavContacts/src/contact_cache.h @@ -0,0 +1,61 @@ +#ifndef __contact_cache__ +#define __contact_cache__ + +class CContactCache +{ +public: + enum { INFOSIZE = 1024 }; + +private: + + struct TContactInfo + { + HANDLE hContact; + float rate; + TCHAR info[INFOSIZE]; + bool infoLoaded; + + static int cmp(const TContactInfo *p1, const TContactInfo *p2) + { + if (p1->rate > p2->rate) return -1; + if (p1->rate < p2->rate) return 1; + return 0; + } + + static int cmp2(const void *a1, const void *a2) + { + return cmp(*(const TContactInfo **)a1, *(const TContactInfo **)a2); + } + + TContactInfo() + { + info[0] = info[1] = 0; + infoLoaded = false; + } + + void LoadInfo(); + }; + + OBJLIST m_cache; + unsigned long m_lastUpdate; + CRITICAL_SECTION m_cs; + HANDLE m_hOnDbEventAdded; + + int __cdecl OnDbEventAdded(WPARAM wParam, LPARAM lParam); + float GetEventWeight(unsigned long age); + float GetTimeWeight(unsigned long age); + +public: + CContactCache(); + ~CContactCache(); + + void Lock() { EnterCriticalSection(&m_cs); } + void Unlock() { LeaveCriticalSection(&m_cs); } + void Rebuild(); + + HANDLE get(int rate); + float getWeight(int rate); + bool filter(int rate, TCHAR *str); +}; + +#endif // __contact_cache__ diff --git a/plugins/FavContacts/src/cserver.cpp b/plugins/FavContacts/src/cserver.cpp new file mode 100644 index 0000000000..957d1a6048 --- /dev/null +++ b/plugins/FavContacts/src/cserver.cpp @@ -0,0 +1,82 @@ +#include +#include +#include + +#include "csocket.h" +#include "cserver.h" + +void CServer::Start(int port, IConnectionProcessorFactory *connectionProcessorFactory, bool background) +{ + m_socket = socket(AF_INET, SOCK_STREAM, 0); + if (m_socket == INVALID_SOCKET) return; + + sockaddr_in addr = {0}; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = htons((WORD)port); + if (bind(m_socket, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) + { + closesocket(m_socket); + m_socket = INVALID_SOCKET; + return; + } + + listen(m_socket, SOMAXCONN); + + m_connectionProcessorFactory = connectionProcessorFactory; + + if (background) + { + CreateThread(NULL, 0, + GlobalConnectionAcceptThread, + this, + 0, NULL); + } else + { + ConnectionAcceptThread(); + } +} + +void CServer::Stop() +{ + shutdown(m_socket, SD_BOTH); + closesocket(m_socket); +} + +DWORD CServer::ConnectionAcceptThread() +{ + while (1) + { + SOCKET s = accept(m_socket, NULL, NULL); + if (s == INVALID_SOCKET) break; + + CreateThread(NULL, 0, + GlobalConnectionProcessThread, + new GlobalConnectionProcessThreadArgs(this, s), + 0, NULL); + } + return 0; +} + +DWORD CServer::ConnectionProcessThread(SOCKET s) +{ + CSocket sock(s); + IConnectionProcessor *processor = m_connectionProcessorFactory->Create(&sock); + processor->ProcessConnection(); + delete processor; + return 0; +} + +DWORD WINAPI CServer::GlobalConnectionAcceptThread(void *arg) +{ + CServer *server = (CServer *)arg; + return server->ConnectionAcceptThread(); +} + +DWORD WINAPI CServer::GlobalConnectionProcessThread(void *arg) +{ + GlobalConnectionProcessThreadArgs *args = (GlobalConnectionProcessThreadArgs *)arg; + DWORD result = args->m_server->ConnectionProcessThread(args->m_socket); + delete args; + return result; +} diff --git a/plugins/FavContacts/src/cserver.h b/plugins/FavContacts/src/cserver.h new file mode 100644 index 0000000000..007a341896 --- /dev/null +++ b/plugins/FavContacts/src/cserver.h @@ -0,0 +1,42 @@ +#ifndef cserver_h__ +#define cserver_h__ + +class IConnectionProcessor +{ +public: + virtual ~IConnectionProcessor() {} + virtual void ProcessConnection() = 0; +}; + +class IConnectionProcessorFactory +{ +public: + virtual IConnectionProcessor *Create(CSocket *s) = 0; +}; + +class CServer +{ +private: + SOCKET m_socket; + IConnectionProcessorFactory *m_connectionProcessorFactory; + + DWORD ConnectionAcceptThread(); + DWORD ConnectionProcessThread(SOCKET s); + + static DWORD WINAPI GlobalConnectionAcceptThread(void *arg); + + struct GlobalConnectionProcessThreadArgs + { + CServer *m_server; + SOCKET m_socket; + + GlobalConnectionProcessThreadArgs(CServer *server, SOCKET s): m_server(server), m_socket(s) {} + }; + static DWORD WINAPI GlobalConnectionProcessThread(void *arg); + +public: + void Start(int port, IConnectionProcessorFactory *connectionProcessorFactory, bool background); + void Stop(); +}; + +#endif // cserver_h__ diff --git a/plugins/FavContacts/src/csocket.cpp b/plugins/FavContacts/src/csocket.cpp new file mode 100644 index 0000000000..dfff16fbf1 --- /dev/null +++ b/plugins/FavContacts/src/csocket.cpp @@ -0,0 +1,22 @@ +#include +#include +#include + +#include "csocket.h" + +int CSocket::Recv(char *buf, int count) +{ + return recv(m_socket, buf, count, 0); +} + +int CSocket::Send(char *buf, int count) +{ + if (count < 0) count = strlen(buf); + return send(m_socket, buf, count, 0); +} + +void CSocket::Close() +{ + shutdown(m_socket, SD_BOTH); + closesocket(m_socket); +} diff --git a/plugins/FavContacts/src/csocket.h b/plugins/FavContacts/src/csocket.h new file mode 100644 index 0000000000..3fa1c87852 --- /dev/null +++ b/plugins/FavContacts/src/csocket.h @@ -0,0 +1,16 @@ +#ifndef csocket_h__ +#define csocket_h__ + +class CSocket +{ +protected: + SOCKET m_socket; + +public: + CSocket(SOCKET socket = INVALID_SOCKET): m_socket(socket) {} + int Recv(char *buf, int count); + int Send(char *buf, int count = -1); + void Close(); +}; + +#endif // csocket_h__ diff --git a/plugins/FavContacts/src/favlist.cpp b/plugins/FavContacts/src/favlist.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/FavContacts/src/favlist.h b/plugins/FavContacts/src/favlist.h new file mode 100644 index 0000000000..6201126b44 --- /dev/null +++ b/plugins/FavContacts/src/favlist.h @@ -0,0 +1,134 @@ +#ifndef favlist_h__ +#define favlist_h__ + +struct TContactInfo +{ +private: + HANDLE hContact; + DWORD status; + TCHAR *name; + TCHAR *group; + bool bManual; + float fRate; + +public: + TContactInfo(HANDLE hContact, bool bManual, float fRate = 0) + { + DBVARIANT dbv = {0}; + + this->hContact = hContact; + this->bManual = bManual; + this->fRate = fRate; + name = mir_tstrdup((TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)); + if (g_Options.bUseGroups && !DBGetContactSettingTString(hContact, "CList", "Group", &dbv)) + { + group = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } else + if (g_Options.bUseGroups) + { + group = mir_tstrdup(TranslateT("")); + } else + { + group = mir_tstrdup(TranslateT("Favourite Contacts")); + } + status = DBGetContactSettingWord(hContact, (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0), "Status", ID_STATUS_OFFLINE); + } + + ~TContactInfo() + { + mir_free(name); + mir_free(group); + } + + HANDLE getHandle() const + { + return hContact; + } + + TCHAR *getGroup() const + { + return group; + } + + static int cmp(const TContactInfo *p1, const TContactInfo *p2) + { + if (p1->bManual && !p2->bManual) return -1; + if (!p1->bManual && p2->bManual) return 1; + + if (!p1->bManual) + { + if (p1->fRate > p2->fRate) return -1; + if (p1->fRate < p2->fRate) return 1; + } + + int res = 0; + if (res = lstrcmp(p1->group, p2->group)) return res; + //if (p1->status < p2->status) return -1; + //if (p1->status < p2->status) return +1; + if (res = lstrcmp(p1->name, p2->name)) return res; + return 0; + } +}; + +class TFavContacts: public LIST +{ +private: + int nGroups; + +public: + TFavContacts(): LIST(5, TContactInfo::cmp) {} + ~TFavContacts() + { + for (int i = 0; i < this->getCount(); ++i) + delete (*this)[i]; + } + + int groupCount() + { + return nGroups; + } + + TContactInfo *addContact(HANDLE hContact, bool bManual) + { + TContactInfo *info = new TContactInfo(hContact, bManual); + this->insert(info); + return info; + } + + void build() + { + TCHAR *prevGroup = NULL; + int i; + + nGroups = 1; + + 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)) + { + TCHAR *group = addContact(hContact, true)->getGroup(); + if (prevGroup && lstrcmp(prevGroup, group)) + ++nGroups; + prevGroup = group; + } + + int nRecent = 0; + for (i = 0; nRecent < g_Options.wMaxRecent; ++i) + { + hContact = g_contactCache->get(i); + if (!hContact) break; + if (!DBGetContactSettingByte(hContact, "FavContacts", "IsFavourite", 0)) + { + TCHAR *group = addContact(hContact, false)->getGroup(); + if (prevGroup && lstrcmp(prevGroup, group)) + ++nGroups; + prevGroup = group; + + ++nRecent; + } + } + } +}; + +#endif // favlist_h__ diff --git a/plugins/FavContacts/src/headers.h b/plugins/FavContacts/src/headers.h new file mode 100644 index 0000000000..8863317199 --- /dev/null +++ b/plugins/FavContacts/src/headers.h @@ -0,0 +1,94 @@ +/* +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. +*/ + +#define _CRT_SECURE_NO_DEPRECATE + +#if defined(UNICODE) && !defined(_UNICODE) + #define _UNICODE +#endif + +#include +#define _WIN32_WINNT 0x0501 +#include +#include +#include +#include + +#define MIRANDA_VER 0x800 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../resource.h" + +#define NEWTSTR_ALLOCA(A) (A==NULL)?NULL:_tcscpy((TCHAR*)alloca(sizeof(TCHAR)*(_tcslen(A)+1)),A) + +struct Options +{ + BYTE bSecondLine; + BYTE bAvatars; + BYTE bAvatarBorder; + WORD wAvatarRadius; + BYTE bNoTransparentBorder; + BYTE bSysColors; + BYTE bCenterHotkey; + BYTE bUseGroups; + BYTE bUseColumns; + BYTE bRightAvatars; + BYTE bDimIdle; + WORD wMaxRecent; + + COLORREF clLine1, clLine2, clBack; + COLORREF clLine1Sel, clLine2Sel, clBackSel; + HFONT hfntName, hfntSecond; +}; + + +#include "contact_cache.h" + +extern Options g_Options; +extern CContactCache *g_contactCache; + +#include "favlist.h" +#include "http_api.h" diff --git a/plugins/FavContacts/src/http_api.cpp b/plugins/FavContacts/src/http_api.cpp new file mode 100644 index 0000000000..147cabdd7d --- /dev/null +++ b/plugins/FavContacts/src/http_api.cpp @@ -0,0 +1,165 @@ +#include "headers.h" + +#pragma comment(lib,"ws2_32.lib") + +#include "csocket.h" +#include "cserver.h" + +#define MS_FAVCONTACTS_OPEN_CONTACT "FavContacts/OpenContact" + +class CHttpProcessor: public IConnectionProcessor +{ +private: + CSocket *m_socket; + + char *FetchURL(char *s) + { + char *p; + if (p = strstr(s, "\r\n")) *p = 0; + if (p = strrchr(s, ' ')) *p = 0; + if (p = strchr(s, ' ')) while (*p && *p == ' ') p++; + return mir_strdup(p); + } + +public: + CHttpProcessor(CSocket *s): m_socket(s) {} + + void ProcessConnection() + { + char buf[1024]; + int n = m_socket->Recv(buf, sizeof(buf)); + buf[n] = 0; + + char *s = FetchURL(buf); + + if (!strncmp(s, "/fav/list/", 10)) + { + SendList(); + } else + if (!strncmp(s, "/fav/open/", 10)) + { + OpenContact(s); + } + + mir_free(s); + m_socket->Close(); + } + + void OpenContact(char *s) + { + m_socket->Send("HTTP 200 OK\r\n\r\n"); + + int hContact; + sscanf(s, "/fav/open/%d", &hContact); + if (CallService(MS_DB_CONTACT_IS, hContact, 0)) + CallServiceSync(MS_FAVCONTACTS_OPEN_CONTACT, (WPARAM)hContact, 0); + } + + void SendList() + { + TFavContacts favList; + favList.build(); + + m_socket->Send( + "HTTP 200 OK\r\n" + "Content-Type: text/javascript\r\n" + "\r\n"); + + Send("try {\r\n"); + Send("SetContactCount("); + Send(favList.getCount()); + Send(");\r\n"); + + for (int i = 0; i < favList.getCount(); ++i) + { + HANDLE hContact = favList[i]->getHandle(); + TCHAR *name = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); + AVATARCACHEENTRY *avatar = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)hContact, 0); + int status = DBGetContactSettingWord(hContact, (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0), "Status", ID_STATUS_OFFLINE); + + Send("SetContact("); + Send(i); + Send(", "); + Send((int)hContact); + Send(", '"); + SendQuoted(name); + Send("', "); + Send(status); + Send(", '"); + SendQuoted(avatar ? avatar->szFilename : ""); + Send("');\r\n"); + } + Send("} catch(e) {}\r\n"); + } + + void Send(char *s) + { + m_socket->Send(s); + } + +#ifdef UNICODE + void Send(WCHAR *ws) + { + char *s = mir_utf8encodeW(ws); + m_socket->Send(s); + mir_free(s); + } +#endif + + void Send(int i) + { + char buf[32]; + wsprintfA(buf, "%d", i); + Send(buf); + } + + template + void SendQuoted(const XCHAR *s) + { + int length = 0; + const XCHAR *p; + for (p = s; *p; p++) + { + if (*p == '\'' || *p == '\\' || *p == '\"') + length++; + length++; + } + XCHAR *buf = (XCHAR *)mir_alloc(sizeof(XCHAR) * (length + 1)); + XCHAR *q = buf; + for (p = s; *p; p++) + { + if (*p == '\'' || *p == '\\' || *p == '\"') + { + *q = '\\'; + q++; + } + *q = *p; + q++; + } + *q = 0; + Send(buf); + mir_free(buf); + } +}; + +class CHttpProcessorFactory: public IConnectionProcessorFactory +{ +public: + IConnectionProcessor *Create(CSocket *s) + { + return new CHttpProcessor(s); + } +}; + +static CHttpProcessorFactory g_httpProcessorFactory; +static CServer g_httpServer; + +void LoadHttpApi() +{ + g_httpServer.Start(60888, &g_httpProcessorFactory, true); +} + +void UnloadHttpApi() +{ + g_httpServer.Stop(); +} diff --git a/plugins/FavContacts/src/http_api.h b/plugins/FavContacts/src/http_api.h new file mode 100644 index 0000000000..cccb7ea13b --- /dev/null +++ b/plugins/FavContacts/src/http_api.h @@ -0,0 +1,7 @@ +#ifndef http_api_h__ +#define http_api_h__ + +void LoadHttpApi(); +void UnloadHttpApi(); + +#endif // http_api_h__ diff --git a/plugins/FavContacts/src/main.cpp b/plugins/FavContacts/src/main.cpp new file mode 100644 index 0000000000..5e5a1f1f9a --- /dev/null +++ b/plugins/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, GSMDF_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, GSMDF_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; +} diff --git a/plugins/FloatingContacts/FltCont_10.sln b/plugins/FloatingContacts/FltCont_10.sln new file mode 100644 index 0000000000..823e987bbd --- /dev/null +++ b/plugins/FloatingContacts/FltCont_10.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FltCont", "FltCont_10.vcxproj", "{9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Win32 = Debug Unicode|Win32 + Debug|Win32 = Debug|Win32 + Release Unicode|Win32 = Release Unicode|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Debug|Win32.ActiveCfg = Debug|Win32 + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Debug|Win32.Build.0 = Debug|Win32 + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Release|Win32.ActiveCfg = Release|Win32 + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/FloatingContacts/FltCont_10.vcxproj b/plugins/FloatingContacts/FltCont_10.vcxproj new file mode 100644 index 0000000000..a76fd934d2 --- /dev/null +++ b/plugins/FloatingContacts/FltCont_10.vcxproj @@ -0,0 +1,254 @@ + + + + + Debug Unicode + Win32 + + + Debug + Win32 + + + Release Unicode + Win32 + + + Release + Win32 + + + + FltCont + {9290A9CC-3FDA-4FD6-A8A2-04AD4BA1C856} + + + + DynamicLibrary + false + Unicode + + + DynamicLibrary + false + Unicode + + + DynamicLibrary + false + MultiByte + + + DynamicLibrary + false + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + false + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + fltcontacts + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + EnableFastChecks + MultiThreadedDebug + Use + stdhdr.h + Level4 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + + + Msimg32.lib;%(AdditionalDependencies) + true + true + false + + + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Full + Size + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + true + true + Use + stdhdr.h + Level4 + ProgramDatabase + OnlyExplicitInline + true + + + NDEBUG;%(PreprocessorDefinitions) + + + Msimg32.lib;%(AdditionalDependencies) + true + true + true + true + false + + + MachineX86 + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + EnableFastChecks + MultiThreadedDebug + Use + stdhdr.h + Level4 + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + + + Msimg32.lib;%(AdditionalDependencies) + true + true + false + + + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Full + Size + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + true + true + Use + stdhdr.h + Level4 + ProgramDatabase + OnlyExplicitInline + true + + + NDEBUG;%(PreprocessorDefinitions) + + + Msimg32.lib;%(AdditionalDependencies) + true + true + true + true + false + + + MachineX86 + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + true + true + true + true + + + + true + true + true + true + + + + + + + + + + \ No newline at end of file diff --git a/plugins/FloatingContacts/FltCont_10.vcxproj.filters b/plugins/FloatingContacts/FltCont_10.vcxproj.filters new file mode 100644 index 0000000000..4b33b8e646 --- /dev/null +++ b/plugins/FloatingContacts/FltCont_10.vcxproj.filters @@ -0,0 +1,76 @@ + + + + + {84999e29-bc79-471f-9875-ab09dde3a08a} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {715cbea0-9043-4420-8266-8083bb9d03e1} + h;hpp;hxx;hm;inl + + + {fd5f5482-d8cc-42d5-b4e9-5055d6618caa} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/plugins/FloatingContacts/Script.rc b/plugins/FloatingContacts/Script.rc new file mode 100644 index 0000000000..b1bbc9db7b --- /dev/null +++ b/plugins/FloatingContacts/Script.rc @@ -0,0 +1,2 @@ +#include "version.rc" +#include "fltcnt.rc" diff --git a/plugins/FloatingContacts/bitmap_funcs.cpp b/plugins/FloatingContacts/bitmap_funcs.cpp new file mode 100644 index 0000000000..3d92e7a9d8 --- /dev/null +++ b/plugins/FloatingContacts/bitmap_funcs.cpp @@ -0,0 +1,1239 @@ +/* +Popup Plus plugin for Miranda IM + +Copyright 2002 Luca Santarelli, + 2004-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 "stdhdr.h" +#include "bitmap_funcs.h" + +#include +#include + +#define PU_FONT_THRESHOLD 96 +#define PU_BMP_ACCURATE_ARITHMETICS + +#ifdef PU_BMP_ACCURATE_ARITHMETICS + #define PU_DIV255(x) ((x)/255) + #define PU_DIV128(x) ((x)/128) + typedef float pu_koef; +#else + #define PU_DIV255(x) ((x)>>8) + #define PU_DIV128(x) ((x)>>7) + typedef long pu_koef; +#endif + +MyBitmap::MyBitmap() +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; +} + +MyBitmap::MyBitmap(int w, int h) +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; + allocate(w,h); +} + +MyBitmap::MyBitmap(const char *fn, const char *fnAlpha) +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; + loadFromFile(fn, fnAlpha); +} + +MyBitmap::~MyBitmap() +{ + if (bitsSave) + delete [] bitsSave; + free(); +} + +void MyBitmap::setAlpha(BYTE level) +{ + if (!bits) return; + + GdiFlush(); + for (int i = 0; i < width*height; i++) + { + if (bits[i] & 0xff000000) + { + bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, geta(bits[i])*level/255); + } else + { + bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, level); + } + } +} + +void MyBitmap::setAlphaRect(int x1, int y1, int x2, int y2, BYTE level) +{ + if (!bits) return; + + GdiFlush(); + for (int i = y1; i < y2; i++) + for (int j = x1; j < x2; j++) + { + int idx = i * width + j; + if (bits[idx] & 0xff000000) + { + bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, geta(bits[idx])*level/255); + } else + { + bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, level); + } + } +} + +void MyBitmap::makeOpaque() +{ + if (!bits) return; + + GdiFlush(); + for (int i = 0; i < width*height; i++) + bits[i] |= 0xff000000; +} + +void MyBitmap::makeOpaqueRect(int x1, int y1, int x2, int y2) +{ + if (!bits) return; + + GdiFlush(); + for (int i = y1; i < y2; i++) + for (int j = x1; j < x2; j++) + { + int idx = i * width + j; + bits[idx] |= 0xff000000; + } +} + +void MyBitmap::saveAlpha(int x, int y, int w, int h) +{ + if (bitsSave) + delete [] bitsSave; + + GdiFlush(); + + if (!w) w = width; + if (!h) h = height; + + bitsSave = new COLOR32[w*h]; + COLOR32 *p1 = bitsSave; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + COLOR32 *p2 = bits + (y+i)*width + x; + p1 = bitsSave + i*w; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + *p1++ = *p2++; + } + } +} + +void MyBitmap::restoreAlpha(int x, int y, int w, int h) +{ + if (!bitsSave) + return; + + GdiFlush(); + + if (!w) w = width; + if (!h) h = height; + + COLOR32 *p1 = bitsSave; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + COLOR32 *p2 = bits + (y+i)*width + x; + p1 = bitsSave + i*w; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + if ((*p1&0x00ffffff) != (*p2&0x00ffffff)) + { + *p2 |= 0xff000000; + } else + { + *p2 = (*p2&0x00ffffff) | (*p1&0xff000000); + } + ++p1; + ++p2; + } + } + + delete [] bitsSave; + bitsSave = 0; +} + +void MyBitmap::DrawBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h) +{ + if (!(bits && inbits)) return; + + GdiFlush(); + + float kx = (float)inw / w; + float ky = (float)inh / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = inbits[int(i*ky)*inw + int(j*kx)]; + } + } +} + +void MyBitmap::BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h) +{ + if (!(bits && inbits)) return; + + GdiFlush(); + + float kx = (float)inw / w; + float ky = (float)inh / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + COLOR32 src = inbits[int(i*ky)*inw + int(j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + } + } +} + +void MyBitmap::Blend(MyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + COLOR32 src = bmp->bits[int(i*ky)*bmp->width + int(j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + } + } +} + +void MyBitmap::Draw(MyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + + if (!x && !y && (w == width) && (h == height) && (w == bmp->width) && (h == bmp->height)) + { + // fast bitmap copy is possible good for animated avatars + CopyMemory(bits, bmp->bits, width*height*sizeof(COLOR32)); + return; + } + + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[int(i*ky)*bmp->width + int(j*kx)]; + } + } +} + +void MyBitmap::BlendColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// bits[(i+y)*width + (j+x)] = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])); + + long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + COLOR32 src = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 src = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha); + COLOR32 dst = bits[(i+y)*width + (j+x)]; +// long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + + } + } +} + +void MyBitmap::DrawColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + + long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + bits[(i+y)*width + (j+x)] = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// bits[(i+y)*width + (j+x)] = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])); + } + } +} + +void MyBitmap::BlendPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + float kx = (float)win / w; + float ky = (float)hin / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); +// bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void MyBitmap::BlendPartColorized(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + float kx = (float)win / w; + float ky = (float)hin / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + + long alpha = geta(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + COLOR32 src = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 src = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha); + COLOR32 dst = bits[(i+y)*width + (j+x)]; +// long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + +/* COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+(255-alpha)*getr(dst)/255, + getg(src)+(255-alpha)*getg(dst)/255, + getb(src)+(255-alpha)*getb(dst)/255, + geta(src)+(255-alpha)*geta(dst)/255 + );*/ +// bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void MyBitmap::DrawPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + float kx = (float)win / w; + float ky = (float)hin / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void MyBitmap::DrawNoAlpha(MyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + for (int i = 0; i < bmp->height; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < bmp->width; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[i*bmp->width + j]; + } + } +} + +static __forceinline int ReadP(long *p, int w, int h, int x, int y, int k) +{ + if (x<0) x=0; else if (x>=w) x=w-1; + if (y<0) y=0; else if (y>=h) y=h-1; + return p[(x+y*w)*4+k]; +} + +void MyBitmap::Blur(int w, int h) +{ + if ((w <= 0) || (h <= 0)) return; + + BYTE *buf_src = new BYTE[width*height*4]; + long *buf_tmp = new long[width*height*4]; + BYTE *buf_dst = (BYTE *)bits; + memcpy(buf_src, buf_dst, width*height*4); + + BYTE *src, *dst; + long *tmp; + + src = buf_src; + tmp = buf_tmp; + dst = buf_dst; + + int y; + + for (y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + for (int k = 0; k < 4; ++k) + { + int tot = src[0]; + if (x > 0) tot += tmp[-4]; + if (y > 0) tot += tmp[-width*4]; + if (x > 0 && y > 0) tot -= tmp[-(width+1)*4]; + *tmp = tot; + + ++src; + ++tmp; + } + } + } + + src = buf_src; + tmp = buf_tmp; + dst = buf_dst; + + float mul = 1.f/((w*2+1)*(h*2+1)); + for (y=0;yBlendBits((COLOR32 *)cbit, bmpColor.bmWidth, bmpColor.bmHeight, x, y, w, h); + + delete [] mbit; + delete [] cbit; + } else + { + this->saveAlpha(x,y,w,h); + DrawIconEx(this->getDC(), x, y, hic, w, h, 0, NULL, DI_NORMAL); + this->restoreAlpha(x,y,w,h); + } + + DeleteObject(info.hbmColor); + DeleteObject(info.hbmMask); +} + +//Base on code by Artem Shpynov +//from clist_modern plugin +//slightly modified and integrated to MyBitmap class +void MyBitmap::DrawText(TCHAR *str, int x, int y, int blur, int strength) +{ + SIZE sz; GetTextExtentPoint32(this->getDC(), str, lstrlen(str), &sz); + sz.cx += (blur+2)*2; sz.cy += (blur+2)*2; + x -= blur+2; y -= blur+2; + + static BYTE pbGammaWeight[256]={0}; + static BOOL bGammaWeightFilled=FALSE; + + if (!bGammaWeightFilled) + { + int i; + for(i=0;i<256;i++) + { + double f; + double gamma=(double)700/1000; + + f=(double)i/255; + f=pow(f,(1/gamma)); + + pbGammaWeight[i]=(BYTE)(255*f); + } + bGammaWeightFilled=1; + } + + MyBitmap tmp(sz.cx, sz.cy); + HFONT hfnTmp = (HFONT)SelectObject(tmp.getDC(), GetCurrentObject(this->getDC(), OBJ_FONT)); + + RECT rc; SetRect(&rc, 0, 0, sz.cx, sz.cy); + SetTextColor(tmp.getDC(), RGB(255,255,255)); + SetBkColor(tmp.getDC(), RGB(0,0,0)); + ExtTextOutA(tmp.getDC(), 0, 0, ETO_OPAQUE, &rc, "", 0, NULL); + ::DrawText(tmp.getDC(), str, lstrlen(str), &rc, DT_CENTER|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER); + SelectObject(tmp.getDC(), hfnTmp); + + GdiFlush(); + + if (blur) + { + for (int i = 0; i < sz.cy; i++) + { + COLOR32 *row_src = tmp.bits + i * tmp.width; + + for (int j = 0; j < sz.cx; j++) + { + COLOR32 cl = row_src[j]; + if (!cl) continue; + + int a1 = (getr(cl) + getg(cl) + getb(cl)) / 3; + row_src[j] = rgba(a1, a1, a1, a1); + } + } + tmp.Blur(blur, blur); + tmp.IncreaseAlpha((float)(strength ? strength : blur)); + } + + // use Get*Value for COLORREF and get* for COLOR32 + COLOR32 textColor = GetTextColor(this->getDC()); + COLOR32 r = GetRValue(textColor); + COLOR32 g = GetGValue(textColor); + COLOR32 b = GetBValue(textColor); + + int minx = max(0,-x); + int miny = max(0,-y); + int maxx = min(sz.cx, width-x); + int maxy = min(sz.cy, height-y); + + for (int i = miny; i < maxy; i++) + { + COLOR32 *row_dst = bits + (i+y) * width + x; + COLOR32 *row_src = tmp.bits + i * tmp.width; + + for (int j = minx; j < maxx; j++) + { + COLOR32 bx,rx,gx,mx; + { + bx=pbGammaWeight[getb(row_src[j])]; + gx=pbGammaWeight[getg(row_src[j])]; + rx=pbGammaWeight[getr(row_src[j])]; + } + + bx=(pbGammaWeight[bx]*(255-b)+bx*(b))/255; + gx=(pbGammaWeight[gx]*(255-g)+gx*(g))/255; + rx=(pbGammaWeight[rx]*(255-r)+rx*(r))/255; + + mx=(BYTE)(max(max(bx,rx),gx)); + + if (1) + { + bx=(bx>3):bx; + rx=(rx>3):rx; + gx=(gx>3):gx; + // reduce boldeness at white fonts + } + COLOR32 cl = row_dst[j]; + if (mx) + { + COLOR32 rrx,grx,brx; + COLOR32 rlx,glx,blx; + COLOR32 axx=geta(cl); + COLOR32 mmx=(bx+gx+rx)/3; + COLOR32 nx=mmx;;//pbGammaWeight[mx];// + { + //Normalize components to alpha level + bx=(nx*(255-axx)+bx*axx)/255; + gx=(nx*(255-axx)+gx*axx)/255; + rx=(nx*(255-axx)+rx*axx)/255; + mx=(nx*(255-axx)+mmx*axx)/255; + } + { + blx = getb(cl); + glx = getg(cl); + rlx = getr(cl); + + brx=(b-blx)*bx/255; + grx=(g-glx)*gx/255; + rrx=(r-rlx)*rx/255; + row_dst[j] = rgba(rlx+rrx, glx+grx, blx+brx, mx+(255-mx)*axx/255); + } + } + } + } +} + +// based on code by Yuriy Zaporozhets from: +// http://www.codeproject.com/gdi/coolrgn.asp?df=100&forumid=739&exp=0&select=6341 +// slightly modified to integrate with MyBitmap class. +HRGN MyBitmap::buildOpaqueRgn(int level, bool opaque) +{ + GdiFlush(); + + const int addRectsCount = 64; + int rectsCount = addRectsCount; + PRGNDATA pRgnData = (PRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + LPRECT pRects = (LPRECT)(&pRgnData->Buffer); + + memset(pRgnData, 0, sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)); + pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); + pRgnData->rdh.iType = RDH_RECTANGLES; + + int first = 0; + bool wasfirst = false; + bool ismask = false; + for (int i = 0; i < height; i++) + { + int j; // we will need j after the loop! + for (j = 0; j < width; j++) + { + ismask = opaque ? (int)geta(this->getRow(i)[j]) > level : (int)geta(this->getRow(i)[j]) < level; + if (wasfirst) + { + if (!ismask) + { + SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1); + if ((int)(pRgnData->rdh.nCount) >= rectsCount) + { + rectsCount += addRectsCount; + LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT)); + delete pRgnData; + pRgnData = pRgnDataNew; + pRects = (LPRECT)(&pRgnData->Buffer); + } + wasfirst = false; + } + } else + if (ismask) // set wasfirst when mask is found + { + first = j; + wasfirst = true; + } + } + + if (wasfirst && ismask) + { + SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1); + if ((int)(pRgnData->rdh.nCount) >= rectsCount) + { + rectsCount += addRectsCount; + LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT)); + delete pRgnData; + pRgnData = pRgnDataNew; + pRects = (LPRECT)(&pRgnData->Buffer); + } + wasfirst = false; + } + + } + + HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData); + delete pRgnData; + return hRgn; +} + +static int hex2dec(char hex) +{ + if ((hex >= '0') && (hex <= '9')) + return hex - '0'; + if ((hex >= 'a') && (hex <= 'f')) + return hex - 'a' + 0xa; + if ((hex >= 'A') && (hex <= 'F')) + return hex - 'A' + 0xa; + return 0; +} + +bool MyBitmap::loadFromFile_pixel(const char *fn, const char *fnAlpha) +{ + allocate(1,1); + int r, g, b, a=255; + const char *p = fn + lstrlenA("pixel:"); + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + *bits = rgba(r,g,b,a); + return true; +} + +bool MyBitmap::loadFromFile_gradient(const char *fn, const char *fnAlpha) +{ + const char *p = fn + lstrlenA("gradient:"); + + if (*p == 'h') allocate(256,1); + else allocate(1,256); + + int r, g, b, a=255; + + p += 2; + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + COLOR32 from = rgba(r,g,b,a); + + p += 7; + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + COLOR32 to = rgba(r,g,b,a); + + for (int i = 0; i < 256; ++i) + { + bits[i] = rgba( + ((255-i) * getr(from) + i * getr(to)) / 255, + ((255-i) * getg(from) + i * getg(to)) / 255, + ((255-i) * getb(from) + i * getb(to)) / 255, + 255 + ); + } + + return true; +} + +bool MyBitmap::loadFromFile_png(const char *fn, const char *fnAlpha) +{ + if (ServiceExists(MS_PNG2DIB)) + { + HANDLE hFile, hMap = 0; + BYTE *ppMap = 0; + long cbFileSize = 0; + BITMAPINFOHEADER *pDib; + BYTE *pDibBits; + if ((hFile = CreateFileA(fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) + if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) + if ((ppMap = (BYTE*)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL) + cbFileSize = GetFileSize(hFile, NULL); + if (cbFileSize) + { + PNG2DIB param; + param.pSource = ppMap; + param.cbSourceSize = cbFileSize; + param.pResult = &pDib; + if (CallService(MS_PNG2DIB, 0, (LPARAM)¶m)) + pDibBits = (BYTE*)(pDib+1); + else + cbFileSize = 0; + } + + if (ppMap) UnmapViewOfFile(ppMap); + if (hMap) CloseHandle(hMap); + if (hFile) CloseHandle(hFile); + + if (!cbFileSize) return false; + + BITMAPINFO *bi=(BITMAPINFO*)pDib; + BYTE *pt=(BYTE*)bi; + pt+=bi->bmiHeader.biSize; + + if (bi->bmiHeader.biBitCount != 32) + { + allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight)); + HDC hdcTmp = CreateCompatibleDC(getDC()); + HBITMAP hBitmap = CreateDIBitmap(getDC(), pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS); + SelectObject(hdcTmp, hBitmap); + BitBlt(this->getDC(), 0, 0, abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight), hdcTmp, 0, 0, SRCCOPY); + this->makeOpaque(); + DeleteDC(hdcTmp); + DeleteObject(hBitmap); + } else + { + allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight)); + BYTE *p2=(BYTE *)pt; + for (int y=0; ybmiHeader.biHeight; ++y) + { + BYTE *p1=(BYTE *)bits + (bi->bmiHeader.biHeight-y-1)*bi->bmiHeader.biWidth*4; + for (int x=0; xbmiHeader.biWidth; ++x) + { + p1[0]= p2[0]; + p1[1]= p2[1]; + p1[2]= p2[2]; + p1[3]= p2[3]; + p1 += 4; + p2 += 4; + } + } +// memcpy(bits, pt, bi->bmiHeader.biSizeImage); + premultipleChannels(); + } + + GlobalFree(pDib); + return true; + } else + { +// MessageBox(NULL, Translate("You need the png2dib plugin v. 0.1.3.x or later to process PNG images"), Translate("Error"), MB_OK); + return false; + } +} + +bool MyBitmap::loadFromFile_default(const char *fn, const char *fnAlpha) +{ + SIZE sz; + HBITMAP hBmpLoaded = (HBITMAP)LoadImageA(NULL, fn, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + if (!hBmpLoaded) + return false; + + BITMAP bm; GetObject(hBmpLoaded, sizeof(bm), &bm); + SetBitmapDimensionEx(hBmpLoaded, bm.bmWidth, bm.bmHeight, NULL); + + HDC dcTmp = CreateCompatibleDC(0); + GetBitmapDimensionEx(hBmpLoaded, &sz); + HBITMAP hBmpDcSave = (HBITMAP)SelectObject(dcTmp, hBmpLoaded); + + allocate(sz.cx, sz.cy); + BitBlt(dcBmp, 0, 0, width, height, dcTmp, 0, 0, SRCCOPY); + + DeleteObject(SelectObject(dcTmp, hBmpDcSave)); + DeleteDC(dcTmp); + + MyBitmap alpha; + if (fnAlpha && alpha.loadFromFile(fnAlpha) && + (alpha.getWidth() == width) && + (alpha.getHeight() == height) ) + { + for (int i = 0; i < width*height; i++) + bits[i] = (bits[i] & 0x00ffffff) | ( (alpha.bits[i] & 0x000000ff) << 24 ); + premultipleChannels(); + } else + { + makeOpaque(); + } + return true; +} + +bool MyBitmap::loadFromFile(const char *fn, const char *fnAlpha) +{ + if (bits) free(); + + if (!strncmp(fn, "pixel:", lstrlenA("pixel:"))) + { + return loadFromFile_pixel(fn, fnAlpha); + } else + if (!strncmp(fn, "gradient:", lstrlenA("gradient:"))) + { + return loadFromFile_gradient(fn, fnAlpha); + } else + { + char ext[5]; + memcpy(ext,fn+(strlen(fn)-4),5); + if (!lstrcmpiA(ext,".png")) + { + return loadFromFile_png(fn, fnAlpha); + } else + { + return loadFromFile_default(fn, fnAlpha); + } + } + // unreachable place + return false; +} + +void MyBitmap::allocate(int w, int h) +{ + if (dcBmp && (width == w) && (height == h)) return; + + width = w; + height = h; + + BITMAPINFO bi; + + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = w; + bi.bmiHeader.biHeight = -h; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + + if (dcBmp) + { + DeleteObject(SelectObject(dcBmp, hBmpSave)); + DeleteDC(dcBmp); + } + + hBmp = (HBITMAP)CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void **)&bits, 0, 0); + dcBmp = CreateCompatibleDC(0); + hBmpSave = (HBITMAP)SelectObject(dcBmp, hBmp); + + GdiFlush(); +} + +void MyBitmap::free() +{ + GdiFlush(); + + DeleteObject(SelectObject(dcBmp, hBmpSave)); + DeleteDC(dcBmp); + + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; +} + +void MyBitmap::premultipleChannels() +{ + GdiFlush(); + + for (int i = 0; i < width*height; i++) + bits[i] = rgba(getr(bits[i])*geta(bits[i])/255, getg(bits[i])*geta(bits[i])/255, getb(bits[i])*geta(bits[i])/255, geta(bits[i])); +} diff --git a/plugins/FloatingContacts/bitmap_funcs.h b/plugins/FloatingContacts/bitmap_funcs.h new file mode 100644 index 0000000000..b7f55a43d7 --- /dev/null +++ b/plugins/FloatingContacts/bitmap_funcs.h @@ -0,0 +1,127 @@ +/* +Popup Plus plugin for Miranda IM + +Copyright 2002 Luca Santarelli, + 2004-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. +*/ + +#ifndef __bitmap_funcs_h__ +#define __bitmap_funcs_h__ + +// This should make bitmap manipulations much easier... +class MyBitmap +{ +public: + typedef unsigned long COLOR32; + static inline COLOR32 RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0xff) + { + return (a << 24) | (r << 16) | (g << 8) | b; + }; + +private: + HBITMAP hBmpSave, hBmp; + HDC dcBmp; + COLOR32 *bits; + COLOR32 *bitsSave; + int width, height; + + void free(); + + bool loadFromFile_pixel(const char *fn, const char *fnAlpha = 0); + bool loadFromFile_gradient(const char *fn, const char *fnAlpha = 0); + bool loadFromFile_png(const char *fn, const char *fnAlpha = 0); + bool loadFromFile_default(const char *fn, const char *fnAlpha = 0); + void premultipleChannels(); + +public: + MyBitmap(); + MyBitmap(int w, int h); + MyBitmap(const char *fn, const char *fnAlpha = 0); + ~MyBitmap(); + void allocate(int w, int h); + + bool loadFromFile(const char *fn, const char *fnAlpha = 0); + + int getWidth() { return width; } + int getHeight() { return height; } + + HDC getDC() { return dcBmp; } + HBITMAP getBitmap() { return hBmp; } + + void setAlpha(BYTE level); + void setAlphaRect(int x1, int y1, int x2, int y2, BYTE level); + void setAlphaRect(RECT rc, BYTE level) { setAlphaRect(rc.left, rc.top, rc.right, rc.bottom, level); } + + void makeOpaque(); + void makeOpaqueRect(int x1, int y1, int x2, int y2); + void makeOpaqueRect(RECT rc) { makeOpaqueRect(rc.left, rc.top, rc.right, rc.bottom); } + + void saveAlpha(int x = 0, int y = 0, int w = 0, int h = 0); + void restoreAlpha(int x = 0, int y = 0, int w = 0, int h = 0); + + void DrawBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h); + void BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h); + + void DrawNoAlpha(MyBitmap *bmp, int x, int y, int w, int h); + + void Blend(MyBitmap *bmp, int x, int y, int w, int h); + void Draw(MyBitmap *bmp, int x, int y, int w, int h); + + void BlendColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color); + void DrawColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color); + + void BlendPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h); + void BlendPartColorized(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color); + void DrawPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h); +// void DrawPartNoAlpha(MyBitmap *bmp, int x, int y, int w, int h); +// void DrawPartColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color); + + void Blur(int w, int h); + void IncreaseAlpha(float q); + + void DrawIcon(HICON hic, int x, int y, int w = 0, int h = 0); + void DrawText(TCHAR *str, int x, int y, int blur=0, int strength = 0); + + __forceinline COLOR32 *getBits() { return bits; } + __forceinline COLOR32 *getRow(int row) { return bits + row * width; } + __forceinline COLOR32 *operator[] (int row) { return bits + row * width; } + + static __forceinline COLOR32 rgba(COLOR32 r, COLOR32 g, COLOR32 b, COLOR32 a) + { + return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); + } + static __forceinline COLOR32 getr(COLOR32 c) + { + return (c >> 16) & 0xff; + } + static __forceinline COLOR32 getg(COLOR32 c) + { + return (c >> 8) & 0xff; + } + static __forceinline COLOR32 getb(COLOR32 c) + { + return c & 0xff; + } + static __forceinline COLOR32 geta(COLOR32 c) + { + return (c >> 24) & 0xff; + } + + HRGN buildOpaqueRgn(int level = 64, bool opaque = true); +}; + +#endif // __bitmap_funcs_h__ diff --git a/plugins/FloatingContacts/docs/fltcontacts_langpack.txt b/plugins/FloatingContacts/docs/fltcontacts_langpack.txt new file mode 100644 index 0000000000..4aba1cd0db --- /dev/null +++ b/plugins/FloatingContacts/docs/fltcontacts_langpack.txt @@ -0,0 +1,68 @@ +;============================================================ +; Module: fltcontacts.dll +; Plugin: Floating ontacts +; Versions: 0.1.1.9 +; URL: http://www.miranda-im.org/ +;============================================================ + +[Floating Contacts] + + +;Menu +[Remove thumb] + +[Hide all thumbs] + +[Show all thumbs] + + +;Hotkeys +[Show/Hide all thumbs] + + +;Properties +;Main Features +[Main Features] + +[Hiding contacts] + +[Hide offline contacts] + +[Hide all contacts] + +[Hide when a fulscreen app is active] + +[Hide when contact list is shown] + +[Stick together] + +[Use fixed width] + +[Show tooltips] + +[Miscellaneous] + +[0 = Default] + +[requires mToolTip or Tipper plugin] + +[Bring to front] + +[Bring to front every] + + +;Appearance +[] + +[Opacity:] + +[Floating Contacts Background] + +[Draw border] + +[Left-top edges color:] + +[Right-bottom eges color:] + + +;End (Floating ontacts) \ No newline at end of file diff --git a/plugins/FloatingContacts/docs/fltcontacts_readme.txt b/plugins/FloatingContacts/docs/fltcontacts_readme.txt new file mode 100644 index 0000000000..b62a9c7ff6 --- /dev/null +++ b/plugins/FloatingContacts/docs/fltcontacts_readme.txt @@ -0,0 +1,91 @@ +****************** +Floating Contacts +****************** + +Description +=========== +This plugin is further development of Floating contacts plugin v1.0.0.7 from Iavor Vajarov (thx). + +New features +************ +- Showing a tooltip when mouse's hovering over a floating contact's window. +- Support MUID inteface of Miranda v0.8.0.0 and higher. +- Unicode aware. +- True alpha channel support on windows 2000+. +- "Bring to front" feature allows bring to front floating windows every x seconds. + With a lot of window may get backside effect, in this case set greater interval. +- And various other features. + +Requirements +************ +- Miranda v0.6.0.0 or higher. +- Tipper or mToolTip plugin for tooltip show. + +Changelog +========= + ++ Relative coordinates. + +---1.0.2.2--- +! Fixed gdi leak. +! Fixed possible crash. +! Fixed drawing 8-bit status icons. +! Show floating contacts on startup when "Hide when contact list is shown" option is checked. + +---1.0.2.1--- +! Wrong detection of hiding CList behind display border. +* Changed "Mouse In" highlight (must resolve some problem). +! Fixed "Single click" feature. +! Fixed memory leak. + +----1.0.2.0--- ++ True alpha channel support on windows 2000+. +! Minor fixed. +* Converted to C++. + +----1.0.1.1--- ++ Added "Dim idle contacts" feature. +! Fixed menu. +* Updated icons (added 256 colors icons). +* Changed painting. +* Changed moving. + +----1.0.1.0--- ++ Unicode aware. ++ Added russian langpack. +* Updated langpack. +! Fixed showing of nicks, containing "&". ++ Added feature "Single click interface". ++ Added hotkeys for "Show/Hide all thumbs" and "Hide when contact list is showing". +! Fixed refresh icon. ++ Added "Hide when contact list is showing" feature. + +----1.0.0.9--- +! Fixed show of floating contact's windows if check "Hide all contacts". ++ Added "Bring to front" feature. The feature provide keeping floating contact's windows on top. +* Unified plugin name in service, db setting and db contacts settings. + To keep your old settings just rename module settings branch "Floating contacts" in database to "FloatingContacts" (use DBE++). +! Fixed font size. +* Reformed options. +- Deleted support Miranda version lower then 0.6.0.0. ++ Added MUID. +* New icons. + +----1.0.0.8--- +! Fixed coordinate floating contact's window when it is dragged. +! Fixed name change. ++ Added showing of tooltip when mouse's hovering over a floating contact's window (requires Tipper or mToolTip plugin). + +Symbols used in changelog +-------------- ++ : new feature +* : changed +! : bufgix +- : feature removed or disabled because of pending bugs +-------------- + +Author +====== +Created by Iavor Vajarov ( ivajarov code bg ). +Further development by Kosh&chka ( ell-6 ya ru ). + diff --git a/plugins/FloatingContacts/docs/fltcontacts_russian_langpack.txt b/plugins/FloatingContacts/docs/fltcontacts_russian_langpack.txt new file mode 100644 index 0000000000..2ae3442f7a --- /dev/null +++ b/plugins/FloatingContacts/docs/fltcontacts_russian_langpack.txt @@ -0,0 +1,70 @@ +;============================================================ +; Module: fltcontacts.dll +; Plugin: Floating ontacts +; Versions: 0.1.1.9 +; Translators: SAOPP +; URL: http://www.miranda-im.org/ +;============================================================ +[Floating Contacts] + + +;Menu +[Remove thumb] + +[Hide all thumbs] + +[Show all thumbs] + + +;Hotkeys +[Show/Hide all thumbs] +/ + +;Properties +;Main Features +[Main Features] + +[Hiding contacts] + +[Hide offline contacts] + +[Hide all contacts] + +[Hide when a fulscreen app is active] + +[Hide when contact list is shown] + +[Stick together] + +[Use fixed width] + +[Show tooltips] + +[Miscellaneous] + +[0 = Default] +0= +[requires mToolTip or Tipper plugin] + mToolTip Tipper +[Bring to front] + +[Bring to front every] + + +;Appearance +[] + +[Opacity:] +: +[Floating Contacts Background] + : +[Draw border] + +[Left-top edges color:] + -: +[Right-bottom eges color:] + -: + +;End (Floating ontacts) + + diff --git a/plugins/FloatingContacts/filedrop.cpp b/plugins/FloatingContacts/filedrop.cpp new file mode 100644 index 0000000000..09fe2dace2 --- /dev/null +++ b/plugins/FloatingContacts/filedrop.cpp @@ -0,0 +1,368 @@ +#include "stdhdr.h" + +static void ProcessDroppedItems ( char **ppDroppedItems, int nCount, char **ppFiles ); +static int CountDroppedFiles ( char **ppDroppedItems, int nCount ); +static BOOL OnDropFiles ( HDROP hDrop, ThumbInfo *pThumb ); + +HRESULT STDMETHODCALLTYPE CDropTarget::QueryInterface(REFIID riid,LPVOID *ppvObj) +{ + if ( IsEqualIID( riid, IID_IDropTarget ) ) + { + *ppvObj = this; + this->AddRef(); + return S_OK; + } + + *ppvObj=NULL; + + return ( E_NOINTERFACE ); +} + +ULONG STDMETHODCALLTYPE CDropTarget::AddRef( ) +{ + return ++this->refCount; +} + +ULONG STDMETHODCALLTYPE CDropTarget::Release( ) +{ + int res = --this->refCount; + if (!res) delete this; + return res; +} + + +HRESULT STDMETHODCALLTYPE CDropTarget::DragOver( DWORD fKeyState, POINTL pt, DWORD *pdwEffect ) +{ + *pdwEffect = 0; + + if( hwndCurDrag == NULL ) + { + *pdwEffect = DROPEFFECT_NONE; + } + else + { + *pdwEffect |= DROPEFFECT_COPY; + } + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE CDropTarget::DragEnter( IDataObject *pData, DWORD fKeyState, POINTL pt, DWORD *pdwEffect) +{ + HWND hwnd = NULL; + POINT shortPt; + FORMATETC feFile = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + FORMATETC feText = { CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + ThumbInfo *pThumb; + + if ( S_OK == pData->QueryGetData( &feFile ) || + S_OK == pData->QueryGetData( &feText ) ) + { + shortPt.x = pt.x; + shortPt.y = pt.y; + + hwnd = WindowFromPoint( shortPt ); + + if ( pThumb = thumbList.FindThumb( hwnd ) ) + { + hwndCurDrag = hwnd; + pThumb->ThumbSelect( TRUE ); + } + } + + return DragOver( fKeyState, pt, pdwEffect); +} + + +HRESULT STDMETHODCALLTYPE CDropTarget::DragLeave( ) +{ + ThumbInfo *pThumb = thumbList.FindThumb( hwndCurDrag ); + + if ( NULL != pThumb ) + { + pThumb->ThumbDeselect( TRUE ); + } + + hwndCurDrag = NULL; + + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE CDropTarget::Drop( IDataObject *pData,DWORD fKeyState,POINTL pt,DWORD *pdwEffect) +{ + FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stg; + HDROP hDrop = NULL; + ThumbInfo *pThumb = NULL; + char *pText = NULL; + BOOL bFormatText = FALSE; + + *pdwEffect = DROPEFFECT_NONE; + + + if( hwndCurDrag == NULL ) return( S_OK ); + + pThumb = (ThumbInfo*)GetWindowLong( hwndCurDrag, GWL_USERDATA ); + if ( pThumb == NULL ) return( S_OK ); + + if ( S_OK != pData->GetData( &fe,&stg ) ) + { + fe.cfFormat = CF_TEXT; + + if ( S_OK != pData->GetData( &fe,&stg ) ) + { + return( S_OK ); + } + else + { + bFormatText = TRUE; + } + } + + + + if ( !bFormatText ) + { + hDrop = (HDROP)stg.hGlobal; + + if ( hDrop != NULL ) + { + OnDropFiles( hDrop, pThumb ); + } + } + else + { + pText = (char*)GlobalLock( stg.hGlobal ); + + if ( pText != NULL ) + { + SendMsgDialog( hwndCurDrag, pText ); + GlobalUnlock( stg.hGlobal ); + } + } + + if( stg.pUnkForRelease != NULL ) + { + stg.pUnkForRelease->Release( ); + } + else + { + GlobalFree( stg.hGlobal ); + } + + DragLeave( ); + + return S_OK; +} + +/////////////////////////////////////////////////////// +// Send files processing + +BOOL OnDropFiles( HDROP hDrop, ThumbInfo *pThumb ) +{ + BOOL bSuccess = FALSE; + UINT nFilesCount = 0; + UINT iItem = 0; + char **ppFiles = NULL; + char **ppDroppedItems = NULL; + UINT nDroppedItemsCount = 0; + char szFilename[ MAX_PATH ]; + + + nDroppedItemsCount = DragQueryFile( hDrop, 0xFFFFFFFF, NULL, 0 ); + + ppDroppedItems = ( char** )malloc( sizeof(char*)*( nDroppedItemsCount + 1 ) ); + + if ( ppDroppedItems == NULL ) + { + return( FALSE ); + } + + ppDroppedItems[ nDroppedItemsCount ] = NULL; + + for( iItem = 0; iItem < nDroppedItemsCount; ++iItem ) + { + DragQueryFileA( hDrop, iItem, szFilename, sizeof( szFilename ) ); + ppDroppedItems[ iItem ] = _strdup( szFilename ); + } + + nFilesCount = CountDroppedFiles( ppDroppedItems, nDroppedItemsCount ); + + ppFiles = ( char** )malloc( sizeof( char *)* ( nFilesCount+1 ) ); + + if ( ppFiles == NULL ) + { + return( FALSE ); + } + + ppFiles[ nFilesCount] = NULL; + + ProcessDroppedItems( ppDroppedItems, nDroppedItemsCount, ppFiles ); + + bSuccess = (BOOL)CallService( MS_CLIST_CONTACTFILESDROPPED, (WPARAM)pThumb->hContact, (LPARAM)ppFiles ); + + // Cleanup + for( iItem = 0; ppDroppedItems[ iItem ]; ++iItem ) + { + free( ppDroppedItems[ iItem ] ); + } + + free( ppDroppedItems ); + + for( iItem = 0; iItem < nFilesCount ; ++iItem ) + { + free( ppFiles[ iItem ] ); + } + + free( ppFiles ); + + return( bSuccess ); +} + + +static int CountFiles( char *szItem ) +{ + int nCount = 0; + WIN32_FIND_DATAA fd; + + HANDLE hFind = FindFirstFileA( szItem, &fd ); + + if ( hFind != INVALID_HANDLE_VALUE ) + { + do + { + if ( fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY ) + { + // Skip parent directories + if ( ( 0 != strcmp( fd.cFileName, "." ) ) && + ( 0 != strcmp( fd.cFileName, ".." ) ) ) + { + char szDirName[ MAX_PATH ]; + strncpy( szDirName, szItem, MAX_PATH - 1 ); + + if ( NULL != strstr( szItem, "*.*" ) ) + { + sprintf( szDirName + strlen( szDirName ) - 3, "%s\0", fd.cFileName ); + } + + ++nCount; + strcat( szDirName, "\\*.*" ); + nCount += CountFiles( szDirName ); + } + } + else + { + ++nCount; + } + } + while( FALSE != FindNextFileA( hFind, &fd ) ); + } + + return( nCount ); +} + + + +static void SaveFiles( char *szItem, char **ppFiles, int *pnCount ) +{ + + WIN32_FIND_DATAA fd; + + HANDLE hFind = FindFirstFileA( szItem, &fd ); + + if ( hFind != INVALID_HANDLE_VALUE ) + { + do + { + if ( fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY ) + { + // Skip parent directories + if ( ( 0 != strcmp( fd.cFileName, "." ) ) && + ( 0 != strcmp( fd.cFileName, ".." ) ) ) + { + char szDirName[ MAX_PATH ]; + strncpy( szDirName, szItem, MAX_PATH - 1 ); + + if ( NULL != strstr( szItem, "*.*" ) ) + { + sprintf( szDirName + strlen( szDirName ) - 3, "%s\0", fd.cFileName ); + } + + ppFiles[ *pnCount ] = _strdup( szDirName ); + ++( *pnCount ); + + strcat( szDirName, "\\*.*" ); + SaveFiles( szDirName, ppFiles, pnCount ); + + } + } + else + { + int nSize = sizeof(char) * ( strlen( szItem ) + strlen( fd.cFileName ) + sizeof( char ) ); + char *szFile = (char*) malloc( nSize ) ; + + strncpy( szFile, szItem, nSize - 1 ); + + if ( NULL != strstr( szFile, "*.*" ) ) + { + szFile[ strlen( szFile ) - 3 ] = '\0'; + strncat( szFile, fd.cFileName, MAX_PATH - 1 ); + } + + ppFiles[ *pnCount ] = szFile; + ++( *pnCount ); + } + } + while( FALSE != FindNextFileA( hFind, &fd ) ); + } +} + + +static void ProcessDroppedItems( char **ppDroppedItems, int nCount, char **ppFiles ) +{ + int i; + int fileCount = 0; + + for( i = 0; i < nCount; ++i ) + { + SaveFiles( ppDroppedItems[ i ], ppFiles, &fileCount ); + } +} + + +static int CountDroppedFiles( char **ppDroppedItems, int nCount ) +{ + int fileCount = 0; + int i; + + for( i = 0; i < nCount; ++i ) + { + fileCount += CountFiles( ppDroppedItems[ i ] ); + } + + return( fileCount ); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Init/destroy +void InitFileDropping() +{ + OleInitialize( NULL ); +} + +void FreeFileDropping(void) +{ + OleUninitialize(); +} + +void RegisterFileDropping( HWND hwnd, CDropTarget* pdropTarget ) +{ + RegisterDragDrop( hwnd, (IDropTarget*)pdropTarget ); +} + +void UnregisterFileDropping( HWND hwnd ) +{ + RevokeDragDrop( hwnd ); +} diff --git a/plugins/FloatingContacts/filedrop.h b/plugins/FloatingContacts/filedrop.h new file mode 100644 index 0000000000..ed03cdbf68 --- /dev/null +++ b/plugins/FloatingContacts/filedrop.h @@ -0,0 +1,26 @@ +/* This file is a modification of clcfiledrop.h originally + written by Richard Hughes*/ + +static HWND hwndCurDrag = NULL; + +class CDropTarget: public IDropTarget +{ +private: + unsigned long refCount; + +public: + CDropTarget(): refCount(0) {} + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,LPVOID *ppvObj); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE DragOver(DWORD fKeyState, POINTL pt, DWORD *pdwEffect); + HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pData, DWORD fKeyState, POINTL pt, DWORD *pdwEffect); + HRESULT STDMETHODCALLTYPE DragLeave(); + HRESULT STDMETHODCALLTYPE Drop(IDataObject *pData,DWORD fKeyState,POINTL pt,DWORD *pdwEffect); +}; + +void InitFileDropping(); +void FreeFileDropping(void); +void RegisterFileDropping( HWND hwnd, CDropTarget* pdropTarget ); +void UnregisterFileDropping( HWND hwnd ); diff --git a/plugins/FloatingContacts/fltcnt.rc b/plugins/FloatingContacts/fltcnt.rc new file mode 100644 index 0000000000..c341a349cc --- /dev/null +++ b/plugins/FloatingContacts/fltcnt.rc @@ -0,0 +1,232 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPT_FLTCONT DIALOGEX 0, 0, 277, 229 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0xCC +BEGIN + GROUPBOX "Hiding contacts",IDC_STATIC,4,4,269,52 + CONTROL "Hide offline contacts",IDC_CHK_HIDE_OFFLINE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,12,16,133,10 + CONTROL "Stick together",IDC_CHK_STICK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,12,89,95,11 + CONTROL "Use fixed width",IDC_CHK_WIDTH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,12,74,62,12 + EDITTEXT IDC_TXT_WIDTH,77,74,30,12,ES_RIGHT | ES_AUTOHSCROLL | + ES_NUMBER + CONTROL "",IDC_WIDTHSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | + UDS_NOTHOUSANDS | UDS_HOTTRACK,96,73,11,14 + LTEXT "pixels",IDC_LBL_WIDTH,111,75,27,8 + CONTROL "Hide all contacts",IDC_CHK_HIDE_ALL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,151,14,115,13 + CONTROL "Hide when a fulscreen app is active", + IDC_CHK_HIDE_WHEN_FULSCREEN,"Button",BS_AUTOCHECKBOX | + BS_MULTILINE | WS_TABSTOP,12,28,137,22 + CONTROL "Show tooltips",IDC_CHK_TIP,"Button",BS_AUTOCHECKBOX | + BS_MULTILINE | WS_TABSTOP,152,72,60,14 + EDITTEXT IDC_TXT_TIMEIN,214,73,35,12,ES_RIGHT | ES_AUTOHSCROLL | + ES_NUMBER + CONTROL "",IDC_TIMEINSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | + UDS_NOTHOUSANDS | UDS_HOTTRACK,242,72,11,14 + LTEXT "ms",IDC_LBL_TIMEIN,256,75,10,8 + GROUPBOX "Tooltips",IDC_STATIC,142,62,131,58 + GROUPBOX "Miscellaneous",IDC_STATIC,4,62,132,58 + LTEXT "0 = Default",IDC_LBL_TIMEIN_CMT,217,89,51,8 + LTEXT "requires mToolTip or Tipper plugin",IDC_STATIC,153,88, + 56,27 + GROUPBOX "Bring to front",IDC_STATIC,4,126,132,40 + CONTROL "Bring to front every",IDC_CHK_TOTOP,"Button", + BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,12,135,56,28 + EDITTEXT IDC_TXT_TOTOPTIME,68,142,30,12,ES_RIGHT | ES_AUTOHSCROLL | + ES_NUMBER + CONTROL "",IDC_TOTOPTIMESPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | + UDS_NOTHOUSANDS | UDS_HOTTRACK,85,141,11,14 + LTEXT "seconds",IDC_LBL_TOTOP,100,144,34,8 + CONTROL "Hide when contact list is shown", + IDC_CHK_HIDE_WHEN_CLISTSHOW,"Button",BS_AUTOCHECKBOX | + BS_MULTILINE | WS_TABSTOP,152,28,114,22 + CONTROL "Single click interface",IDC_CHK_SINGLECLK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,12,103,120,10 + CONTROL "Dim idle contacts",IDC_CHK_SHOWIDLE,"Button", + BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,152,138,116, + 20 +END + +IDD_OPT_SKIN DIALOGEX 0, 0, 277, 229 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0xCC +BEGIN + GROUPBOX "Fonts",IDC_STATIC,4,2,269,113 + COMBOBOX IDC_FONTID,12,15,253,87,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "same",IDC_STSAMETEXT,19,29,45,10,SS_CENTERIMAGE + CONTROL "Typeface",IDC_SAMETYPE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,64,29,52,10 + CONTROL "Size",IDC_SAMESIZE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,117,29,45,10 + CONTROL "Style",IDC_SAMESTYLE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,163,29,48,10 + CONTROL "Colour",IDC_SAMECOLOUR,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,212,29,53,10 + LTEXT "as:",IDC_STASTEXT,19,45,45,10,SS_CENTERIMAGE + COMBOBOX IDC_SAMEAS,64,42,201,88,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + CONTROL "",IDC_STHORZBAR,"Static",SS_ETCHEDHORZ,9,59,256,1 + COMBOBOX IDC_TYPEFACE,12,64,136,182,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_SCRIPT,156,64,60,68,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + COMBOBOX IDC_FONTSIZE,226,64,40,69,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + CONTROL "Bold",IDC_BOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12, + 78,45,10 + CONTROL "Italic",IDC_ITALIC,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,65,78,52,10 + CONTROL "Underline",IDC_UNDERLINE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,117,78,66,10 + CONTROL "",IDC_COLOUR,"ColourPicker",WS_TABSTOP,206,80,59,11 + EDITTEXT IDC_SAMPLE,63,94,151,16,ES_CENTER | ES_READONLY | NOT + WS_TABSTOP + CONTROL "Slider1",IDC_SLIDER_OPACITY,"msctls_trackbar32",TBS_TOP | + TBS_NOTICKS | WS_TABSTOP,178,162,67,16 + CTEXT "100 %",IDC_OPACITY,245,166,25,8 + GROUPBOX "Border",IDC_STATIC,4,116,269,38 + CONTROL "Draw border",IDC_DRAWBORDER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,11,126,81,10 + LTEXT "Left-top edges color:",IDC_STATIC,11,139,76,8,NOT + WS_GROUP + CONTROL "",IDC_LTEDGESCOLOR,"ColourPicker",WS_TABSTOP,87,138,32, + 10 + LTEXT "Right-bottom eges color:",IDC_STATIC,128,139,87,8,NOT + WS_GROUP + CONTROL "",IDC_RBEDGESCOLOR,"ColourPicker",WS_TABSTOP,217,138,32, + 10 + GROUPBOX "Background",IDC_STATIC,4,156,269,70 + LTEXT "Background colour:",IDC_STATIC,13,166,72,8,NOT WS_GROUP + CONTROL "",IDC_BKGCOLOUR,"ColourPicker",WS_TABSTOP,87,166,32,10 + CONTROL "Use background bitmap",IDC_BITMAP,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,179,115,10 + EDITTEXT IDC_FILENAME,131,179,111,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_BROWSE,245,179,15,11 + CONTROL "Stretch to width",IDC_STRETCHH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,13,201,100,10 + CONTROL "Stretch to height",IDC_STRETCHV,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,131,201,101,10 + CONTROL "Tile horizontally",IDC_TILEH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,13,212,102,10 + CONTROL "Tile vertically",IDC_TILEV,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,131,212,101,10 + CONTROL "Stretch proportionally",IDC_PROPORTIONAL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,190,101,10 + LTEXT "Opacity:",IDC_STATIC,129,166,52,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPT_FLTCONT, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 273 + VERTGUIDE, 12 + VERTGUIDE, 22 + TOPMARGIN, 4 + BOTTOMMARGIN, 225 + HORZGUIDE, 18 + END + + IDD_OPT_SKIN, DIALOG + BEGIN + BOTTOMMARGIN, 226 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_HIDE ICON "hide.ico" +IDI_SHOW ICON "show.ico" + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/FloatingContacts/fltcont.h b/plugins/FloatingContacts/fltcont.h new file mode 100644 index 0000000000..3d725d71bc --- /dev/null +++ b/plugins/FloatingContacts/fltcont.h @@ -0,0 +1,191 @@ + +#ifndef __FLTCONT_H__ +#define __FLTCONT_H__ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +///////////////////////////////////////////////////////////////////////////// +// + +#define WND_CLASS _T("MirandaThumbsWnd") +#define WM_REFRESH_CONTACT WM_USER + 0x100 + +#ifndef WS_EX_LAYERED + #define WS_EX_LAYERED 0x00080000 +#endif + +#ifndef LWA_ALPHA + #define LWA_ALPHA 0x00000002 +#endif + +#ifndef ULW_ALPHA + #define ULW_ALPHA 0x00000002 +#endif + +#define TIMERID_SELECT_T 1 +#define TIMERID_HOVER_T 2 +#define TIMERID_TOTOP_T 3 +#define TIMERID_LEAVE_T 4 + + +#if WINVER < 0x0500 + #define SM_XVIRTUALSCREEN 76 + #define SM_YVIRTUALSCREEN 77 + #define SM_CXVIRTUALSCREEN 78 + #define SM_CYVIRTUALSCREEN 79 +#endif + +///////////////////////////////////////////////////////////////////////////// +// + +enum +{ + FLT_FONTID_CONTACTS, + FLT_FONTID_INVIS, + FLT_FONTID_OFFLINE, + FLT_FONTID_OFFINVIS, + FLT_FONTID_NOTONLIST, + FLT_FONTIDS, +}; + +#define DBFONTF_BOLD 1 +#define DBFONTF_ITALIC 2 +#define DBFONTF_UNDERLINE 4 + +///////////////////////////////////////////////////////////////////////////// +// + +#define FLT_DEFAULT_DRAWBORDER TRUE +#define FLT_DEFAULT_LTEDGESCOLOR GetSysColor(COLOR_3DHILIGHT) +#define FLT_DEFAULT_RBEDGESCOLOR GetSysColor(COLOR_3DDKSHADOW) +#define FLT_DEFAULT_BKGNDCOLOR GetSysColor(COLOR_3DFACE) +#define FLT_DEFAULT_BKGNDUSEBITMAP FALSE +#define FLT_DEFAULT_BKGNDBITMAPOPT CLB_STRETCH + +///////////////////////////////////////////////////////////////////////////// +// + +#define sModule "FloatingContacts" + +#define TOTOPTIME_P 1000 +#define TOTOPTIME_MAX (15*(60000/TOTOPTIME_P)) +#define TOTOPTIME_DEF (3*(60000/TOTOPTIME_P)) + +#define MAXRCOOR 32767.0 +#define DB_POS_GETX(pos) (short)(((float)(short)(LOWORD(pos))*(float)GetSystemMetrics(SM_CXSCREEN))/MAXRCOOR+0.5) +#define DB_POS_GETY(pos) (short)(((float)(short)(HIWORD(pos))*(float)GetSystemMetrics(SM_CYSCREEN))/MAXRCOOR+0.5) +#define DB_POS_MAKE_XY(x, y) MAKELONG((short)(((float)x*MAXRCOOR)/(float)GetSystemMetrics(SM_CXSCREEN)+0.5), (short)(((float)y*MAXRCOOR)/(float)GetSystemMetrics(SM_CYSCREEN)+0.5)) + +extern HINSTANCE hInst; +extern BOOL bNT; +//extern BOOL bHideOffline; +//extern BOOL bHideAll; +//extern BOOL bHideWhenFullscreen; +//extern BOOL bMoveTogether; +//extern BOOL bFixedWidth; +//extern int nThumbWidth; +//extern BYTE thumbAlpha; +//extern BOOL bShowTip; +extern BOOL bEnableTip; +//extern WORD TimeIn; +//extern BOOL bToTop; +//extern WORD ToTopTime; +//extern BOOL bHideWhenCListShow; + +extern BOOL bIsCListShow; +extern HWND hwndMiranda; +extern HIMAGELIST himl; +extern RECT rcScreen; + +extern HFONT hFont[FLT_FONTIDS]; +extern COLORREF tColor[FLT_FONTIDS]; + +extern HPEN hLTEdgesPen; +extern HPEN hRBEdgesPen; +extern HBRUSH hBkBrush; +extern DWORD bkColor; +extern HBITMAP hBmpBackground; +extern WORD nBackgroundBmpUse; + + + +typedef struct _FCOptions +{ + BYTE thumbAlpha; + BOOL bHideOffline; + BOOL bHideAll; + BOOL bHideWhenFullscreen; + BOOL bMoveTogether; + BOOL bFixedWidth; + int nThumbWidth; + BOOL bShowTip; + WORD TimeIn; + BOOL bToTop; + WORD ToTopTime; + BOOL bHideWhenCListShow; + BOOL bUseSingleClick; + BOOL bShowIdle; +} +FCOptions; + +extern FCOptions fcOpt; + +extern BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); +extern BOOL (WINAPI *pUpdateLayeredWindow) + (HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, + COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags); + + +///////////////////////////////////////////////////////////////////////////// +// + +static __forceinline BOOL ImageList_GetIconSize_my(HIMAGELIST himl, SIZE &sz) +{ + int cx, cy; + BOOL res = ImageList_GetIconSize(himl, &cx, &cy); + sz.cx = cx; sz.cy = cy; + return res; +} + +void RegHotkey ( HANDLE hContact, HWND hwnd ); +BOOL IsStatusVisible ( int status ); +BOOL HideOnFullScreen (); +void SendMsgDialog ( HWND hwnd, char *pText ); +void SaveContactsPos ( void ); + +///////////////////////////////////////////////////////////////////////////// +// + +void +GetFontSetting + ( IN BOOL bFltContacts + , IN int nFontId + , IN LOGFONTA* lf + , IN COLORREF* colour + ); + +void +ApplyOptionsChanges(); + +void +OnStatusChanged(); + +void +SetThumbsOpacity + ( IN BYTE btAlpha + ); + +int +OnOptionsInitialize + ( IN WPARAM wParam + , IN LPARAM lParam + ); + +///////////////////////////////////////////////////////////////////////////// + +#endif // #ifndef __FLTCONT_H__ + +///////////////////////////////////////////////////////////////////////////// +// End Of File fltcont.h diff --git a/plugins/FloatingContacts/hide.ico b/plugins/FloatingContacts/hide.ico new file mode 100644 index 0000000000..941da6aeb9 Binary files /dev/null and b/plugins/FloatingContacts/hide.ico differ diff --git a/plugins/FloatingContacts/main.cpp b/plugins/FloatingContacts/main.cpp new file mode 100644 index 0000000000..9246e6f2b2 --- /dev/null +++ b/plugins/FloatingContacts/main.cpp @@ -0,0 +1,1331 @@ +/* +Miranda Floating Contacts plugin, created by Iavor Vajarov ( ivajarov@code.bg ) +http://miranda-icq.sourceforge.net/ + +Miranda fonts and colors settings by Ranger. +Extended bonts and backgrounds settings by Oleksiy Shurubura + + +This file is placed in the public domain. Anybody is free to use or +modify it as they wish with no restriction. + +This plugin has been tested to work under Windows ME, 2000 and XP. + +No warranty for any misbehaviour. +*/ + +#include "stdhdr.h" +#include "shlwapi.h" + +#include "version.h" + +#pragma comment ( lib, "comctl32.lib" ) +#pragma comment ( lib, "shlwapi.lib" ) + +#pragma warning ( default : 4201 ) + +//#define DB_POS_GETX(pos) LOWORD(pos) +//#define DB_POS_GETY(pos) HIWORD(pos) +//#define DB_POS_MAKE_XY(x, y) MAKELONG(x, y) + +BOOL (WINAPI *pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); +BOOL (WINAPI *pUpdateLayeredWindow) + (HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, + COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags); + +// Globals + +// TODO: move to some more approriate place, probably part of Thumbs manager +static void LoadContacts ( void ); +static void LoadContact ( HANDLE hContact ); + +// Internal funcs +static void RepaintWindow ( HWND hwnd, HDC hdc ); +static void LoadMenus (); +static void CreateThumbWnd ( TCHAR *ptszName, HANDLE hContact, int nX, int nY ); +static void RegisterWindowClass ( void ); +static void UnregisterWindowClass ( void ); +static void CleanUp ( void ); +static BOOL GetOSPlatform ( void ); +static void LoadDBSettings ( void ); +static void CreateThumbsFont ( void ); +static void CreateBackgroundBrush ( void ); +static int GetContactStatus ( HANDLE hContact ); +static void GetScreenRect ( void ); +extern void SetThumbsOpacity ( BYTE btAlpha ); +static int ClcStatusToPf2 ( int status ); + +static LRESULT __stdcall CommWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); +static LRESULT __stdcall newMirandaWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); + +static int OnContactDeleted ( WPARAM wParam,LPARAM lParam ); +static int OnContactIconChanged ( WPARAM wParam, LPARAM lParam ); +static int OnContactDrag ( WPARAM wParam, LPARAM lParam ); +static int OnContactDrop ( WPARAM wParam, LPARAM lParam ); +static int OnContactDragStop ( WPARAM wParam, LPARAM lParam ); +static int OnSkinIconsChanged ( WPARAM wParam, LPARAM lParam ); +static int OnContactSettingChanged ( WPARAM wParam, LPARAM lParam ); +static int OnStatusModeChange ( WPARAM wParam, LPARAM lParam ); +static int OnModulesLoded ( WPARAM wParam, LPARAM lParam ); +static int OnPrebuildContactMenu ( WPARAM wParam, LPARAM lParam ); + +static int OnContactMenu_Remove ( WPARAM wParam,LPARAM lParam ); +//static int OnContactMenu_HideAll ( WPARAM wParam,LPARAM lParam ); +static int OnMainMenu_HideAll ( WPARAM wParam,LPARAM lParam ); +static int OnHotKey_HideWhenCListShow( WPARAM wParam,LPARAM lParam ); +static VOID CALLBACK ToTopTimerProc ( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); + +WNDPROC oldMirandaWndProc; + + +HINSTANCE hInst = NULL; +HMODULE hUserDll = NULL; +PLUGINLINK *pluginLink = NULL; +LIST_INTERFACE li = {0}; +HFONT hFont[FLT_FONTIDS] = {NULL}; +COLORREF tColor[FLT_FONTIDS] = {0}; +HIMAGELIST himl = NULL; +HANDLE hevContactIcon = NULL; +HANDLE hevContactDrop = NULL; +HANDLE hevContactDragStop = NULL; +HANDLE hevSkinIcons = NULL; +HANDLE hevContactDrag = NULL; +HANDLE hevContactSetting = NULL; +HANDLE hevContactDeleted = NULL; +HANDLE hevOptionsInit = NULL; +HANDLE hevStatusMode = NULL; +HANDLE hevModules = NULL; +HANDLE hevPrebuildMenu = NULL; +HANDLE hNewContact = NULL; + +HPEN hLTEdgesPen = NULL; +HPEN hRBEdgesPen = NULL; +HBRUSH hBkBrush = NULL; +DWORD bkColor = 0; +HBITMAP hBmpBackground = NULL; +WORD nBackgroundBmpUse = CLB_STRETCH; + +HWND hwndMiranda = NULL; +BOOL bVersionOK = FALSE; +BOOL bNT = FALSE; +BOOL bDockHorz = TRUE; +//UINT nStatus = 0; +HMENU hContactMenu = NULL; +HANDLE hMenuItemRemove = NULL; +HANDLE hMenuItemHideAll = NULL; +HANDLE hMainMenuItemHideAll = NULL; +RECT rcScreen; +DWORD dwOfflineModes = 0; +BOOL bEnableTip = FALSE; +UINT_PTR ToTopTimerID = 0; +BOOL bIsCListShow = TRUE; + +HANDLE hRemoveThumb = NULL; +HANDLE hMainHideAllThumbs = NULL; +HANDLE hHideWhenCListShow = NULL; + +//Options + +FCOptions fcOpt = {0}; + +static void InitOptions(){ + fcOpt.thumbAlpha = 255; + fcOpt.bHideOffline = FALSE; + fcOpt.bHideAll = FALSE; + fcOpt.bHideWhenFullscreen = FALSE; + fcOpt.bMoveTogether = FALSE; + fcOpt.bFixedWidth = FALSE; + fcOpt.nThumbWidth = 0; + fcOpt.bShowTip = TRUE; + fcOpt.TimeIn = 0; + fcOpt.bToTop = TRUE; + fcOpt.ToTopTime = TOTOPTIME_DEF; + fcOpt.bHideWhenCListShow = FALSE; + fcOpt.bUseSingleClick = FALSE; + fcOpt.bShowIdle = TRUE; +} + + +PLUGININFO pluginInfo ={ + sizeof(PLUGININFO), + __PLUGIN_NAME, + 0, + __DESC, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + 0 +}; + +// {53C715A8-EB01-4136-A73C-441868610074} +#define MIID_FLTCONT { 0x53c715a8, 0xeb01, 0x4136, { 0xa7, 0x3c, 0x44, 0x18, 0x68, 0x61, 0x0, 0x74 } } + +static const MUUID interfaces[] = {MIID_FLTCONT, MIID_LAST}; + +extern "C" __declspec(dllexport) const MUUID * MirandaPluginInterfaces(void) +{ + return interfaces; +} + +PLUGININFOEX pluginInfoEx ={ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + 0, + __DESC, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + 0, + MIID_FLTCONT +}; + +_inline unsigned int MakeVer(int a,int b,int c,int d) +{ + return PLUGIN_MAKE_VERSION(a,b,c,d); +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) { + + if( mirandaVersion < MakeVer(MINIMAL_COREVERSION) ) return NULL; + pluginInfoEx.version=MakeVer(PRODUCT_VERSION); + return &pluginInfoEx; +} + + +/////////////////////////////////////////////////////// +// Load / unload +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) +{ + hInst = hinstDLL; + + switch ( fdwReason ) + { + case DLL_PROCESS_ATTACH: + break; + + case DLL_PROCESS_DETACH: + break; + } + + return( TRUE ); +} + + + +extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo( DWORD mirandaVersion ) +{ + if( mirandaVersion < MakeVer(MINIMAL_COREVERSION) ) return NULL; + pluginInfo.version=MakeVer(PRODUCT_VERSION); + return &pluginInfo; +} + + + +extern "C" int __declspec(dllexport) Load( PLUGINLINK *link ) +{ + SetLastError( 0 ); + InitOptions(); + pluginLink = link; + + mir_getLI(&li); + + hevModules = HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoded ); + bNT = GetOSPlatform(); + + if (hUserDll = LoadLibrary(_T("user32.dll"))) + { + pSetLayeredWindowAttributes = + (BOOL (WINAPI *)(HWND,COLORREF,BYTE,DWORD)) + GetProcAddress(hUserDll, "SetLayeredWindowAttributes"); + pUpdateLayeredWindow = + (BOOL (WINAPI *)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD)) + GetProcAddress(hUserDll, "UpdateLayeredWindow"); + } else + { + pSetLayeredWindowAttributes = NULL; + pUpdateLayeredWindow = NULL; + } + + return 0; +} + + + +extern "C" int __declspec(dllexport) Unload() +{ + CleanUp(); + return 0; +} + + + +static void CleanUp() +{ + int nFontId; + + UnhookEvent( hevContactIcon ); + UnhookEvent( hevContactDrag ); + UnhookEvent( hevContactDrop ); + UnhookEvent( hevContactDragStop ); + UnhookEvent( hevSkinIcons ); + UnhookEvent( hevContactDeleted ); + UnhookEvent( hevContactSetting ); + UnhookEvent( hevOptionsInit ); + UnhookEvent( hevStatusMode ); + UnhookEvent( hevModules ); + UnhookEvent( hevPrebuildMenu ); + + if(hRemoveThumb) + DestroyServiceFunction(hRemoveThumb); + if(hMainHideAllThumbs) + DestroyServiceFunction(hMainHideAllThumbs); + if(hHideWhenCListShow) + DestroyServiceFunction(hHideWhenCListShow); + +// while( pThumbsList != NULL ) +// RemoveThumb( pThumbsList ); + + if(ServiceExists(MS_HOTKEY_UNREGISTER)){ + CallService(MS_HOTKEY_UNREGISTER, 0, (LPARAM)(sModule "/MainHideAllThumbs")); + CallService(MS_HOTKEY_UNREGISTER, 0, (LPARAM)(sModule "/HideWhenCListShow")); + } + + if (NULL != hLTEdgesPen) + DeleteObject(hLTEdgesPen); + if (NULL != hRBEdgesPen) + DeleteObject(hRBEdgesPen); + if (NULL != hBmpBackground) + DeleteObject(hBmpBackground); + if (NULL != hBkBrush) + { + SetClassLong((HWND)WND_CLASS, GCL_HBRBACKGROUND, (LONG)NULL); + DeleteObject(hBkBrush); + hBkBrush=NULL; + } + + for (nFontId = 0; nFontId < FLT_FONTIDS; nFontId++) + if (NULL != hFont[nFontId]) + DeleteObject(hFont[nFontId]); + + UnregisterWindowClass(); + + FreeFileDropping(); + + if ( hUserDll != NULL ) + { + FreeLibrary( hUserDll ); + } +} + + + +/////////////////////////////////////////////////////// +// Hooked events +static int OnModulesLoded( WPARAM wParam, LPARAM lParam ) +{ + hevContactIcon = HookEvent( ME_CLIST_CONTACTICONCHANGED, OnContactIconChanged ); + hevSkinIcons = HookEvent( ME_SKIN_ICONSCHANGED, OnSkinIconsChanged ); + hevContactDrag = HookEvent( ME_CLUI_CONTACTDRAGGING, OnContactDrag ); + hevContactDrop = HookEvent( ME_CLUI_CONTACTDROPPED, OnContactDrop ); + hevContactDragStop = HookEvent( ME_CLUI_CONTACTDRAGSTOP, OnContactDragStop ); + hevContactSetting = HookEvent( ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged ); + hevContactDeleted = HookEvent( ME_DB_CONTACT_DELETED, OnContactDeleted ); + hevOptionsInit = HookEvent( ME_OPT_INITIALISE, OnOptionsInitialize ); + hevStatusMode = HookEvent( ME_CLIST_STATUSMODECHANGE, OnStatusModeChange ); + hevPrebuildMenu = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildContactMenu ); + hwndMiranda = (HWND)CallService( MS_CLUI_GETHWND, 0, 0 ); + + oldMirandaWndProc = (WNDPROC)SetWindowLong( hwndMiranda, GWL_WNDPROC, (LONG)newMirandaWndProc); + + + + // No thumbs yet +// pThumbsList = NULL; + bEnableTip = ServiceExists("mToolTip/ShowTip"); + + RegisterWindowClass(); + InitFileDropping(); + GetScreenRect(); + LoadDBSettings(); + CreateBackgroundBrush(); + CreateThumbsFont(); + LoadContacts(); + LoadMenus(); + + if(fcOpt.bToTop){ + fcOpt.ToTopTime = (fcOpt.ToTopTime<1)?1:fcOpt.ToTopTime; + fcOpt.ToTopTime = (fcOpt.ToTopTime>TOTOPTIME_MAX)?TOTOPTIME_MAX:fcOpt.ToTopTime; + ToTopTimerID=SetTimer(NULL, 0, fcOpt.ToTopTime*TOTOPTIME_P, ToTopTimerProc); + } + return( 0 ); +} + + +static int OnContactDeleted( WPARAM wParam, LPARAM lParam ) +{ + HANDLE hContact = ( HANDLE )wParam; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + if (!pThumb) return 0; + + pThumb->DeleteContactPos(); + thumbList.RemoveThumb(pThumb); + + return 0; +} + + +static int OnContactIconChanged( WPARAM wParam, LPARAM lParam ) +{ + HANDLE hContact = ( HANDLE )wParam; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + + if ( pThumb ) + { + pThumb->RefreshContactIcon( ( int )lParam ); + //pThumb->ThumbSelect( FALSE ); + //SetTimer( pThumb->hwnd, TIMERID_SELECT_T, 1000, NULL ); + } + + return 0; +} + + +static int OnContactDrag( WPARAM wParam, LPARAM lParam ) +{ + ThumbInfo *pNewThumb = NULL; + HANDLE hContact = ( HANDLE )wParam; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + TCHAR *ptName = (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME, wParam, (LPARAM)GCDNF_TCHAR ); + int idStatus = ID_STATUS_OFFLINE; + POINT pt; + GetCursorPos(&pt); + + if ( pThumb == NULL ) + { + idStatus = GetContactStatus( hContact ); + + if ( !fcOpt.bHideAll && !HideOnFullScreen() && ( !fcOpt.bHideOffline || IsStatusVisible( idStatus ) ) && (!fcOpt.bHideWhenCListShow || !bIsCListShow) ) + { +// CreateThumbWnd( pName, hContact, LOWORD( lParam ), HIWORD( lParam ) ); + CreateThumbWnd( ptName, hContact, pt.x, pt.y ); + pNewThumb = thumbList.FindThumbByContact( hContact ); + ShowWindow( pNewThumb->hwnd, SW_SHOWNA ); + hNewContact = hContact; + + OnStatusChanged(); + } + } + else if ( hContact == hNewContact ) + { +// PositionThumb( pThumb, (short)( LOWORD( lParam ) - 5 ), (short)( HIWORD( lParam ) - 5 ) ); + pThumb->PositionThumb( (short)( pt.x - 5 ), (short)( pt.y - 5 ) ); + } + + return( hNewContact != NULL ? 1 : 0 ); +} + + + +static int OnContactDrop( WPARAM wParam, LPARAM lParam ) +{ + RECT rcMiranda; + RECT rcThumb; +// RECT rcOverlap; + + HANDLE hContact = ( HANDLE )wParam; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + + if ( ( hNewContact == hContact ) && ( pThumb != NULL ) ) + { + hNewContact = NULL; + + GetWindowRect( hwndMiranda, &rcMiranda ); + pThumb->GetThumbRect( &rcThumb ); + + //if ( IntersectRect( &rcOverlap, &rcThumb, &rcMiranda ) ) + //{ + // pThumb->OnLButtonDown( (short)(rcThumb.left + 5), (short)(rcThumb.top + 5) ); + //} + } + + SaveContactsPos(); + + return( 1 ); +} + + +static int OnContactDragStop( WPARAM wParam, LPARAM lParam ) +{ + HANDLE hContact = ( HANDLE )wParam; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + + if ( ( pThumb != NULL ) && ( hNewContact == hContact ) ) + { + thumbList.RemoveThumb( pThumb ); + hNewContact = NULL; + } + + return( 0 ); +} + + +static int OnSkinIconsChanged( WPARAM wParam, LPARAM lParam ) +{ + // Get handle to the image list + himl = ( HIMAGELIST )CallService( MS_CLIST_GETICONSIMAGELIST, 0, 0 ); + + // Update thumbs + for (int i = 0; i < thumbList.getCount(); ++i) + thumbList[i]->UpdateContent(); + + return( 0 ); +} + + + +static int OnContactSettingChanged( WPARAM wParam, LPARAM lParam ) +{ + HANDLE hContact = ( HANDLE )wParam; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + int idStatus = ID_STATUS_OFFLINE; + BOOL bRefresh = TRUE; + DBCONTACTWRITESETTING* pdbcws = ( DBCONTACTWRITESETTING* )lParam; + + + if ( hContact == NULL ) + { + if(( 0 == stricmp( pdbcws->szModule, "CLC" ) ) || ( 0 == stricmp( pdbcws->szModule, sModule ) ) ){ + LoadDBSettings(); + ApplyOptionsChanges(); + } + + return( 0 ); + } + + if ( pThumb == NULL ) return( 0 ); + + // Only on these 2 events we need to refresh + if( 0 == stricmp( pdbcws->szSetting, "Status" ) ) + { + idStatus = pdbcws->value.wVal; + } + else if ( 0 == stricmp( pdbcws->szSetting, "Nick" ) ) + { + idStatus = GetContactStatus( hContact ); + } + else if ( 0 == stricmp( pdbcws->szSetting, "MyHandle" ) ) + { + idStatus = GetContactStatus( hContact ); + } + else if ( fcOpt.bShowIdle && 0 == stricmp( pdbcws->szSetting, "IdleTS" )) + { + idStatus = GetContactStatus( hContact ); + } + else + { + bRefresh = FALSE; + } + + if ( bRefresh ) + { + // Detach call + PostMessage( pThumb->hwnd, WM_REFRESH_CONTACT, 0, idStatus ); + } + + return( 0 ); +} + + +static int OnStatusModeChange( WPARAM wParam, LPARAM lParam ) +{ + int idStatus; + + //nStatus = (int)wParam; + + for (int i = 0; i < thumbList.getCount(); ++i) + { + idStatus = GetContactStatus( thumbList[i]->hContact ); + thumbList[i]->RefreshContactStatus( idStatus ); + } + if ( wParam == ID_STATUS_OFFLINE ) + { + // Floating status window will use this + } + + return( 0 ); +} + + + +static int OnPrebuildContactMenu( WPARAM wParam, LPARAM lParam ) +{ + ThumbInfo *pThumb = thumbList.FindThumbByContact( (HANDLE) wParam ); + CLISTMENUITEM clmi; + + ZeroMemory( &clmi, sizeof( clmi ) ); + clmi.cbSize = sizeof( clmi ); + + clmi.flags = ( pThumb == NULL ) ? CMIM_FLAGS | CMIF_HIDDEN : CMIM_FLAGS &~CMIF_HIDDEN; + CallService( MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemRemove, (LPARAM)&clmi ); + + clmi.flags = fcOpt.bHideAll ? CMIM_FLAGS | CMIF_HIDDEN : CMIM_FLAGS &~CMIF_HIDDEN; + CallService( MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemHideAll, (LPARAM)&clmi ); + + return( 0 ); +} + + + + +/////////////////////////////////////////////////////// +// General functions + +static void LoadDBSettings() +{ + fcOpt.thumbAlpha = (BYTE)((double)DBGetContactSettingByte( NULL, sModule, "Opacity", 100 ) * 2.55 ); + fcOpt.bHideOffline = (BOOL)DBGetContactSettingByte( NULL, sModule, "HideOffline", 0 ); + fcOpt.bHideAll = (BOOL)DBGetContactSettingByte( NULL, sModule, "HideAll", 0 ); + fcOpt.bHideWhenFullscreen = (BOOL)DBGetContactSettingByte( NULL, sModule, "HideWhenFullscreen", 0 ); + fcOpt.bMoveTogether = (BOOL)DBGetContactSettingByte( NULL, sModule, "MoveTogether", 0 ); + fcOpt.bFixedWidth = (BOOL)DBGetContactSettingByte( NULL, sModule, "FixedWidth", 0 ); + fcOpt.nThumbWidth = (DWORD)DBGetContactSettingDword( NULL, sModule, "Width", 0 ); + dwOfflineModes = DBGetContactSettingDword( NULL, "CLC","OfflineModes", CLCDEFAULT_OFFLINEMODES ); + fcOpt.bShowTip = (BOOL)DBGetContactSettingByte( NULL, sModule, "ShowTip", 1 ); + fcOpt.TimeIn = (WORD)DBGetContactSettingWord( NULL, sModule, "TimeIn", 0 ); + fcOpt.bToTop = (BOOL)DBGetContactSettingByte( NULL, sModule, "ToTop", 0 ); + fcOpt.ToTopTime = (WORD)DBGetContactSettingWord( NULL, sModule, "ToTopTime", TOTOPTIME_DEF ); + fcOpt.bHideWhenCListShow = (BOOL)DBGetContactSettingByte( NULL, sModule, "HideWhenCListShow", 0 ); + fcOpt.bUseSingleClick = (BOOL)DBGetContactSettingByte( NULL, sModule, "UseSingleClick", 0 ); + fcOpt.bShowIdle = (BOOL)DBGetContactSettingByte( NULL, sModule, "ShowIdle", 0 ); + + if(DBGetContactSettingByte(NULL, "ModernData", "HideBehind", 0)) + bIsCListShow = (DBGetContactSettingByte(NULL, "ModernData", "BehindEdge", 0)==0); + else + bIsCListShow = (DBGetContactSettingByte(NULL,"CList","State",0)==2); +} + +void SendMsgDialog( HWND hwnd, char *pText ) +{ + ThumbInfo *pThumb = thumbList.FindThumb( hwnd ); + + if ( pThumb != NULL ) + CallService( MS_MSG_SENDMESSAGE, (WPARAM)pThumb->hContact, (LPARAM)pText ); +} + + +static void ShowContactMenu( HWND hwnd, POINT pt ) +{ + ThumbInfo *pThumb = thumbList.FindThumb( hwnd ); + int idCommand = 0; + + if ( pThumb != NULL ) + { + hContactMenu = (HMENU)CallService( MS_CLIST_MENUBUILDCONTACT, (WPARAM)pThumb->hContact, (LPARAM)0 ); + + if ( hContactMenu == NULL ) return; + + idCommand = TrackPopupMenu( hContactMenu, TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, 0 , hwnd, NULL ); + CallService( MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM( idCommand ,MPCF_CONTACTMENU), (LPARAM)pThumb->hContact ); + } +} + +static LRESULT __stdcall CommWndProc( HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam ) +{ + LRESULT lResult = 0; + ThumbInfo *pThumb = thumbList.FindThumb( hwnd ); + + switch( uMsg ) + { + case WM_RBUTTONUP: + { + POINT pt; + pt.x = LOWORD( lParam ); + pt.y = HIWORD( lParam ); + + if (pThumb) pThumb->ThumbDeselect( TRUE ); + + ClientToScreen(hwnd,&pt); + ShowContactMenu( hwnd, pt ); + } + + break; + +//#if 0 + case WM_NCPAINT: + if(pThumb){ + HDC hdc = GetWindowDC( hwnd ); + BitBlt(hdc, 0, 0, pThumb->bmpContent.getWidth(), pThumb->bmpContent.getHeight(), pThumb->bmpContent.getDC(), 0, 0, SRCCOPY); + //RepaintWindow( hwnd, hdc ); + ReleaseDC( hwnd, hdc ); + ValidateRect( hwnd, NULL ); + return 0; + } + + case WM_PAINT: + if(pThumb){ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + BitBlt(hdc, 0, 0, pThumb->bmpContent.getWidth(), pThumb->bmpContent.getHeight(), pThumb->bmpContent.getDC(), 0, 0, SRCCOPY); + //RepaintWindow( hwnd, hdc ); + EndPaint(hwnd, &ps); + break; + } + + case WM_PRINT: + case WM_PRINTCLIENT: + if(pThumb){ + BitBlt((HDC)wParam, 0, 0, pThumb->bmpContent.getWidth(), pThumb->bmpContent.getHeight(), pThumb->bmpContent.getDC(), 0, 0, SRCCOPY); + //RepaintWindow(hwnd, (HDC)wParam); + break; + } +//#endif + + case WM_MEASUREITEM: + lResult = CallService( MS_CLIST_MENUMEASUREITEM,wParam,lParam ); + break; + + case WM_DRAWITEM: + lResult = CallService( MS_CLIST_MENUDRAWITEM,wParam,lParam ); + break; + + case WM_LBUTTONDOWN: + if (pThumb) pThumb->OnLButtonDown( (short)LOWORD( lParam ), (short)HIWORD( lParam ) ); + break; + + case WM_MOUSEMOVE: + if (pThumb) pThumb->OnMouseMove( (short)LOWORD( lParam ), (short)HIWORD( lParam ), wParam); + break; + + case WM_LBUTTONUP: + if (pThumb) pThumb->OnLButtonUp(); + //if (bMouseMoved || !DBGetContactSettingByte(NULL, "CList", "Tray1Click", SETTING_TRAY1CLICK_DEFAULT)) + break; + // FALL THRU + + case WM_LBUTTONDBLCLK: + // Popup message dialog + //if (pThumb) pThumb->ThumbDeselect( TRUE ); + if(!fcOpt.bUseSingleClick && pThumb) + pThumb->PopUpMessageDialog(); + break; + + case WM_RBUTTONDOWN: + if(bEnableTip && fcOpt.bShowTip && pThumb) pThumb->KillTip(); + break; + case WM_REFRESH_CONTACT: + if (pThumb) + { + _tcsncpy( pThumb->ptszName, (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pThumb->hContact, (LPARAM)GCDNF_TCHAR ), USERNAME_LEN - 1 ); + pThumb->RefreshContactStatus( (int)lParam ); + pThumb->ResizeThumb(); + } + break; + + case WM_TIMER: + if(pThumb)pThumb->OnTimer(wParam); + break; + + case WM_HOTKEY: + { + ThumbInfo *pThumb = thumbList.FindThumb( ( HWND )wParam ); + + if (pThumb) pThumb->PopUpMessageDialog(); + } + + default: + break; + } + + lResult = DefWindowProc( hwnd, uMsg, wParam, lParam ); + + return( lResult ); +} + + + +extern void SetThumbsOpacity( BYTE btAlpha ) +{ + for (int i = 0; i < thumbList.getCount(); ++i) + thumbList[i]->SetThumbOpacity( btAlpha ); +} + + + +static void GetScreenRect() +{ + rcScreen.left = GetSystemMetrics( SM_XVIRTUALSCREEN ); + rcScreen.top = GetSystemMetrics( SM_YVIRTUALSCREEN ); + rcScreen.right = GetSystemMetrics( SM_CXVIRTUALSCREEN ) + rcScreen.left; + rcScreen.bottom = GetSystemMetrics( SM_CYVIRTUALSCREEN ) + rcScreen.top; +} + + + +void OnStatusChanged() +{ + int idStatus = ID_STATUS_OFFLINE; + + for (int i = 0; i < thumbList.getCount(); ++i) + { + idStatus = GetContactStatus( thumbList[i]->hContact ); + thumbList[i]->RefreshContactStatus( idStatus ); + } +} + + + +void ApplyOptionsChanges() +{ + CreateThumbsFont(); + CreateBackgroundBrush(); + +// dwOfflineModes = DBGetContactSettingDword( NULL, "CLC","OfflineModes", CLCDEFAULT_OFFLINEMODES ); + if(!fcOpt.bToTop && ToTopTimerID){ + KillTimer(NULL, ToTopTimerID); + ToTopTimerID = 0; + } + if(fcOpt.bToTop){ + if (ToTopTimerID) KillTimer(NULL, ToTopTimerID); + fcOpt.ToTopTime = (fcOpt.ToTopTime<1)?1:fcOpt.ToTopTime; + fcOpt.ToTopTime = (fcOpt.ToTopTime>TOTOPTIME_MAX)?TOTOPTIME_MAX:fcOpt.ToTopTime; + ToTopTimerID = SetTimer(NULL, 0, fcOpt.ToTopTime*TOTOPTIME_P, ToTopTimerProc); + } + + OnStatusChanged(); + + for (int i = 0; i < thumbList.getCount(); ++i) + thumbList[i]->ResizeThumb(); +} + + + +/////////////////////////////////////////////////////// +// Window creation +static void RegisterWindowClass() +{ + WNDCLASSEX wcx; + ZeroMemory( &wcx, sizeof( wcx ) ); + + wcx.cbSize = sizeof( WNDCLASSEX ); + wcx.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS; + wcx.lpfnWndProc = CommWndProc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = hInst; + wcx.hIcon = NULL; + wcx.hCursor = NULL; + wcx.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = WND_CLASS; + wcx.hIconSm = NULL; + + SetLastError( 0 ); + + RegisterClassEx( &wcx ); +} + + + +static void UnregisterWindowClass() +{ + UnregisterClass( WND_CLASS, hInst ); +} + + + +static void CreateThumbWnd( TCHAR *ptszName, HANDLE hContact, int nX, int nY ) +{ + HWND hwnd = NULL; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + + // Prepare for window creation + if ( pThumb == NULL ) + { + hwnd = CreateWindowEx( WS_EX_TOOLWINDOW | WS_EX_TOPMOST, + WND_CLASS, + ptszName, + WS_POPUP, + nX, + nY, + 50, + 20, + NULL /*hwndMiranda*/, + NULL, + hInst, + NULL + ); + + if ( hwnd != NULL ) + { + pThumb = thumbList.AddThumb( hwnd, ptszName, hContact ); + SetWindowLong( hwnd, GWL_USERDATA, (long)pThumb ); + pThumb->ResizeThumb(); + + pThumb->SetThumbOpacity( fcOpt.thumbAlpha ); + ShowWindow( hwnd, ( fcOpt.bHideAll || HideOnFullScreen() || fcOpt.bHideOffline || (fcOpt.bHideWhenCListShow && bIsCListShow) )? SW_HIDE : SW_SHOWNA ); + pThumb->PositionThumb( (short)nX, (short)nY ); + + // force repaint + pThumb->UpdateContent(); + } + } +} + + + +static BOOL GetOSPlatform() +{ + OSVERSIONINFO VersionInfo; + + // Get OS platform + ZeroMemory( &VersionInfo, sizeof( VersionInfo ) ); + VersionInfo.dwOSVersionInfoSize = sizeof( VersionInfo ); + + GetVersionEx( &VersionInfo ); + return( VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ); +} + + + +static void CreateThumbsFont() +{ + int nFontId; + LOGFONTA lf; + + for (nFontId = 0; nFontId < FLT_FONTIDS; nFontId++) + { + if (NULL != hFont[nFontId]) + { + DeleteObject(hFont[nFontId]); + hFont[nFontId] = NULL; + } + GetFontSetting(TRUE, nFontId, &lf, &tColor[nFontId]); + { + LONG height; + HDC hdc=GetDC(NULL); + height=lf.lfHeight; + lf.lfHeight=-MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72); + ReleaseDC(NULL,hdc); + + hFont[nFontId] = CreateFontIndirectA(&lf); + + lf.lfHeight=height; + } + } +} + + + +static void CreateBackgroundBrush() +{ +// LOGBRUSH lb; + bkColor = DBGetContactSettingDword(NULL, sModule, "BkColor", FLT_DEFAULT_BKGNDCOLOR); + + + if (NULL != hLTEdgesPen) + { + DeleteObject(hLTEdgesPen); + hLTEdgesPen = NULL; + } + if (NULL != hRBEdgesPen) + { + DeleteObject(hRBEdgesPen); + hRBEdgesPen = NULL; + } + if (NULL != hBmpBackground) + { + DeleteObject(hBmpBackground); + hBmpBackground = NULL; + } + if (NULL != hBkBrush) + { + SetClassLong((HWND)WND_CLASS, GCL_HBRBACKGROUND, (LONG)NULL); + DeleteObject( hBkBrush ); + hBkBrush = NULL; + } + + if (DBGetContactSettingByte(NULL, sModule, "DrawBorder", FLT_DEFAULT_DRAWBORDER)) + { + COLORREF cr; + + cr = (COLORREF)DBGetContactSettingDword(NULL, sModule, "LTEdgesColor", FLT_DEFAULT_LTEDGESCOLOR); + hLTEdgesPen = CreatePen(PS_SOLID, 1, cr); + cr = (COLORREF)DBGetContactSettingDword(NULL, sModule, "RBEdgesColor", FLT_DEFAULT_RBEDGESCOLOR); + hRBEdgesPen = CreatePen(PS_SOLID, 1, cr); + } + if (DBGetContactSettingByte(NULL, sModule, "BkUseBitmap", FLT_DEFAULT_BKGNDUSEBITMAP)) + { + DBVARIANT dbv; + + if (!DBGetContactSetting(NULL, sModule, "BkBitmap", &dbv)) + { + hBmpBackground = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + } + } + nBackgroundBmpUse = (WORD)DBGetContactSettingWord(NULL, sModule, "BkBitmapOpt", FLT_DEFAULT_BKGNDBITMAPOPT); + + // Create brush + hBkBrush = CreateSolidBrush(bkColor); + + // Attach brush to the window + SetClassLong((HWND)WND_CLASS, GCL_HBRBACKGROUND, (LONG)hBkBrush); +} + + +static int GetContactStatus( HANDLE hContact ) +{ + char *szProto = NULL; + int idStatus = ID_STATUS_OFFLINE; + + if ( hContact == NULL ) + { + assert( !"Contact is NULL" ); + return( 0 ); + } + + szProto = ( char* )CallService( "Proto/GetContactBaseProto", (WPARAM)hContact, 0 ); + + if ( NULL != szProto ) + { + idStatus = DBGetContactSettingWord( hContact, szProto, "Status", ID_STATUS_OFFLINE ); + } + + + return( idStatus ); +} + + +static int ClcStatusToPf2( int status ) +{ + switch(status) { + case ID_STATUS_ONLINE: return PF2_ONLINE; + case ID_STATUS_AWAY: return PF2_SHORTAWAY; + case ID_STATUS_DND: return PF2_HEAVYDND; + case ID_STATUS_NA: return PF2_LONGAWAY; + case ID_STATUS_OCCUPIED: return PF2_LIGHTDND; + case ID_STATUS_FREECHAT: return PF2_FREECHAT; + case ID_STATUS_INVISIBLE: return PF2_INVISIBLE; + case ID_STATUS_ONTHEPHONE: return PF2_ONTHEPHONE; + case ID_STATUS_OUTTOLUNCH: return PF2_OUTTOLUNCH; + case ID_STATUS_OFFLINE: return MODEF_OFFLINE; + } + return 0; +} + +BOOL IsStatusVisible( int status ) +{ + return ( 0 == ( dwOfflineModes & ClcStatusToPf2( status ) ) ); +} + + + +void RegHotkey( HANDLE hContact, HWND hwnd ) +{ + char szBuf[ MAX_PATH ]= {0}; +/* char szPath[ MAX_PATH ]= {0}; + + GetModuleFileName( NULL, szPath, MAX_PATH ); + PathRemoveFileSpec( szPath ); + strcat( szPath, "\\Thumbs.ini" ); + GetPrivateProfileString( "Hotkeys", szName, "", szBuf, MAX_PATH - 1, szPath );*/ + DBVARIANT dbv; + if(DBGetContactSettingString ( hContact, sModule, "Hotkey", &dbv)) return; + strncpy(szBuf, dbv.pszVal, MAX_PATH - 1); + DBFreeVariant( &dbv ); + + if ( 0 != strlen( szBuf ) ) + { + UINT nModifiers = 0; + char chKey = 0; + char szMod[ 2 ][ 20 ] = {0}; + char szKey[ 20 ] = {0}; + int i = 0; + + sscanf( szBuf, "%[^'+']+%[^'+']+%[^'+']", szMod[ 0 ], szMod[ 1 ], szKey ); + + for ( i = 0; i < 2; ++i ) + { + if( 0 == strncmp( szMod[ i ], "ALT", 19 ) ) + { + nModifiers = nModifiers | MOD_ALT; + } + else if( 0 == strncmp( szMod[ i ], "CTRL", 19 ) ) + { + nModifiers = nModifiers | MOD_CONTROL; + } + else if( 0 == strncmp( szMod[ i ], "SHIFT", 19 ) ) + { + nModifiers = nModifiers | MOD_SHIFT; + } + } + + chKey = szKey[ 0 ]; + + RegisterHotKey( hwnd, (int)hwnd, nModifiers, VkKeyScan( chKey ) ); + } +} + + + +/////////////////////////////////////////////////////// +// Contact sttings + +void SaveContactsPos() +{ + RECT rc; + + for (int i = 0; i < thumbList.getCount(); ++i) + { + SetLastError( 0 ); + + thumbList[i]->GetThumbRect( &rc ); + + if( 0 == GetLastError() ) + DBWriteContactSettingDword( thumbList[i]->hContact, sModule, "ThumbsPos", DB_POS_MAKE_XY(rc.left,rc.top) ); + } +} + + +static void LoadContacts() +{ + HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0) ; + + while( hContact != NULL ) + { + LoadContact( hContact ); + + hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 ); + } +} + + + + +static void LoadMenus() +{ + CLISTMENUITEM mi; + + // Remove thumb menu item + hRemoveThumb = CreateServiceFunction( sModule "/RemoveThumb",OnContactMenu_Remove ); + ZeroMemory( &mi,sizeof( mi ) ); + + mi.cbSize = sizeof( mi ); + mi.position = 0xFFFFF; + mi.flags = CMIF_TCHAR; + mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_HIDE ) ); + mi.ptszName = _T("Remove thumb"); + mi.pszService = sModule "/RemoveThumb"; + hMenuItemRemove = (HANDLE)CallService( MS_CLIST_ADDCONTACTMENUITEM,0, ( LPARAM )&mi ); + + // Hide all thumbs main menu item + hMainHideAllThumbs = CreateServiceFunction( sModule "/MainHideAllThumbs",OnMainMenu_HideAll ); + ZeroMemory( &mi,sizeof( mi ) ); + + mi.cbSize = sizeof( mi ); + mi.position = 0xFFFFF; + mi.flags = CMIF_TCHAR; + mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( fcOpt.bHideAll ? IDI_SHOW : IDI_HIDE ) ); + mi.ptszName = fcOpt.bHideAll ? _T("Show all thumbs") : _T("Hide all thumbs"); + mi.pszService = sModule "/MainHideAllThumbs"; + hMainMenuItemHideAll = (HANDLE)CallService( MS_CLIST_ADDMAINMENUITEM,0, ( LPARAM )&mi ); + + if(ServiceExists(MS_HOTKEY_REGISTER)){ + HOTKEYDESC hkd={0}; + + hkd.cbSize = sizeof(hkd); + hkd.pszSection = "Floating Contacts"; + + hkd.pszName = sModule "/MainHideAllThumbs"; + hkd.pszDescription = "Show/Hide all thumbs"; + hkd.pszService = sModule "/MainHideAllThumbs"; + CallService(MS_HOTKEY_REGISTER, 0, (LPARAM)&hkd); + + hHideWhenCListShow = CreateServiceFunction( sModule "/HideWhenCListShow",OnHotKey_HideWhenCListShow ); + hkd.pszName = sModule "/HideWhenCListShow"; + hkd.pszDescription = "Hide when contact list is shown"; + hkd.pszService = sModule "/HideWhenCListShow"; + CallService(MS_HOTKEY_REGISTER, 0, (LPARAM)&hkd); + } +} + + +static void LoadContact( HANDLE hContact ) +{ + DWORD dwPos = (DWORD)-1; + TCHAR *ptName = NULL; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + int nX, nY; + + + if ( hContact == NULL ) return; + + dwPos = DBGetContactSettingDword( hContact, sModule, "ThumbsPos", (DWORD)-1 ); + + if ( dwPos != -1 ) + { + ptName = (TCHAR*)CallService( MS_CLIST_GETCONTACTDISPLAYNAME, ( WPARAM )hContact, (LPARAM)GCDNF_TCHAR ); + + if ( ptName != NULL ) + { + nX = DB_POS_GETX( dwPos ); + nY = DB_POS_GETY( dwPos ); + + CreateThumbWnd( ptName, hContact, nX, nY ); + pThumb->PositionThumb( (short)nX, (short)nY ); + } + } +} + + +BOOL HideOnFullScreen() +{ + BOOL bFullscreen = FALSE; + HWND hWnd = 0; + + if ( fcOpt.bHideWhenFullscreen ) + { + int w = GetSystemMetrics(SM_CXSCREEN); + int h = GetSystemMetrics(SM_CYSCREEN); + + hWnd = GetForegroundWindow(); + + while (GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) + { + RECT WindowRect; + GetWindowRect(hWnd, &WindowRect); + + if ( (w == (WindowRect.right - WindowRect.left) ) && + (h == (WindowRect.bottom - WindowRect.top))) + { + bFullscreen = TRUE; + break; + } + + hWnd = GetNextWindow( hWnd, GW_HWNDNEXT ); + } + } + + return bFullscreen && fcOpt.bHideWhenFullscreen; +} + + +static int OnContactMenu_Remove( WPARAM wParam,LPARAM lParam ) +{ + HANDLE hContact = ( HANDLE )wParam; + ThumbInfo *pThumb = thumbList.FindThumbByContact( hContact ); + + if (pThumb) + { + pThumb->DeleteContactPos(); + thumbList.RemoveThumb(pThumb); + } + + DestroyMenu( hContactMenu ); + + return 0; +} + +static int OnHotKey_HideWhenCListShow( WPARAM wParam,LPARAM lParam ) +{ + fcOpt.bHideWhenCListShow=!fcOpt.bHideWhenCListShow; + DBWriteContactSettingByte(NULL, sModule, "HideWhenCListShow", (BYTE)fcOpt.bHideWhenCListShow); + OnStatusChanged(); + return 0; +} + + +static int OnMainMenu_HideAll( WPARAM wParam,LPARAM lParam ) +{ + CLISTMENUITEM clmi = {0}; + int b; + + fcOpt.bHideAll = !fcOpt.bHideAll; + DBWriteContactSettingByte(NULL, sModule, "HideAll", (BYTE)fcOpt.bHideAll); + OnStatusChanged(); + + clmi.cbSize = sizeof( clmi ); + clmi.flags = CMIM_NAME | CMIM_ICON|CMIF_TCHAR; + clmi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( fcOpt.bHideAll ? IDI_SHOW : IDI_HIDE ) ); + clmi.ptszName = fcOpt.bHideAll ? _T("Show all thumbs") : _T("Hide all thumbs"); + b = CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMainMenuItemHideAll, ( LPARAM )&clmi ); + return 0; +} + +static VOID CALLBACK ToTopTimerProc ( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + for (int i = 0; i < thumbList.getCount(); ++i) + { + SetWindowPos(thumbList[i]->hwnd, + HWND_TOPMOST, + 0, + 0, + 0, + 0, + SWP_NOSIZE | SWP_NOMOVE | /*SWP_NOZORDER |*/ SWP_NOACTIVATE); + } +} + +void ShowThumbsOnHideCList() +{ + if(!fcOpt.bHideWhenCListShow || fcOpt.bHideAll || HideOnFullScreen())return; + for (int i = 0; i < thumbList.getCount(); ++i) + { + if ( !fcOpt.bHideOffline || IsStatusVisible( GetContactStatus(thumbList[i]->hContact) ) ) + { + ShowWindow( thumbList[i]->hwnd, SW_SHOWNA ); + } + } +} + + +void HideThumbsOnShowCList() +{ + if(!fcOpt.bHideWhenCListShow || fcOpt.bHideAll || HideOnFullScreen())return; + for (int i = 0; i < thumbList.getCount(); ++i) + ShowWindow( thumbList[i]->hwnd, SW_HIDE ); +} + +static LRESULT __stdcall newMirandaWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( uMsg == WM_WINDOWPOSCHANGED) + { + WINDOWPOS *wp = (WINDOWPOS *)lParam; + if(wp->flags&SWP_HIDEWINDOW) { + bIsCListShow = FALSE; + ShowThumbsOnHideCList(); + } + else if(wp->flags&SWP_SHOWWINDOW){ + bIsCListShow = TRUE; + HideThumbsOnShowCList(); + } + else if(!(wp->flags&SWP_NOMOVE)){ + BYTE method=DBGetContactSettingByte(NULL, "ModernData", "HideBehind", 0); + if(method) { + WORD wBehindEdgeBorderSize=DBGetContactSettingWord(NULL, "ModernData", "HideBehindBorderSize", 0); + RECT rc = {wp->x, wp->y, wp->x+wp->cx, wp->y+wp->cy}; + RECT rcScreen = {wBehindEdgeBorderSize*(2-method), 0, GetSystemMetrics(SM_CXSCREEN)-wBehindEdgeBorderSize*(method-1), GetSystemMetrics(SM_CYSCREEN)}; + RECT rcOverlap; + BOOL isIntersect; + + isIntersect = IntersectRect( &rcOverlap, &rc, &rcScreen ); + if ( !isIntersect && bIsCListShow ){ + bIsCListShow = FALSE; + ShowThumbsOnHideCList(); + } + else if ( isIntersect && !bIsCListShow ){ + bIsCListShow = TRUE; + HideThumbsOnShowCList(); + } + } + } + } + return( CallWindowProc(oldMirandaWndProc, hwnd, uMsg, wParam, lParam) ); +} diff --git a/plugins/FloatingContacts/options.cpp b/plugins/FloatingContacts/options.cpp new file mode 100644 index 0000000000..be257e7456 --- /dev/null +++ b/plugins/FloatingContacts/options.cpp @@ -0,0 +1,1179 @@ + +#include "stdhdr.h" + +#include "resource.h" +#include "fltcont.h" + +///////////////////////////////////////////////////////////////////////////// +// + +#define SAMEASF_FACE 1 +#define SAMEASF_SIZE 2 +#define SAMEASF_STYLE 4 +#define SAMEASF_COLOUR 8 + +typedef struct _SFontSettings +{ + BYTE sameAsFlags,sameAs; + COLORREF colour; + char size; + BYTE style; + BYTE charset; + char szFace[LF_FACESIZE]; +} SFontSettings; + +static SFontSettings s_rgFontSettings[FLT_FONTIDS]; +static SFontSettings s_rgFontSettingsMiranda[FLT_FONTIDS]; + +#define FLT_SAME_AS_NONE ((BYTE)0xFF) +#define FLT_SAME_AS_MIRANDA ((BYTE)0xFE) + +static char* s_rgszFontSizes[]={"8","10","14","16","18","20","24","28"}; + +static const TCHAR* s_rgszFontIdDescr[FLT_FONTIDS] = +{ + _T("Standard contacts"), + _T("Online contacts to whom you have a different visibility"), + _T("Offline contacts"), + _T("Offline contacts to whom you have a different visibility"), + _T("Contacts which are 'not on list'"), +}; + +static WORD s_rgwFontSameAsDefault[FLT_FONTIDS] = +{ + MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F), + MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F), + MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F), + MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F), + MAKEWORD(FLT_SAME_AS_MIRANDA, 0x0F), +}; + +static int s_rgnMirandaFontId[FLT_FONTIDS] = +{ + FONTID_CONTACTS, + FONTID_INVIS, + FONTID_OFFLINE, + FONTID_OFFINVIS, + FONTID_NOTONLIST +}; + +#define M_REBUILDFONTGROUP (WM_USER + 10) +#define M_REMAKESAMPLE (WM_USER + 11) +#define M_RECALCONEFONT (WM_USER + 12) +#define M_RECALCOTHERFONTS (WM_USER + 13) +#define M_SAVEFONT (WM_USER + 14) +#define M_REFRESHSAMEASBOXES (WM_USER + 15) +#define M_FILLSCRIPTCOMBO (WM_USER + 16) +#define M_LOADFONT (WM_USER + 17) +#define M_GUESSSAMEASBOXES (WM_USER + 18) +#define M_SETSAMEASBOXES (WM_USER + 19) + +#define M_REFRESHBKGBOXES (WM_USER + 20) +#define M_REFRESHBORDERPICKERS (WM_USER + 21) + +///////////////////////////////////////////////////////////////////////////// +// + +static +LRESULT +APIENTRY +OptWndProc + ( IN HWND hwndDlg + , IN UINT uMsg + , IN WPARAM wParam + , IN LPARAM lParam + ); + +static +LRESULT +APIENTRY +OptSknWndProc + ( IN HWND hwndDlg + , IN UINT uMsg + , IN WPARAM wParam + , IN LPARAM lParam + ); + +///////////////////////////////////////////////////////////////////////////// +// + +int +OnOptionsInitialize + ( IN WPARAM wParam + , IN LPARAM lParam + ) +{ + OPTIONSDIALOGPAGE odp; + + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.hInstance = hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FLTCONT); + odp.ptszTitle = _T("Floating Contacts"); + odp.ptszGroup = _T("Plugins"); + odp.ptszTab = _T("Main Features"); + odp.flags = ODPF_BOLDGROUPS|ODPF_TCHAR; + odp.pfnDlgProc = (DLGPROC)OptWndProc; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.hInstance = hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SKIN); + odp.ptszTitle = _T("Floating Contacts"); + odp.ptszGroup = _T("Plugins"); + odp.ptszTab = _T("Appearance"); + odp.flags = ODPF_BOLDGROUPS|ODPF_TCHAR; + odp.pfnDlgProc = (DLGPROC)OptSknWndProc; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + + return 0; +} + +static +int +CALLBACK +EnumFontsProc + ( IN ENUMLOGFONTEXA* lpelfe + , IN NEWTEXTMETRICEXA* lpntme + , IN int FontType + , IN LPARAM lParam + ) +{ + if (IsWindow((HWND)lParam)) + { + if (CB_ERR == SendMessageA((HWND)lParam, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)lpelfe->elfLogFont.lfFaceName)) + SendMessageA((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)lpelfe->elfLogFont.lfFaceName); + return TRUE; + } + return FALSE; +} + +void +FillFontListThread + ( IN HWND hwndDlg + ) +{ + LOGFONTA lf = {0}; + HDC hdc = GetDC(hwndDlg); + + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfFaceName[0] = 0; + lf.lfPitchAndFamily = 0; + EnumFontFamiliesExA(hdc, &lf, (FONTENUMPROCA)EnumFontsProc, (LPARAM)GetDlgItem(hwndDlg,IDC_TYPEFACE), 0); + ReleaseDC(hwndDlg, hdc); + return; +} + +static +int +CALLBACK +EnumFontScriptsProc + ( IN ENUMLOGFONTEX* lpelfe + , IN NEWTEXTMETRICEX* lpntme + , IN int FontType + , IN LPARAM lParam + ) +{ + if (CB_ERR == SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)lpelfe->elfScript)) + { + int i = SendMessage((HWND)lParam, CB_ADDSTRING, 0, (LPARAM)lpelfe->elfScript); + SendMessage((HWND)lParam, CB_SETITEMDATA, i, lpelfe->elfLogFont.lfCharSet); + } + return TRUE; +} + +static +void +GetDefaultFontSetting + ( IN BOOL bFltContacts + , IN int nFontId + , IN LOGFONTA* lf + , IN COLORREF* colour + ) +{ + SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(LOGFONTA), lf, FALSE); + *colour = GetSysColor(COLOR_WINDOWTEXT); + if (bFltContacts) + { + switch (nFontId) + { + case FLT_FONTID_OFFINVIS: + case FLT_FONTID_INVIS: + lf->lfItalic = !lf->lfItalic; + break; + + case FLT_FONTID_NOTONLIST: + *colour = GetSysColor(COLOR_3DSHADOW); + break; + } + } + else + { + switch (s_rgnMirandaFontId[nFontId]) + { + case FONTID_OFFINVIS: + case FONTID_INVIS: + lf->lfItalic = !lf->lfItalic; + break; + + case FONTID_NOTONLIST: + *colour = GetSysColor(COLOR_3DSHADOW); + break; + } + } +} + +void +GetFontSetting + ( IN BOOL bFltContacts + , IN int nFontId + , IN LOGFONTA* lf + , IN COLORREF* colour + ) +{ + DBVARIANT dbv; + char idstr[10]; + BYTE style; + const char* pModule = (bFltContacts ? sModule : "CLC"); + + GetDefaultFontSetting(bFltContacts, nFontId, lf, colour); + if (!bFltContacts) + nFontId = s_rgnMirandaFontId[nFontId]; + wsprintfA(idstr, "Font%dName", nFontId); + if (!DBGetContactSetting(NULL, pModule, idstr, &dbv)) + { + lstrcpyA(lf->lfFaceName, dbv.pszVal); + DBFreeVariant(&dbv); + } + + wsprintfA(idstr, "Font%dCol", nFontId); + *colour = DBGetContactSettingDword(NULL, pModule, idstr, *colour); + + wsprintfA(idstr, "Font%dSize", nFontId); + lf->lfHeight = (char)DBGetContactSettingByte(NULL, pModule, idstr, lf->lfHeight); + + wsprintfA(idstr, "Font%dSty", nFontId); + style = (BYTE)DBGetContactSettingByte(NULL, pModule, idstr + , (lf->lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD) + | (lf->lfItalic ? DBFONTF_ITALIC : 0) + | (lf->lfUnderline ? DBFONTF_UNDERLINE : 0) + ); + lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0; + lf->lfWeight = ((style & DBFONTF_BOLD) ? FW_BOLD : FW_NORMAL); + lf->lfItalic = (0 != (style & DBFONTF_ITALIC)); + lf->lfUnderline = (0 != (style & DBFONTF_UNDERLINE)); + lf->lfStrikeOut = 0; + + wsprintfA(idstr, "Font%dSet", nFontId); + lf->lfCharSet = (BYTE)DBGetContactSettingByte(NULL, pModule, idstr, lf->lfCharSet); + lf->lfOutPrecision = OUT_DEFAULT_PRECIS; + lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf->lfQuality = DEFAULT_QUALITY; + lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + if (bFltContacts) + { + WORD wSameAs; + BYTE bySameAs; + BYTE bySameAsFlags; + + wsprintfA(idstr, "Font%dAs", nFontId); + wSameAs = (WORD)DBGetContactSettingWord(NULL, sModule, idstr, s_rgwFontSameAsDefault[nFontId]); + bySameAs=LOBYTE(wSameAs); + bySameAsFlags=HIBYTE(wSameAs); + + if (FLT_SAME_AS_MIRANDA == bySameAs) + { + LOGFONTA lfMiranda; + COLORREF colourMiranda; + + GetFontSetting(FALSE, nFontId, &lfMiranda, &colourMiranda); + if (bySameAsFlags & SAMEASF_FACE) + { + lstrcpyA(lf->lfFaceName, lfMiranda.lfFaceName); + lf->lfCharSet = lfMiranda.lfCharSet; + } + if (bySameAsFlags & SAMEASF_SIZE) + lf->lfHeight = lfMiranda.lfHeight; + if (bySameAsFlags & SAMEASF_STYLE) + { + lf->lfWeight = lfMiranda.lfWeight; + lf->lfItalic = lfMiranda.lfItalic; + lf->lfUnderline = lfMiranda.lfUnderline; + } + if (bySameAsFlags & SAMEASF_COLOUR) + *colour = colourMiranda; + } + } +} + +static +LRESULT +APIENTRY +OptWndProc + ( IN HWND hwndDlg + , IN UINT uMsg + , IN WPARAM wParam + , IN LPARAM lParam + ) +{ + switch ( uMsg ) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + // Properties + CheckDlgButton(hwndDlg, IDC_CHK_HIDE_OFFLINE, (fcOpt.bHideOffline ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_CHK_HIDE_ALL, (fcOpt.bHideAll ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_CHK_HIDE_WHEN_FULSCREEN, (fcOpt.bHideWhenFullscreen ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_CHK_STICK, (fcOpt.bMoveTogether ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_CHK_WIDTH, (fcOpt.bFixedWidth ? BST_CHECKED : BST_UNCHECKED)); + + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_WIDTH), fcOpt.bFixedWidth); + EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_WIDTH), fcOpt.bFixedWidth); + EnableWindow(GetDlgItem(hwndDlg, IDC_WIDTHSPIN), fcOpt.bFixedWidth); + + SendDlgItemMessage(hwndDlg, IDC_WIDTHSPIN, UDM_SETRANGE, 0, MAKELONG(255,0)); + SendDlgItemMessage(hwndDlg, IDC_WIDTHSPIN, UDM_SETPOS, 0, fcOpt.nThumbWidth); + + CheckDlgButton(hwndDlg, IDC_CHK_TIP, (fcOpt.bShowTip ? BST_CHECKED : BST_UNCHECKED)); + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_TIP), bEnableTip); + + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN), bEnableTip && fcOpt.bShowTip); + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN_CMT), bEnableTip && fcOpt.bShowTip); + EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TIMEIN), bEnableTip && fcOpt.bShowTip); + EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEINSPIN), bEnableTip && fcOpt.bShowTip); + + SendDlgItemMessage(hwndDlg, IDC_TIMEINSPIN, UDM_SETRANGE, 0, MAKELONG(5000,0)); + SendDlgItemMessage(hwndDlg, IDC_TIMEINSPIN, UDM_SETPOS, 0, fcOpt.TimeIn); + + CheckDlgButton(hwndDlg, IDC_CHK_TOTOP, (fcOpt.bToTop ? BST_CHECKED : BST_UNCHECKED)); + + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TOTOP), fcOpt.bToTop); + EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TOTOPTIME), fcOpt.bToTop); + EnableWindow(GetDlgItem(hwndDlg, IDC_TOTOPTIMESPIN), fcOpt.bToTop); + + SendDlgItemMessage(hwndDlg, IDC_TOTOPTIMESPIN, UDM_SETRANGE, 0, MAKELONG(TOTOPTIME_MAX,1)); + SendDlgItemMessage(hwndDlg, IDC_TOTOPTIMESPIN, UDM_SETPOS, 0, fcOpt.ToTopTime); + + CheckDlgButton(hwndDlg, IDC_CHK_HIDE_WHEN_CLISTSHOW, (fcOpt.bHideWhenCListShow ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_CHK_SINGLECLK, (fcOpt.bUseSingleClick ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_CHK_SHOWIDLE, (fcOpt.bShowIdle ? BST_CHECKED : BST_UNCHECKED)); + + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_CHK_WIDTH: + { + if (BN_CLICKED == HIWORD(wParam)) + { + BOOL bChecked = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_WIDTH); + + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_WIDTH ), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_WIDTH ), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_WIDTHSPIN), bChecked); + } + break; + } + case IDC_TXT_WIDTH: + { + if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus()) + return 0; + break; + } + case IDC_CHK_TIP: + { + if (BN_CLICKED == HIWORD(wParam)) + { + BOOL bChecked = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TIP); + + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN ), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TIMEIN_CMT ), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TIMEIN ), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_TIMEINSPIN), bChecked); + } + break; + } + case IDC_TXT_TIMEIN: + { + if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus()) + return 0; + break; + } + case IDC_CHK_TOTOP: + { + if (BN_CLICKED == HIWORD(wParam)) + { + BOOL bChecked = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TOTOP); + + EnableWindow(GetDlgItem(hwndDlg, IDC_LBL_TOTOP ), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_TOTOPTIME ), bChecked); + EnableWindow(GetDlgItem(hwndDlg, IDC_TOTOPTIMESPIN), bChecked); + } + break; + } + case IDC_TXT_TOTOPTIME: + { + if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus()) + return 0; + break; + } + } + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + case WM_NOTIFY: + { + LPNMHDR phdr = (LPNMHDR)(lParam); + + if (0 == phdr->idFrom) + { + switch (phdr->code) + { + case PSN_APPLY: + { + BOOL bSuccess = FALSE; + + fcOpt.bHideOffline = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_OFFLINE); + DBWriteContactSettingByte(NULL, sModule, "HideOffline", (BYTE)fcOpt.bHideOffline); + + fcOpt.bHideAll = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_ALL); + DBWriteContactSettingByte(NULL, sModule, "HideAll", (BYTE)fcOpt.bHideAll); + + fcOpt.bHideWhenFullscreen = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_WHEN_FULSCREEN); + DBWriteContactSettingByte(NULL, sModule, "HideWhenFullscreen", (BYTE)fcOpt.bHideWhenFullscreen); + + fcOpt.bMoveTogether = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_STICK); + DBWriteContactSettingByte(NULL, sModule, "MoveTogether", (BYTE)fcOpt.bMoveTogether); + + fcOpt.bFixedWidth = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_WIDTH); + DBWriteContactSettingByte(NULL, sModule, "FixedWidth", (BYTE)fcOpt.bFixedWidth); + fcOpt.nThumbWidth = GetDlgItemInt(hwndDlg, IDC_TXT_WIDTH, &bSuccess, FALSE); + DBWriteContactSettingDword(NULL, sModule, "Width", fcOpt.nThumbWidth ); + + if(bEnableTip) + { + fcOpt.bShowTip = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TIP); + DBWriteContactSettingByte(NULL, sModule, "ShowTip", (BYTE)fcOpt.bShowTip); + fcOpt.TimeIn = GetDlgItemInt(hwndDlg, IDC_TXT_TIMEIN, &bSuccess, FALSE); + DBWriteContactSettingWord(NULL, sModule, "TimeIn", fcOpt.TimeIn ); + } + + fcOpt.bToTop = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_TOTOP); + DBWriteContactSettingByte(NULL, sModule, "ToTop", (BYTE)fcOpt.bToTop); + fcOpt.ToTopTime = GetDlgItemInt(hwndDlg, IDC_TXT_TOTOPTIME, &bSuccess, FALSE); + DBWriteContactSettingWord(NULL, sModule, "ToTopTime", fcOpt.ToTopTime ); + + fcOpt.bHideWhenCListShow = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_HIDE_WHEN_CLISTSHOW); + DBWriteContactSettingByte(NULL, sModule, "HideWhenCListShow", (BYTE)fcOpt.bHideWhenCListShow); + + fcOpt.bUseSingleClick = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_SINGLECLK); + DBWriteContactSettingByte(NULL, sModule, "UseSingleClick", (BYTE)fcOpt.bUseSingleClick); + + fcOpt.bShowIdle = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_CHK_SHOWIDLE); + DBWriteContactSettingByte(NULL, sModule, "ShowIdle", (BYTE)fcOpt.bShowIdle); + + ApplyOptionsChanges(); + OnStatusChanged(); + return TRUE; + } + } + } + break; + } + } + return FALSE; +} + +static +LRESULT +APIENTRY +OptSknWndProc + ( IN HWND hwndDlg + , IN UINT uMsg + , IN WPARAM wParam + , IN LPARAM lParam + ) +{ + static HFONT hFontSample; + + switch ( uMsg ) + { + case WM_INITDIALOG: + { + BYTE btOpacity; + char szPercent[20]; + + TranslateDialogDefault(hwndDlg); + + // Border + CheckDlgButton(hwndDlg, IDC_DRAWBORDER + , DBGetContactSettingByte(NULL, sModule, "DrawBorder", FLT_DEFAULT_DRAWBORDER) + ? BST_CHECKED : BST_UNCHECKED + ); + SendMessage(hwndDlg, M_REFRESHBORDERPICKERS, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_LTEDGESCOLOR, CPM_SETDEFAULTCOLOUR, 0, FLT_DEFAULT_LTEDGESCOLOR); + SendDlgItemMessage(hwndDlg, IDC_LTEDGESCOLOR, CPM_SETCOLOUR, 0 + , DBGetContactSettingDword(NULL, sModule, "LTEdgesColor", FLT_DEFAULT_LTEDGESCOLOR) + ); + SendDlgItemMessage(hwndDlg, IDC_RBEDGESCOLOR, CPM_SETDEFAULTCOLOUR, 0, FLT_DEFAULT_RBEDGESCOLOR); + SendDlgItemMessage(hwndDlg, IDC_RBEDGESCOLOR, CPM_SETCOLOUR, 0 + , DBGetContactSettingDword(NULL, sModule, "RBEdgesColor", FLT_DEFAULT_RBEDGESCOLOR) + ); + + // Background + CheckDlgButton(hwndDlg, IDC_CHK_WIDTH, (fcOpt.bFixedWidth ? BST_CHECKED : BST_UNCHECKED)); + + SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETDEFAULTCOLOUR, 0, FLT_DEFAULT_BKGNDCOLOR); + SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETCOLOUR, 0 + , DBGetContactSettingDword(NULL, sModule, "BkColor", FLT_DEFAULT_BKGNDCOLOR) + ); + CheckDlgButton(hwndDlg, IDC_BITMAP + , DBGetContactSettingByte(NULL, sModule, "BkUseBitmap", FLT_DEFAULT_BKGNDUSEBITMAP) + ? BST_CHECKED : BST_UNCHECKED + ); + SendMessage(hwndDlg, M_REFRESHBKGBOXES, 0, 0); + { + DBVARIANT dbv; + + if (!DBGetContactSetting(NULL, sModule, "BkBitmap", &dbv)) + { + SetDlgItemTextA(hwndDlg, IDC_FILENAME, dbv.pszVal); + DBFreeVariant(&dbv); + } + } + { + WORD bmpUse = (WORD)DBGetContactSettingWord(NULL, sModule, "BkBitmapOpt", FLT_DEFAULT_BKGNDBITMAPOPT); + + CheckDlgButton(hwndDlg, IDC_STRETCHH, ((bmpUse & CLB_STRETCHH) ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_STRETCHV, ((bmpUse & CLB_STRETCHV) ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_TILEH, ((bmpUse & CLBF_TILEH) ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_TILEV, ((bmpUse & CLBF_TILEV) ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_PROPORTIONAL, ((bmpUse & CLBF_PROPORTIONAL) ? BST_CHECKED : BST_UNCHECKED)); + } + { + HRESULT (STDAPICALLTYPE *MySHAutoComplete)(HWND,DWORD); + + MySHAutoComplete = (HRESULT (STDAPICALLTYPE*)(HWND,DWORD))GetProcAddress(GetModuleHandle(_T("shlwapi")), "SHAutoComplete"); + if (MySHAutoComplete) + MySHAutoComplete(GetDlgItem(hwndDlg, IDC_FILENAME), 1); + } + + // Windows 2K/XP + btOpacity = (BYTE)DBGetContactSettingByte(NULL, sModule, "Opacity", 100); + SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_SETRANGE, TRUE, MAKELONG(0, 100)); + SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_SETPOS, TRUE, btOpacity); + + wsprintfA(szPercent, "%d%%", btOpacity); + SetDlgItemTextA(hwndDlg, IDC_OPACITY, szPercent); + + EnableWindow(GetDlgItem(hwndDlg, IDC_SLIDER_OPACITY), (NULL != pSetLayeredWindowAttributes)); + EnableWindow(GetDlgItem(hwndDlg, IDC_OPACITY), (NULL != pSetLayeredWindowAttributes)); + + // Fonts + hFontSample = NULL; + SetDlgItemText(hwndDlg, IDC_SAMPLE, TranslateT("Sample")); + FillFontListThread(hwndDlg); + { + int i; + int itemId; + LOGFONTA lf; + COLORREF colour; + WORD sameAs; + char str[32]; + + for (i = 0; i < FLT_FONTIDS; i++) + { + // Floating contacts fonts + GetFontSetting(TRUE, i, &lf, &colour); + wsprintfA(str, "Font%dAs", i); + sameAs = (WORD)DBGetContactSettingWord(NULL, sModule, str, s_rgwFontSameAsDefault[i]); + s_rgFontSettings[i].sameAs = LOBYTE(sameAs); + s_rgFontSettings[i].sameAsFlags = HIBYTE(sameAs); + s_rgFontSettings[i].style = (FW_NORMAL == lf.lfWeight? 0 : DBFONTF_BOLD) + | (lf.lfItalic ? DBFONTF_ITALIC : 0) + | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0); + if (lf.lfHeight < 0) + { + HDC hdc; + SIZE size; + HFONT hFont = CreateFontIndirectA(&lf); + + hdc=GetDC(hwndDlg); + SelectObject(hdc, hFont); + GetTextExtentPoint32A(hdc, "x", 1, &size); + ReleaseDC(hwndDlg, hdc); + DeleteObject(hFont); + s_rgFontSettings[i].size = (char)size.cy; + } + else + s_rgFontSettings[i].size = (char)lf.lfHeight; + s_rgFontSettings[i].charset = lf.lfCharSet; + s_rgFontSettings[i].colour = colour; + lstrcpyA(s_rgFontSettings[i].szFace, lf.lfFaceName); + itemId = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_ADDSTRING, 0, (LPARAM)TranslateTS(s_rgszFontIdDescr[i])); + SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_SETITEMDATA, itemId, i); + + // Miranda contact list fonts + GetFontSetting(FALSE, i, &lf, &colour); + s_rgFontSettingsMiranda[i].sameAs = 0; + s_rgFontSettingsMiranda[i].sameAsFlags = 0; + lstrcpyA(s_rgFontSettingsMiranda[i].szFace, lf.lfFaceName); + s_rgFontSettingsMiranda[i].charset = lf.lfCharSet; + s_rgFontSettingsMiranda[i].style = (FW_NORMAL == lf.lfWeight? 0 : DBFONTF_BOLD) + | (lf.lfItalic ? DBFONTF_ITALIC : 0) + | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0); + if (lf.lfHeight < 0) + { + HDC hdc; + SIZE size; + HFONT hFont = CreateFontIndirectA(&lf); + + hdc = GetDC(hwndDlg); + SelectObject(hdc, hFont); + GetTextExtentPoint32A(hdc, "x", 1, &size); + ReleaseDC(hwndDlg, hdc); + DeleteObject(hFont); + s_rgFontSettingsMiranda[i].size = (char)size.cy; + } + else + s_rgFontSettingsMiranda[i].size = (char)lf.lfHeight; + s_rgFontSettingsMiranda[i].colour = colour; + } + SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_SETCURSEL, 0, 0); + for (i = 0; i < sizeof(s_rgszFontSizes)/sizeof(s_rgszFontSizes[0]); i++) + SendDlgItemMessageA(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)s_rgszFontSizes[i]); + } + SendMessage(hwndDlg, M_REBUILDFONTGROUP, 0, 0); + SendMessage(hwndDlg, M_SAVEFONT, 0, 0); + return TRUE; + } + case M_REFRESHBKGBOXES: + { + BOOL bEnable = IsDlgButtonChecked(hwndDlg, IDC_BITMAP); + + EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_STRETCHH), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_STRETCHV), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_TILEH), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_TILEV), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_PROPORTIONAL), bEnable); + break; + } + case M_REFRESHBORDERPICKERS: + { + BOOL bEnable = IsDlgButtonChecked(hwndDlg, IDC_DRAWBORDER); + + EnableWindow(GetDlgItem(hwndDlg, IDC_LTEDGESCOLOR), bEnable); + EnableWindow(GetDlgItem(hwndDlg, IDC_RBEDGESCOLOR), bEnable); + break; + } + // remake all the needed controls when the user changes the font selector at the top + case M_REBUILDFONTGROUP: + { + int i = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETCURSEL, 0, 0); + int j; + int itemId; + int nSameAs = FLT_SAME_AS_NONE; + char szText[256]; + + SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_RESETCONTENT, 0, 0); + itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM)TranslateT("")); + SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, FLT_SAME_AS_NONE); + SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0); + itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM)TranslateT("")); + SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, FLT_SAME_AS_MIRANDA); + if (FLT_SAME_AS_MIRANDA == s_rgFontSettings[i].sameAs) + { + SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0); + nSameAs = FLT_SAME_AS_MIRANDA; + } + for (j = 0; j < FLT_FONTIDS; j++) + { + int nDependsOn = j; + + while (nDependsOn != i) + { + if (FLT_SAME_AS_NONE == nDependsOn || FLT_SAME_AS_MIRANDA == nDependsOn) + { + SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETLBTEXT, j, (LPARAM)szText); + itemId = SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_ADDSTRING, 0, (LPARAM)szText); + SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETITEMDATA, itemId, j); + if (j == s_rgFontSettings[i].sameAs) + { + SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_SETCURSEL, itemId, 0); + nSameAs = j; + } + break; + } + else + nDependsOn = s_rgFontSettings[nDependsOn].sameAs; + } + } + if (FLT_SAME_AS_NONE == nSameAs) + s_rgFontSettings[i].sameAsFlags = 0; + + SendMessage(hwndDlg, M_LOADFONT, i, 0); + SendMessage(hwndDlg, M_SETSAMEASBOXES, i, 0); + SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, i, 0); + SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0); + break; + } + //fill the script combo box and set the selection to the value for fontid wParam + case M_FILLSCRIPTCOMBO: + { + int i; + HDC hdc = GetDC(hwndDlg); + LOGFONT lf = {0}; + + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfPitchAndFamily = 0; + GetDlgItemText(hwndDlg, IDC_TYPEFACE, lf.lfFaceName, sizeof(lf.lfFaceName)); + SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_RESETCONTENT, 0, 0); + EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)EnumFontScriptsProc, (LPARAM)GetDlgItem(hwndDlg, IDC_SCRIPT), 0); + ReleaseDC(hwndDlg, hdc); + for (i = SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCOUNT, 0, 0) - 1; i >= 0; i--) + { + if (SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, i, 0) == s_rgFontSettings[wParam].charset) + { + SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, i, 0); + break; + } + } + if (i < 0) + SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_SETCURSEL, 0, 0); + break; + } + // set the check mark in the 'same as' boxes to the right value for fontid wParam + case M_SETSAMEASBOXES: + { + CheckDlgButton(hwndDlg, IDC_SAMETYPE, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_SAMESIZE, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_SIZE ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_SAMESTYLE, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_SAMECOLOUR, (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_COLOUR ? BST_CHECKED : BST_UNCHECKED)); + break; + } + // set the disabled flag on the 'same as' checkboxes to the values for fontid wParam + case M_REFRESHSAMEASBOXES: + { + BOOL bSameAsNone = (FLT_SAME_AS_NONE == s_rgFontSettings[wParam].sameAs); + + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMETYPE), !bSameAsNone); + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMESIZE), !bSameAsNone); + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMESTYLE), !bSameAsNone); + EnableWindow(GetDlgItem(hwndDlg, IDC_SAMECOLOUR), !bSameAsNone); + EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEFACE), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE)); + EnableWindow(GetDlgItem(hwndDlg, IDC_SCRIPT), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE)); + EnableWindow(GetDlgItem(hwndDlg, IDC_FONTSIZE), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_SIZE)); + EnableWindow(GetDlgItem(hwndDlg, IDC_BOLD), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE)); + EnableWindow(GetDlgItem(hwndDlg, IDC_ITALIC), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE)); + EnableWindow(GetDlgItem(hwndDlg, IDC_UNDERLINE), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE)); + EnableWindow(GetDlgItem(hwndDlg, IDC_COLOUR), bSameAsNone || !(s_rgFontSettings[wParam].sameAsFlags & SAMEASF_COLOUR)); + break; + } + // remake the sample edit box font based on the settings in the controls + case M_REMAKESAMPLE: + { + LOGFONTA lf; + + if (hFontSample) + { + SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDC_FONTID, WM_GETFONT, 0, 0), 0); + DeleteObject(hFontSample); + } + lf.lfHeight = GetDlgItemInt(hwndDlg, IDC_FONTSIZE, NULL, FALSE); + { + HDC hdc=GetDC(NULL); + lf.lfHeight=-MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72); + ReleaseDC(NULL,hdc); + } + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfWeight = (IsDlgButtonChecked(hwndDlg, IDC_BOLD) ? FW_BOLD : FW_NORMAL); + lf.lfItalic = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_ITALIC); + lf.lfUnderline = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE); + lf.lfStrikeOut = 0; + lf.lfCharSet = (BYTE)SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCURSEL, 0, 0), 0); + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = (DEFAULT_PITCH | FF_DONTCARE); + GetDlgItemTextA(hwndDlg, IDC_TYPEFACE, lf.lfFaceName, sizeof(lf.lfFaceName)); + if (NULL != (hFontSample = CreateFontIndirectA(&lf))) + SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, (WPARAM)hFontSample, TRUE); + break; + } + // copy the 'same as' settings for fontid wParam from their sources + case M_RECALCONEFONT: + { + if (FLT_SAME_AS_NONE != s_rgFontSettings[wParam].sameAs) + { + SFontSettings* pSameAs = ((FLT_SAME_AS_MIRANDA == s_rgFontSettings[wParam].sameAs) + ? &s_rgFontSettingsMiranda[wParam] + : &s_rgFontSettings[s_rgFontSettings[wParam].sameAs] + ); + + if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_FACE) + { + lstrcpyA(s_rgFontSettings[wParam].szFace, pSameAs->szFace); + s_rgFontSettings[wParam].charset = pSameAs->charset; + } + if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_SIZE) + s_rgFontSettings[wParam].size = pSameAs->size; + if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_STYLE) + s_rgFontSettings[wParam].style = pSameAs->style; + if (s_rgFontSettings[wParam].sameAsFlags & SAMEASF_COLOUR) + s_rgFontSettings[wParam].colour = pSameAs->colour; + } + break; + } + // recalculate the 'same as' settings for all fonts but wParam + case M_RECALCOTHERFONTS: + { + int nFont; + int nDepth; + int nRecalcedFonts = 1; + int nRecalcDepth; + int nFontId = (int)wParam; + int nSameAs; + + for (nRecalcDepth = 0; nRecalcedFonts < FLT_FONTIDS && nRecalcDepth < FLT_FONTIDS; nRecalcDepth++) + { + for (nFont = 0; nFont < FLT_FONTIDS; nFont++) + { + if (nFontId == nFont) + continue; + + nSameAs = s_rgFontSettings[nFont].sameAs; + for (nDepth = 0; nDepth < nRecalcDepth; nDepth++) + { + if (FLT_SAME_AS_NONE == nSameAs || FLT_SAME_AS_MIRANDA == nSameAs || nFontId == nSameAs) + break; + + nSameAs = s_rgFontSettings[nSameAs].sameAs; + } + if (nDepth == nRecalcDepth) + { + if (nFontId == nSameAs) + { + SendMessage(hwndDlg, M_RECALCONEFONT, nFont, 0); + nRecalcedFonts++; + } + else if (FLT_SAME_AS_NONE == nSameAs || FLT_SAME_AS_MIRANDA == nSameAs) + nRecalcedFonts++; + } + } + } + break; + } + //save the font settings from the controls to font wParam + case M_SAVEFONT: + { + s_rgFontSettings[wParam].sameAsFlags = (IsDlgButtonChecked(hwndDlg, IDC_SAMETYPE) ? SAMEASF_FACE : 0) + | (IsDlgButtonChecked(hwndDlg, IDC_SAMESIZE) ? SAMEASF_SIZE : 0) + | (IsDlgButtonChecked(hwndDlg, IDC_SAMESTYLE) ? SAMEASF_STYLE : 0) + | (IsDlgButtonChecked(hwndDlg, IDC_SAMECOLOUR) ? SAMEASF_COLOUR : 0); + s_rgFontSettings[wParam].sameAs = (BYTE)SendDlgItemMessage(hwndDlg + , IDC_SAMEAS + , CB_GETITEMDATA + , SendDlgItemMessage(hwndDlg, IDC_SAMEAS, CB_GETCURSEL, 0, 0) + , 0 + ); + GetDlgItemTextA(hwndDlg, IDC_TYPEFACE, s_rgFontSettings[wParam].szFace, sizeof(s_rgFontSettings[wParam].szFace)); + s_rgFontSettings[wParam].charset = (BYTE)SendDlgItemMessage(hwndDlg + , IDC_SCRIPT + , CB_GETITEMDATA + , SendDlgItemMessage(hwndDlg, IDC_SCRIPT, CB_GETCURSEL, 0, 0) + , 0 + ); + s_rgFontSettings[wParam].size = (char)GetDlgItemInt(hwndDlg, IDC_FONTSIZE, NULL, FALSE); + s_rgFontSettings[wParam].style= (IsDlgButtonChecked(hwndDlg, IDC_BOLD) ? DBFONTF_BOLD : 0) + | (IsDlgButtonChecked(hwndDlg, IDC_ITALIC) ? DBFONTF_ITALIC : 0) + | (IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE) ? DBFONTF_UNDERLINE : 0); + s_rgFontSettings[wParam].colour = SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_GETCOLOUR, 0, 0); + break; + } + // load font wParam into the controls + case M_LOADFONT: + { + LOGFONTA lf; + COLORREF colour; + + SetDlgItemTextA(hwndDlg, IDC_TYPEFACE, s_rgFontSettings[wParam].szFace); + SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, wParam, 0); + SetDlgItemInt(hwndDlg, IDC_FONTSIZE, s_rgFontSettings[wParam].size, FALSE); + CheckDlgButton(hwndDlg, IDC_BOLD, ((s_rgFontSettings[wParam].style & DBFONTF_BOLD) ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_ITALIC, ((s_rgFontSettings[wParam].style & DBFONTF_ITALIC) ? BST_CHECKED : BST_UNCHECKED)); + CheckDlgButton(hwndDlg, IDC_UNDERLINE, ((s_rgFontSettings[wParam].style & DBFONTF_UNDERLINE) ? BST_CHECKED : BST_UNCHECKED)); + GetDefaultFontSetting(TRUE, wParam, &lf, &colour); + SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_SETDEFAULTCOLOUR, 0, colour); + SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_SETCOLOUR, 0, s_rgFontSettings[wParam].colour); + break; + } + // guess suitable values for the 'same as' checkboxes for fontId wParam + case M_GUESSSAMEASBOXES: + { + s_rgFontSettings[wParam].sameAsFlags = 0; + if (FLT_SAME_AS_NONE != s_rgFontSettings[wParam].sameAs) + { + SFontSettings* pSameAs = ((FLT_SAME_AS_MIRANDA == s_rgFontSettings[wParam].sameAs) + ? &s_rgFontSettingsMiranda[wParam] + : &s_rgFontSettings[s_rgFontSettings[wParam].sameAs] + ); + + if (!lstrcmpA(s_rgFontSettings[wParam].szFace, pSameAs->szFace) && s_rgFontSettings[wParam].charset == pSameAs->charset) + s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_FACE; + if (s_rgFontSettings[wParam].size == pSameAs->size) + s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_SIZE; + if (s_rgFontSettings[wParam].style == pSameAs->style) + s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_STYLE; + if (s_rgFontSettings[wParam].colour == pSameAs->colour) + s_rgFontSettings[wParam].sameAsFlags |= SAMEASF_COLOUR; + SendMessage(hwndDlg,M_SETSAMEASBOXES,wParam,0); + } + break; + } + case WM_CTLCOLORSTATIC: + { + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SAMPLE)) + { + SetTextColor((HDC)wParam, SendDlgItemMessage(hwndDlg, IDC_COLOUR, CPM_GETCOLOUR, 0, 0)); + SetBkColor((HDC)wParam, GetSysColor(COLOR_3DFACE)); + return (BOOL)GetSysColorBrush(COLOR_3DFACE); + } + break; + } + case WM_HSCROLL: + { + if (wParam != TB_ENDTRACK) + { + int nPos; + char szPercent[20]; + + nPos = (BYTE)SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_GETPOS, 0, 0); + fcOpt.thumbAlpha = (BYTE)(( nPos * 255 ) / 100 ); + SetThumbsOpacity(fcOpt.thumbAlpha); + + wsprintfA(szPercent, "%d%%", nPos); + SetDlgItemTextA(hwndDlg, IDC_OPACITY, szPercent); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + } + case WM_COMMAND: + { + int nFontId = SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETITEMDATA + , SendDlgItemMessage(hwndDlg, IDC_FONTID, CB_GETCURSEL, 0, 0) + , 0 + ); + + switch (LOWORD(wParam)) + { + case IDC_DRAWBORDER: + { + SendMessage(hwndDlg, M_REFRESHBORDERPICKERS, 0, 0); + break; + } + case IDC_BROWSE: + { + char str[MAX_PATH]; + OPENFILENAMEA ofn={0}; + char filter[512]; + + GetDlgItemTextA(hwndDlg, IDC_FILENAME, str, sizeof(str)); + ofn.lStructSize = sizeof(OPENFILENAMEA); + ofn.hwndOwner = hwndDlg; + ofn.hInstance = NULL; + CallService(MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof(filter), (LPARAM)filter); + ofn.lpstrFilter = filter; + ofn.lpstrFile = str; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.nMaxFile = sizeof(str); + ofn.nMaxFileTitle = MAX_PATH; + ofn.lpstrDefExt = "bmp"; + if (!GetOpenFileNameA(&ofn)) + return FALSE; + SetDlgItemTextA(hwndDlg, IDC_FILENAME, str); + break; + } + case IDC_FILENAME: + { + if (EN_CHANGE != HIWORD(wParam) || (HWND)lParam != GetFocus()) + return FALSE; + break; + } + case IDC_BITMAP: + { + SendMessage(hwndDlg, M_REFRESHBKGBOXES, 0, 0); + break; + } + case IDC_FONTID: + { + if (CBN_SELCHANGE == HIWORD(wParam)) + SendMessage(hwndDlg, M_REBUILDFONTGROUP, 0, 0); + return FALSE; + } + case IDC_SAMETYPE: + case IDC_SAMESIZE: + case IDC_SAMESTYLE: + case IDC_SAMECOLOUR: + { + SendMessage(hwndDlg, M_SAVEFONT, nFontId, 0); + SendMessage(hwndDlg, M_RECALCONEFONT, nFontId, 0); + SendMessage(hwndDlg, M_RECALCOTHERFONTS, nFontId, 0); + SendMessage(hwndDlg, M_LOADFONT, nFontId, 0); + SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, nFontId, 0); + SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0); + break; + } + case IDC_SAMEAS: + { + if (CBN_SELCHANGE != HIWORD(wParam)) + return FALSE; + SendMessage(hwndDlg, M_SAVEFONT, nFontId, 0); + SendMessage(hwndDlg, M_GUESSSAMEASBOXES, nFontId, 0); + SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, nFontId, 0); + break; + } + case IDC_TYPEFACE: + case IDC_SCRIPT: + case IDC_FONTSIZE: + { + if (CBN_EDITCHANGE != HIWORD(wParam) && CBN_SELCHANGE != HIWORD(wParam)) + return FALSE; + if (CBN_SELCHANGE == HIWORD(wParam)) + SendDlgItemMessage(hwndDlg, LOWORD(wParam), CB_SETCURSEL, SendDlgItemMessage(hwndDlg, LOWORD(wParam), CB_GETCURSEL, 0, 0), 0); + if (IDC_TYPEFACE == LOWORD(wParam)) + SendMessage(hwndDlg, M_FILLSCRIPTCOMBO, nFontId, 0); + // FALL THRU + } + case IDC_BOLD: + case IDC_ITALIC: + case IDC_UNDERLINE: + case IDC_COLOUR: + { + SendMessage(hwndDlg, M_SAVEFONT, nFontId, 0); + //SendMessage(hwndDlg, M_GUESSSAMEASBOXES, nFontId, 0); + //SendMessage(hwndDlg, M_REFRESHSAMEASBOXES, nFontId, 0); + SendMessage(hwndDlg, M_RECALCOTHERFONTS, nFontId, 0); + SendMessage(hwndDlg, M_REMAKESAMPLE, 0, 0); + break; + } + case IDC_SAMPLE: + return 0; + } + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + case WM_NOTIFY: + { + LPNMHDR phdr = (LPNMHDR)(lParam); + + if (0 == phdr->idFrom) + { + switch (phdr->code) + { + case PSN_APPLY: + { + int i; + char str[20]; + //BOOL bSuccess = FALSE; + + // Border + DBWriteContactSettingByte(NULL, sModule, "DrawBorder", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DRAWBORDER)); + { + COLORREF col; + + col = SendDlgItemMessage(hwndDlg, IDC_LTEDGESCOLOR, CPM_GETCOLOUR, 0, 0); + DBWriteContactSettingDword(NULL, sModule, "LTEdgesColor", col); + col = SendDlgItemMessage(hwndDlg, IDC_RBEDGESCOLOR, CPM_GETCOLOUR, 0, 0); + DBWriteContactSettingDword(NULL, sModule, "RBEdgesColor", col); + } + + // Backgroud + { + COLORREF col; + + col = SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0); + DBWriteContactSettingDword(NULL, sModule, "BkColor", col); + } + DBWriteContactSettingByte(NULL, sModule, "BkUseBitmap", (BYTE)IsDlgButtonChecked(hwndDlg, IDC_BITMAP)); + { + char str[MAX_PATH]; + + GetDlgItemTextA(hwndDlg, IDC_FILENAME, str, sizeof(str)); + DBWriteContactSettingString(NULL, sModule, "BkBitmap", str); + } + { + WORD flags = 0; + + if (IsDlgButtonChecked(hwndDlg, IDC_STRETCHH)) + flags |= CLB_STRETCHH; + if (IsDlgButtonChecked(hwndDlg, IDC_STRETCHV)) + flags |= CLB_STRETCHV; + if (IsDlgButtonChecked(hwndDlg, IDC_TILEH)) + flags |= CLBF_TILEH; + if (IsDlgButtonChecked(hwndDlg, IDC_TILEV)) + flags |= CLBF_TILEV; + if (IsDlgButtonChecked(hwndDlg, IDC_PROPORTIONAL)) + flags |= CLBF_PROPORTIONAL; + DBWriteContactSettingWord(NULL, sModule, "BkBitmapOpt", flags); + } + + DBWriteContactSettingByte(NULL, sModule, "Opacity" + , (BYTE)SendDlgItemMessage(hwndDlg, IDC_SLIDER_OPACITY, TBM_GETPOS, 0, 0) + ); + + for (i = 0; i < FLT_FONTIDS; i++) + { + wsprintfA(str, "Font%dName", i); + DBWriteContactSettingString(NULL, sModule, str, s_rgFontSettings[i].szFace); + wsprintfA(str, "Font%dSet", i); + DBWriteContactSettingByte(NULL, sModule, str, s_rgFontSettings[i].charset); + wsprintfA(str, "Font%dSize", i); + DBWriteContactSettingByte(NULL, sModule, str, s_rgFontSettings[i].size); + wsprintfA(str, "Font%dSty", i); + DBWriteContactSettingByte(NULL, sModule, str, s_rgFontSettings[i].style); + wsprintfA(str, "Font%dCol", i); + DBWriteContactSettingDword(NULL, sModule, str, s_rgFontSettings[i].colour); + wsprintfA(str, "Font%dAs", i); + DBWriteContactSettingWord(NULL, sModule, str, MAKEWORD(s_rgFontSettings[i].sameAs, s_rgFontSettings[i].sameAsFlags)); + } + + ApplyOptionsChanges(); + OnStatusChanged(); + return TRUE; + } + case PSN_RESET: + //case PSN_KILLACTIVE: + { + fcOpt.thumbAlpha = (BYTE)((double)DBGetContactSettingByte(NULL, sModule, "Opacity", 100) * 2.55); + SetThumbsOpacity(fcOpt.thumbAlpha); + break; + } + } + } + break; + } + case WM_DESTROY: + { + if (hFontSample) + { + SendDlgItemMessage(hwndDlg, IDC_SAMPLE, WM_SETFONT, SendDlgItemMessage(hwndDlg, IDC_FONTID, WM_GETFONT, 0, 0), 0); + DeleteObject(hFontSample); + } + break; + } + + } + return FALSE; +} + diff --git a/plugins/FloatingContacts/resource.h b/plugins/FloatingContacts/resource.h new file mode 100644 index 0000000000..fec93538d8 --- /dev/null +++ b/plugins/FloatingContacts/resource.h @@ -0,0 +1,75 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Script.rc +// +#define IDD_OPT_FLTCONT 101 +#define IDI_ICON1 103 +#define IDI_HIDE 103 +#define IDI_SHOW 105 +#define IDD_OPT_FNT 106 +#define IDD_OPT_SKIN 106 +#define IDC_SLIDER_OPACITY 1001 +#define IDC_OPACITY 1002 +#define IDC_CHK_HIDE_OFFLINE 1003 +#define IDC_CHK_STICK 1004 +#define IDC_CHK_WIDTH 1005 +#define IDC_LBL_WIDTH 1006 +#define IDC_TXT_WIDTH 1007 +#define IDC_WIDTHSPIN 1008 +#define IDC_TXT_TIMEIN 1009 +#define IDC_TIMEINSPIN 1010 +#define IDC_TXT_TOTOPTIME 1011 +#define IDC_CHK_HIDE_ALL 1012 +#define IDC_CHK_DEF_BACKGROUND 1013 +#define IDC_TOTOPTIMESPIN 1013 +#define IDC_CHK_HIDE_WHEN_FULSCREEN 1014 +#define IDC_CHK_TIP 1015 +#define IDC_LBL_TIMEIN 1016 +#define IDC_CHK_TOTOP 1017 +#define IDC_LBL_TOTOP 1018 +#define IDC_CHK_HIDE_WHEN_CLISTSHOW 1019 +#define IDC_CHECK1 1020 +#define IDC_CHK_SINGLECLK 1020 +#define IDC_CHECK2 1021 +#define IDC_CHK_SHOWIDLE 1021 +#define IDC_FONTID 1100 +#define IDC_SAMEAS 1101 +#define IDC_LBL_TIMEIN_CMT 1101 +#define IDC_SAMETYPE 1102 +#define IDC_SAMESIZE 1103 +#define IDC_SAMESTYLE 1104 +#define IDC_SAMECOLOUR 1105 +#define IDC_TYPEFACE 1106 +#define IDC_SCRIPT 1107 +#define IDC_FONTSIZE 1108 +#define IDC_BOLD 1109 +#define IDC_ITALIC 1110 +#define IDC_UNDERLINE 1111 +#define IDC_COLOUR 1112 +#define IDC_SAMPLE 1113 +#define IDC_STSAMETEXT 1114 +#define IDC_STASTEXT 1115 +#define IDC_STHORZBAR 1116 +#define IDC_BKGCOLOUR 1200 +#define IDC_BITMAP 1201 +#define IDC_FILENAME 1202 +#define IDC_BROWSE 1203 +#define IDC_STRETCHH 1204 +#define IDC_STRETCHV 1205 +#define IDC_TILEH 1206 +#define IDC_TILEV 1207 +#define IDC_PROPORTIONAL 1208 +#define IDC_DRAWBORDER 1209 +#define IDC_LTEDGESCOLOR 1210 +#define IDC_RBEDGESCOLOR 1211 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1022 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/FloatingContacts/show.ico b/plugins/FloatingContacts/show.ico new file mode 100644 index 0000000000..f924c12891 Binary files /dev/null and b/plugins/FloatingContacts/show.ico differ diff --git a/plugins/FloatingContacts/stdhdr.h b/plugins/FloatingContacts/stdhdr.h new file mode 100644 index 0000000000..95e5c6cca7 --- /dev/null +++ b/plugins/FloatingContacts/stdhdr.h @@ -0,0 +1,64 @@ + +#ifndef __STDHDR_H__ +#define __STDHDR_H__ + +// disable security warnings about "*_s" functions +#define _CRT_SECURE_NO_DEPRECATE + +// disable warnings about underscore in stdc functions +#pragma warning(disable: 4996) + +// Unreferenced formal parameter +#pragma warning(disable: 4100) + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +///////////////////////////////////////////////////////////////////////////// +// + +#define STRICT + +#include +#include +#include + +#pragma warning ( disable : 4201 ) //nonstandard extension used : nameless struct/union +#include + +#define MIRANDA_VER 0x600 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "../../include/msgs.h" +#include +#include +#include +#include +#include +//#include "../../include/clc.h" +#include +#include + +#include "bitmap_funcs.h" + +#include "fltcont.h" +#include "thumbs.h" +#include "filedrop.h" +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// + +#endif // #ifndef __STDHDR_H__ + +///////////////////////////////////////////////////////////////////////////// +// End Of File stdhdr.h diff --git a/plugins/FloatingContacts/thumbs.cpp b/plugins/FloatingContacts/thumbs.cpp new file mode 100644 index 0000000000..ad08865f01 --- /dev/null +++ b/plugins/FloatingContacts/thumbs.cpp @@ -0,0 +1,1013 @@ +#include "stdhdr.h" +#include "Wingdi.h" + +ThumbList thumbList; + +///////////////////////////////////////////////////////////////////////////// +// ThumbInfo +static POINT ptOld; +static BOOL bMouseDown = FALSE; +static BOOL bMouseIn = FALSE; +static BOOL bMouseMoved = FALSE; +static short nLeft = 0; +static short nTop = 0; +static int nOffs = 5; +static ThumbInfo *pThumbMouseIn = NULL; + +static void SnapToScreen( RECT rcThumb, int nX, int nY, int *pX, int *pY ) +{ + int nWidth; + int nHeight; + + assert( NULL != pX ); + assert( NULL != pY ); + + nWidth = rcThumb.right - rcThumb.left; + nHeight = rcThumb.bottom - rcThumb.top; + + *pX = nX < ( nOffs + rcScreen.left ) ? rcScreen.left : nX; + *pY = nY < ( nOffs + rcScreen.top ) ? rcScreen.top : nY; + *pX = *pX > ( rcScreen.right - nWidth - nOffs ) ? ( rcScreen.right - nWidth ) : *pX; + *pY = *pY > ( rcScreen.bottom - nHeight - nOffs ) ? ( rcScreen.bottom - nHeight ) : *pY; +} + +ThumbInfo::ThumbInfo() +{ + dropTarget = new CDropTarget; + dropTarget->AddRef(); + btAlpha = 255; +} + +ThumbInfo::~ThumbInfo() +{ + if(pThumbMouseIn==this){ + pThumbMouseIn=NULL; + KillTimer(hwnd, TIMERID_LEAVE_T); + } + dropTarget->Release(); +} + +void ThumbInfo::GetThumbRect(RECT *rc) +{ + rc->left = ptPos.x; + rc->top = ptPos.y; + rc->right = ptPos.x + szSize.cx; + rc->bottom = ptPos.y + szSize.cy; +} + +void ThumbInfo::PositionThumb(short nX, short nY) +{ + POINT pos = { nX, nY }; + HDWP hdwp; + + hdwp = BeginDeferWindowPos(1); + + ThumbInfo *pThumb = this; + while (pThumb) + { + pThumb->PositionThumbWorker( (short)pos.x, (short)pos.y, &pos ); + + DeferWindowPos( hdwp, + pThumb->hwnd, + HWND_TOPMOST, + pos.x, + pos.y, + 0, + 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); + + pThumb->ptPos = pos; + pos.x += pThumb->szSize.cx; + + pThumb = fcOpt.bMoveTogether ? thumbList.FindThumb( pThumb->dockOpt.hwndRight ) : NULL; + } + + EndDeferWindowPos(hdwp); +} + +void ThumbInfo::PositionThumbWorker(short nX, short nY, POINT *newPos) +{ + RECT rc; + RECT rcThumb; + int nNewX; + int nNewY; + int nWidth; + int nHeight; + POINT pt; + RECT rcLeft; + RECT rcTop; + RECT rcRight; + RECT rcBottom; + BOOL bDocked; + BOOL bDockedLeft; + BOOL bDockedRight; + BOOL bLeading; + + // Get thumb dimnsions + GetThumbRect( &rcThumb ); + nWidth = rcThumb.right - rcThumb.left; + nHeight = rcThumb.bottom - rcThumb.top; + + // Docking and screen boundaries check + SnapToScreen( rcThumb, nX, nY, &nNewX, &nNewY ); + + bLeading = dockOpt.hwndRight != NULL; + + if ( fcOpt.bMoveTogether ) + { + UndockThumbs( this, thumbList.FindThumb( dockOpt.hwndLeft ) ); + } + + + for (int i = 0; i < thumbList.getCount(); ++i) + { + ThumbInfo *pCurThumb = thumbList[i]; + + if ( pCurThumb != this ) + { + GetThumbRect( &rcThumb ); + OffsetRect( &rcThumb, nX - rcThumb.left, nY - rcThumb.top ); + + pCurThumb->GetThumbRect( &rc ); + + // These are rects we will dock into + + rcLeft.left = rc.left - nOffs; + rcLeft.top = rc.top - nOffs; + rcLeft.right = rc.left + nOffs; + rcLeft.bottom = rc.bottom + nOffs; + + rcTop.left = rc.left - nOffs; + rcTop.top = rc.top - nOffs; + rcTop.right = rc.right + nOffs; + rcTop.bottom = rc.top + nOffs; + + rcRight.left = rc.right - nOffs; + rcRight.top = rc.top - nOffs; + rcRight.right = rc.right + nOffs; + rcRight.bottom = rc.bottom + nOffs; + + rcBottom.left = rc.left - nOffs; + rcBottom.top = rc.bottom - nOffs; + rcBottom.right = rc.right + nOffs; + rcBottom.bottom = rc.bottom + nOffs; + + + bDockedLeft = FALSE; + bDockedRight = FALSE; + + // Upper-left + pt.x = rcThumb.left; + pt.y = rcThumb.top; + bDocked = FALSE; + + if ( PtInRect( &rcRight, pt ) ) + { + nNewX = rc.right; + bDocked = TRUE; + } + + if ( PtInRect( &rcBottom, pt ) ) + { + nNewY = rc.bottom; + + if ( PtInRect( &rcLeft, pt ) ) + { + nNewX = rc.left; + } + } + + if ( PtInRect( &rcTop, pt ) ) + { + nNewY = rc.top; + bDockedLeft = bDocked; + } + + // Upper-right + pt.x = rcThumb.right; + pt.y = rcThumb.top; + bDocked = FALSE; + + if ( !bLeading && PtInRect( &rcLeft, pt ) ) + { + if ( !bDockedLeft ) + { + nNewX = rc.left - nWidth; + bDocked = TRUE; + } + else if ( rc.right == rcThumb.left ) + { + bDocked = TRUE; + } + } + + + if ( PtInRect( &rcBottom, pt ) ) + { + nNewY = rc.bottom; + + if ( PtInRect( &rcRight, pt ) ) + { + nNewX = rc.right - nWidth; + } + } + + if ( !bLeading && PtInRect( &rcTop, pt ) ) + { + nNewY = rc.top; + bDockedRight = bDocked; + } + + if ( fcOpt.bMoveTogether ) + { + if ( bDockedRight ) + { + DockThumbs( this, pCurThumb, TRUE ); + } + + if ( bDockedLeft ) + { + DockThumbs( pCurThumb, this, FALSE ); + } + } + + // Lower-left + pt.x = rcThumb.left; + pt.y = rcThumb.bottom; + + if ( PtInRect( &rcRight, pt ) ) + { + nNewX = rc.right; + } + + if ( PtInRect( &rcTop, pt ) ) + { + nNewY = rc.top - nHeight; + + if ( PtInRect( &rcLeft, pt ) ) + { + nNewX = rc.left; + } + } + + + // Lower-right + pt.x = rcThumb.right; + pt.y = rcThumb.bottom; + + if ( !bLeading && PtInRect( &rcLeft, pt ) ) + { + nNewX = rc.left - nWidth; + } + + if ( !bLeading && PtInRect( &rcTop, pt ) ) + { + nNewY = rc.top - nHeight; + + if ( PtInRect( &rcRight, pt ) ) + { + nNewX = rc.right - nWidth; + } + } + } + } + + // Adjust coords once again + SnapToScreen( rcThumb, nNewX, nNewY, &nNewX, &nNewY ); + + newPos->x = nNewX; + newPos->y = nNewY; +} + +void ThumbInfo::ResizeThumb() +{ + HDC hdc = NULL; + HFONT hOldFont = NULL; + POINT ptText; + SIZEL sizeIcon; + SIZEL sizeText; + RECT rcThumb; + int index = FLT_FONTID_NOTONLIST; + + ThumbInfo *pNextThumb = NULL; + + himl = ( HIMAGELIST )CallService( MS_CLIST_GETICONSIMAGELIST, 0, 0 ); + + if ( himl == NULL ) return; + + ImageList_GetIconSize_my(himl, sizeIcon); + + hdc = GetWindowDC(hwnd); + + if (!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) + { + int nStatus; + int nContactStatus; + int nApparentMode; + char* szProto; + + szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + if ( NULL != szProto ) + { + nStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); + nContactStatus = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE); + nApparentMode = DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0); + + if ( (nStatus == ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_ONLINE) + || (nStatus != ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_OFFLINE) + ) + { + if (ID_STATUS_OFFLINE == nContactStatus) + { + index = FLT_FONTID_OFFINVIS; + } + else + { + index = FLT_FONTID_INVIS; + } + } + else if (ID_STATUS_OFFLINE == nContactStatus) + { + index = FLT_FONTID_OFFLINE; + } + else + { + index = FLT_FONTID_CONTACTS; + } + } + } + else + { + index = FLT_FONTID_NOTONLIST; + } + + hOldFont = (HFONT)SelectObject( hdc, hFont[ index ] ); + + // Get text and icon sizes + GetTextExtentPoint32( hdc, ptszName, _tcslen( ptszName ), &sizeText ); + + + SelectObject( hdc, hOldFont ); + + // Transform text size + ptText.x = sizeText.cx; + ptText.y = sizeText.cy; + LPtoDP( hdc, &ptText, 1 ); + + + szSize.cx = fcOpt.bFixedWidth ? fcOpt.nThumbWidth : sizeIcon.cx + ptText.x + 10; + szSize.cy = ( ( sizeIcon.cy > ptText.y ) ? sizeIcon.cy : ptText.y ) + 4; + + SetWindowPos( hwnd, + HWND_TOPMOST, + 0, + 0, + szSize.cx, + szSize.cy, + SWP_NOMOVE | /*SWP_NOZORDER |*/ SWP_NOACTIVATE ); + + RefreshContactIcon(0xFFFFFFFF); + + ReleaseDC( hwnd, hdc ); + + // Move the docked widnow if needed + if (pNextThumb = thumbList.FindThumb(dockOpt.hwndRight)) + { + GetThumbRect( &rcThumb ); + pNextThumb->PositionThumb( (short)rcThumb.right, (short)rcThumb.top ); + } +} + +void ThumbInfo::RefreshContactIcon(int iIcon) +{ + if ( iIcon == 0xFFFFFFFF || ImageList_GetImageCount(himl)<=iIcon ) + { + this->iIcon = CallService( MS_CLIST_GETCONTACTICON, (WPARAM)hContact, 0 ); + } + else + { + this->iIcon = iIcon; + } + + UpdateContent(); +} + +void ThumbInfo::RefreshContactStatus(int idStatus) +{ + if ( IsStatusVisible( idStatus ) ) + { + RegisterFileDropping( hwnd, dropTarget ); + } + else + { + UnregisterFileDropping( hwnd ); + } + + ShowWindow( hwnd, fcOpt.bHideAll || HideOnFullScreen() || ( fcOpt.bHideOffline && ( !IsStatusVisible( idStatus ) ) ) || (fcOpt.bHideWhenCListShow && bIsCListShow) ? SW_HIDE : SW_SHOWNA ); +} + +void ThumbInfo::DeleteContactPos() +{ + DBDeleteContactSetting( hContact, sModule, "ThumbsPos" ); +} + +void ThumbInfo::OnLButtonDown(short nX, short nY) +{ + RECT rc; + + if(bEnableTip && fcOpt.bShowTip) KillTip(); + +// ptOld.x = nX; +// ptOld.y = nY; + +// ClientToScreen( hwnd, &ptOld ); + + GetCursorPos(&ptOld); + GetThumbRect(&rc); + + nLeft = (short)rc.left; + nTop = (short)rc.top; + + //bMouseIn = FALSE; + bMouseDown = TRUE; + bMouseMoved = FALSE; + +// SetCapture(hwnd); +} + +void ThumbInfo::OnLButtonUp() +{ + RECT rcMiranda; + RECT rcThumb; + RECT rcOverlap; + + if (!bMouseMoved && fcOpt.bUseSingleClick && bMouseIn){ + PopUpMessageDialog(); + } + + //ThumbDeselect( TRUE ); + + if ( bMouseDown ) + { + bMouseDown = FALSE; + SetCursor( LoadCursor( NULL, IDC_ARROW ) ); + + // Check whether we shoud remove the window + GetWindowRect( hwndMiranda, &rcMiranda ); + GetThumbRect( &rcThumb ); + + if ( IntersectRect( &rcOverlap, &rcMiranda, &rcThumb ) ) + { + if( IsWindowVisible( hwndMiranda ) ) + { + DeleteContactPos( ); + thumbList.RemoveThumb( this ); + } + } + } + + SaveContactsPos(); +} + +void ThumbInfo::OnMouseMove(short nX, short nY, WPARAM wParam) +{ +// if (bMouseDown && !wParam&MK_LBUTTON) OnLButtonUp(); + + int dX; + int dY; + POINT ptNew; + + // Position thumb + + if( bMouseDown ) + { + + ptNew.x = nX; + ptNew.y = nY; + + ClientToScreen( hwnd, &ptNew ); + + dX = ptNew.x - ptOld.x; + dY = ptNew.y - ptOld.y; + + if(dX || dY){ + bMouseMoved = TRUE; + + nLeft += (short)dX; + nTop += (short)dY; + + PositionThumb( nLeft, nTop ); + } + + ptOld = ptNew; + } + else + { + SetCursor( LoadCursor( NULL, IDC_ARROW ) ); + } + + // Update selection status + if ( !pThumbMouseIn )// + { + SetTimer( hwnd, TIMERID_LEAVE_T, 10, NULL ); + pThumbMouseIn=this; + + ThumbSelect( TRUE ); + } + if(bEnableTip && fcOpt.bShowTip && !bMouseDown){ + WORD tmpTimeIn; + POINT pt; + RECT rc; + + GetCursorPos(&pt); + GetThumbRect(&rc); + if(!PtInRect(&rc,pt)){ + KillTip(); + return; + } + if(fTipTimerActive && abs(pt.x-ptTipSt.x)<5 && abs(pt.y-ptTipSt.x)<5){ + return; + } + ptTipSt=pt; + + if (fTipTimerActive) { + KillTimer(hwnd, TIMERID_HOVER_T); + } + if (fTipActive) { + return; + } + + tmpTimeIn = (fcOpt.TimeIn>0)?fcOpt.TimeIn:CallService(MS_CLC_GETINFOTIPHOVERTIME, 0, 0); + SetTimer(hwnd, TIMERID_HOVER_T, tmpTimeIn, 0); + fTipTimerActive = TRUE; + } +} + +void ThumbInfo::ThumbSelect(BOOL bMouse) +{ + if ( bMouse ) + { + bMouseIn = TRUE; + SetCapture( hwnd ); + } + + SetThumbOpacity( 255 ); +} + +void ThumbInfo::ThumbDeselect(BOOL bMouse) +{ + if ( bMouse ) + { + bMouseIn = FALSE; + ReleaseCapture(); + } + + SetThumbOpacity( fcOpt.thumbAlpha ); +} + +void ThumbInfo::SetThumbOpacity(BYTE bAlpha) +{ + if ( pUpdateLayeredWindow && (bAlpha != btAlpha) ) + { + btAlpha = bAlpha; + UpdateContent(); + } +} + +void ThumbInfo::KillTip() +{ + if (fTipTimerActive) + { + KillTimer(hwnd, TIMERID_HOVER_T); + fTipTimerActive = FALSE; + } + + if (fTipActive) + { + CallService("mToolTip/HideTip", 0, 0); + fTipActive = FALSE; + } +} + +void ThumbInfo::UpdateContent() +{ + bmpContent.allocate(szSize.cx, szSize.cy); + + HFONT hOldFont; + SIZE size; + RECT rc; + RECT rcText; + DWORD oldColor; + int oldBkMode, index = 0;// nStatus; + UINT fStyle = ILD_NORMAL; + + HDC hdcDraw = bmpContent.getDC(); + SetRect(&rc, 0, 0, szSize.cx, szSize.cy); + + if ( NULL != hBmpBackground ) + { + RECT rcBkgnd; + BITMAP bmp; + HDC hdcBmp; + HBITMAP hbmTmp; + int x,y; + int maxx,maxy; + int destw,desth; + int width; + int height; + + SetRect(&rcBkgnd, 0, 0, szSize.cx, szSize.cy); + if (NULL != hLTEdgesPen) + InflateRect(&rcBkgnd, -1, -1); + width = rcBkgnd.right - rcBkgnd.left; + height = rcBkgnd.bottom - rcBkgnd.top; + + GetObject(hBmpBackground, sizeof(bmp), &bmp); + hdcBmp = CreateCompatibleDC( hdcDraw ); + hbmTmp = (HBITMAP)SelectObject( hdcBmp, hBmpBackground ); + + maxx = (0 != (nBackgroundBmpUse & CLBF_TILEH) ? rcBkgnd.right : rcBkgnd.left + 1); + maxy = (0 != (nBackgroundBmpUse & CLBF_TILEV) ? rcBkgnd.bottom : rcBkgnd.top + 1); + switch (nBackgroundBmpUse & CLBM_TYPE) + { + case CLB_STRETCH: + if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL)) + { + if (width * bmp.bmHeight < height * bmp.bmWidth) + { + desth = height; + destw = desth * bmp.bmWidth / bmp.bmHeight; + } + else + { + destw = width; + desth = destw * bmp.bmHeight / bmp.bmWidth; + } + } + else + { + destw = width; + desth = height; + } + break; + + case CLB_STRETCHH: + destw = width; + if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL)) + desth = destw * bmp.bmHeight / bmp.bmWidth; + else + desth = bmp.bmHeight; + break; + + case CLB_STRETCHV: + desth = height; + if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL)) + destw = desth * bmp.bmWidth / bmp.bmHeight; + else + destw = bmp.bmWidth; + break; + + default: //clb_topleft + destw = bmp.bmWidth; + desth = bmp.bmHeight; + break; + } + SetStretchBltMode(hdcBmp, STRETCH_HALFTONE); + + for (x = rcBkgnd.left; x < maxx; x += destw) + { + for (y = rcBkgnd.top; y < maxy; y += desth) + { + StretchBlt( hdcDraw, x, y, destw, desth, hdcBmp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY ); + } + } + + SelectObject( hdcBmp, hbmTmp ); + DeleteDC( hdcBmp ); + } + else + { + FillRect( hdcDraw, &rc, hBkBrush ); + } + + if (NULL != hLTEdgesPen) + { + HPEN hOldPen = (HPEN)SelectObject( hdcDraw, hLTEdgesPen ); + + MoveToEx(hdcDraw, 0, 0, NULL); + LineTo(hdcDraw, szSize.cx, 0); + MoveToEx(hdcDraw, 0, 0, NULL); + LineTo(hdcDraw, 0, szSize.cy); + + SelectObject(hdcDraw, hRBEdgesPen); + + MoveToEx(hdcDraw, 0, szSize.cy - 1, NULL); + LineTo(hdcDraw, szSize.cx - 1, szSize.cy - 1); + MoveToEx(hdcDraw, szSize.cx - 1, szSize.cy - 1, NULL); + LineTo(hdcDraw, szSize.cx - 1, 0); + + SelectObject(hdcDraw, hOldPen); + //InflateRect(&rc, -1, -1); + } + + bmpContent.setAlpha(btAlpha); + + ImageList_GetIconSize_my( himl, size ); + + oldBkMode = SetBkMode( hdcDraw, TRANSPARENT ); + + if (!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) + { + int nStatus; + int nContactStatus; + int nApparentMode; + char* szProto; + + + szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + if ( NULL != szProto ) + { + nStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); + nContactStatus = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE); + nApparentMode = DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0); + + if ( (nStatus == ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_ONLINE) || + (nStatus != ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_OFFLINE) ) + { + if (ID_STATUS_OFFLINE == nContactStatus) + { + index = FLT_FONTID_OFFINVIS; + } + else + { + index = FLT_FONTID_INVIS; + if(fcOpt.bShowIdle && DBGetContactSettingDword(hContact, szProto, "IdleTS", 0)){ + fStyle|=ILD_BLEND50; + } + } + } + else if (ID_STATUS_OFFLINE == nContactStatus) + { + index = FLT_FONTID_OFFLINE; + } + else + { + index = FLT_FONTID_CONTACTS; + if(fcOpt.bShowIdle && DBGetContactSettingDword(hContact, szProto, "IdleTS", 0)){ + fStyle|=ILD_BLEND50; + } + } + + } + } + else + { + index = FLT_FONTID_NOTONLIST; + fStyle|=ILD_BLEND50; + } + + oldColor = SetTextColor( hdcDraw, tColor[ index ] ); + +/* ImageList_DrawEx( himl, + iIcon, + hdcDraw, + 2, + ( szSize.cy - size.cx ) / 2, + 0, + 0, + CLR_NONE, + CLR_NONE, + fStyle); +*/ + { + HICON icon = ImageList_GetIcon(himl, iIcon, ILD_NORMAL); + MyBitmap bmptmp(size.cx, size.cy); + bmptmp.DrawIcon(icon,0,0);//bmpContent + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = (fStyle&ILD_BLEND50)?128:255; + blend.AlphaFormat = AC_SRC_ALPHA; + AlphaBlend(hdcDraw, 2,( szSize.cy - size.cx ) / 2, bmptmp.getWidth(), bmptmp.getHeight(), bmptmp.getDC(), 0, 0, bmptmp.getWidth(), bmptmp.getHeight(), blend); + DestroyIcon(icon); + } + SetRect(&rcText, 0, 0, szSize.cx, szSize.cy); + rcText.left += size.cx + 4; + + hOldFont = (HFONT)SelectObject( hdcDraw, hFont[ index ] ); + + SIZE szText; + GetTextExtentPoint32(hdcDraw, ptszName, _tcslen(ptszName), &szText); + SetTextColor(hdcDraw, bkColor); + + // simple border + bmpContent.DrawText(ptszName, rcText.left-1, (rcText.top + rcText.bottom - szText.cy)/2); + bmpContent.DrawText(ptszName, rcText.left+1, (rcText.top + rcText.bottom - szText.cy)/2); + bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2-1); + bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2+1); + + // blurred border + // bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2, 3); + + // text itself + SetTextColor(hdcDraw, tColor[index]); + bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2); + + SelectObject( hdcDraw, hOldFont ); + + SetTextColor( hdcDraw, oldColor ); + SetBkMode( hdcDraw, oldBkMode ); + + if (pUpdateLayeredWindow) + { + SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); + + RECT rc; GetWindowRect(hwnd, &rc); + POINT ptDst = {rc.left, rc.top}; + POINT ptSrc = {0, 0}; + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + + pUpdateLayeredWindow(hwnd, NULL, &ptDst, &szSize, bmpContent.getDC(), &ptSrc, 0xffffffff, &blend, ULW_ALPHA); + } else + { + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + UpdateWindow(hwnd); + } +} + +void ThumbInfo::PopUpMessageDialog( ) +{ + CallService( MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)hContact, (LPARAM)0 ); +} + +void ThumbInfo::OnTimer(BYTE idTimer) +{ + if(idTimer == TIMERID_SELECT_T){ + KillTimer( hwnd, TIMERID_SELECT_T ); + ThumbDeselect( FALSE ); + } + if(idTimer == TIMERID_LEAVE_T && !bMouseDown){ + POINT pt; + RECT rc; + + GetCursorPos(&pt); + GetThumbRect(&rc); + if(!PtInRect(&rc, pt)){ + KillTimer( hwnd, TIMERID_LEAVE_T ); + pThumbMouseIn = NULL; + ThumbDeselect( TRUE ); + } + } + if(bEnableTip && fcOpt.bShowTip && idTimer == TIMERID_HOVER_T){ + POINT pt; + CLCINFOTIP ti = {0}; + ti.cbSize = sizeof(ti); + + KillTimer(hwnd, TIMERID_HOVER_T); + fTipTimerActive = FALSE; + GetCursorPos(&pt); + if(abs(pt.x-ptTipSt.x)<5 && abs(pt.y-ptTipSt.y)<5){ + ti.ptCursor = pt; + + fTipActive = TRUE; + ti.isGroup = 0; + ti.hItem = hContact; + ti.isTreeFocused = 0; + CallService("mToolTip/ShowTip", 0, (LPARAM)&ti); + } + } +} + +void DockThumbs( ThumbInfo *pThumbLeft, ThumbInfo *pThumbRight, BOOL bMoveLeft ) +{ + if ( ( pThumbRight->dockOpt.hwndLeft == NULL ) && ( pThumbLeft->dockOpt.hwndRight == NULL ) ) + { + pThumbRight->dockOpt.hwndLeft = pThumbLeft->hwnd; + pThumbLeft->dockOpt.hwndRight = pThumbRight->hwnd; + } +} + + +void UndockThumbs( ThumbInfo *pThumb1, ThumbInfo *pThumb2 ) +{ + if ( ( pThumb1 == NULL ) || ( pThumb2 == NULL ) ) + { + return; + } + + if ( pThumb1->dockOpt.hwndRight == pThumb2->hwnd ) + { + pThumb1->dockOpt.hwndRight = NULL; + } + + if ( pThumb1->dockOpt.hwndLeft == pThumb2->hwnd ) + { + pThumb1->dockOpt.hwndLeft = NULL; + } + + if ( pThumb2->dockOpt.hwndRight == pThumb1->hwnd ) + { + pThumb2->dockOpt.hwndRight = NULL; + } + + if ( pThumb2->dockOpt.hwndLeft == pThumb1->hwnd ) + { + pThumb2->dockOpt.hwndLeft = NULL; + } +} + +///////////////////////////////////////////////////////////////////////////// +// ThumbList +ThumbList::ThumbList(): LIST(1, cmp) +{ +} + +ThumbList::~ThumbList() +{ + for (int i = 0; i < getCount(); ++i) + delete (*this)[i]; + destroy(); +} + +ThumbInfo *ThumbList::AddThumb(HWND hwnd, TCHAR *ptszName, HANDLE hContact) +{ + ThumbInfo *pThumb = NULL; + + if ( ptszName == NULL ) return( NULL ); + if ( hContact == NULL ) return( NULL ); + if ( hwnd == NULL ) return( NULL ); + + pThumb = new ThumbInfo; + + if ( pThumb != NULL ) + { + _tcsncpy( pThumb->ptszName, ptszName, USERNAME_LEN - 1 ); + pThumb->hContact = hContact; + pThumb->hwnd = hwnd; + + pThumb->dockOpt.hwndLeft = NULL; + pThumb->dockOpt.hwndRight = NULL; + + pThumb->fTipActive = FALSE; + +// RegHotkey(szName, hwnd); + RegHotkey(hContact, hwnd); + } + + insert(pThumb); + + return( pThumb ); +} + +void ThumbList::RemoveThumb(ThumbInfo *pThumb) +{ + if (!pThumb) return; + + if (fcOpt.bMoveTogether) + { + UndockThumbs(pThumb, FindThumb(pThumb->dockOpt.hwndLeft)); + UndockThumbs(pThumb, FindThumb(pThumb->dockOpt.hwndRight)); + } + + remove(pThumb); + + UnregisterFileDropping( pThumb->hwnd ); + DestroyWindow( pThumb->hwnd ); + delete pThumb; +} + +ThumbInfo *ThumbList::FindThumb(HWND hwnd) +{ + if (!hwnd) return NULL; + + for (int i = 0; i < getCount(); ++i) + if ((*this)[i]->hwnd == hwnd) + return (*this)[i]; + + return NULL; +} + +ThumbInfo *ThumbList::FindThumbByContact(HANDLE hContact) +{ + if (!hContact) return NULL; + + for (int i = 0; i < getCount(); ++i) + if ((*this)[i]->hContact == hContact) + return (*this)[i]; + + return NULL; +} + +int ThumbList::cmp(const ThumbInfo *p1, const ThumbInfo *p2) +{ + if ((DWORD)p1->hContact < (DWORD)p2->hContact) return -1; + if ((DWORD)p1->hContact > (DWORD)p2->hContact) return +1; + return 0; +} diff --git a/plugins/FloatingContacts/thumbs.h b/plugins/FloatingContacts/thumbs.h new file mode 100644 index 0000000000..ee6db80097 --- /dev/null +++ b/plugins/FloatingContacts/thumbs.h @@ -0,0 +1,74 @@ +///////////////////////////////////////////////////////////////////////////// +// +#define USERNAME_LEN 50 +class CDropTarget; + +typedef struct _DockOpt +{ + HWND hwndLeft; + HWND hwndRight; +} +DockOpt; + +struct ThumbInfo +{ +public: // TODO: make private + HWND hwnd; + TCHAR ptszName[ USERNAME_LEN ]; + HANDLE hContact; + int iIcon; + CDropTarget * dropTarget; + DockOpt dockOpt; + BOOL fTipActive; + BOOL fTipTimerActive; + POINT ptTipSt; + + BYTE btAlpha; + MyBitmap bmpContent; + + POINT ptPos; + SIZE szSize; + +public: + ThumbInfo(); + ~ThumbInfo(); + + void GetThumbRect (RECT *rc); + void PositionThumb (short nX, short nY); + void PositionThumbWorker (short nX, short nY, POINT *rcNewPos); + void ResizeThumb (); + void RefreshContactIcon (int iIcon); + void RefreshContactStatus (int idStatus); + void DeleteContactPos (); + void OnLButtonDown (short nX, short nY); + void OnLButtonUp (); + void OnMouseMove (short nX, short nY, WPARAM wParam); + void ThumbSelect (BOOL bMouse); + void ThumbDeselect (BOOL bMouse); + void SetThumbOpacity (BYTE btAlpha); + void KillTip (); + void UpdateContent (); + void PopUpMessageDialog (); + void OnTimer (BYTE idTimer); +}; + +void UndockThumbs ( ThumbInfo *pThumb1, ThumbInfo *pThumb2 ); +void DockThumbs ( ThumbInfo *pThumbLeft, ThumbInfo *pThumbRight, BOOL bMoveLeft ); + +class ThumbList: public LIST +{ +public: + ThumbList(); + ~ThumbList(); + + ThumbInfo* AddThumb (HWND hwnd, TCHAR *ptszName, HANDLE hContact); + void RemoveThumb (ThumbInfo *pThumb); + + ThumbInfo* FindThumb (HWND hwnd); + ThumbInfo* FindThumbByContact (HANDLE hContact); + +private: + static int cmp(const ThumbInfo *p1, const ThumbInfo *p2); +}; + +extern ThumbList thumbList; diff --git a/plugins/FloatingContacts/version.h b/plugins/FloatingContacts/version.h new file mode 100644 index 0000000000..2bc7b1cc21 --- /dev/null +++ b/plugins/FloatingContacts/version.h @@ -0,0 +1,29 @@ +#define BUILD_NUM 2 +#define BUILD_NUM_STR "2" +#define REVISION "$Revision: 1136 $" + +#define COREVERSION_NUM 1, 0, 2, +#define COREVERSION_NUM_STR "1, 0, 2" + +#define MINIMAL_COREVERSION 0, 6, 0, 0 +#define MINIMAL_COREVERSION_STR "0, 6, 0, 0" + +#ifdef UNICODE +#define UNICODE_AWARE_STR " (Unicode)" +#else +#define UNICODE_AWARE_STR " (Ansi)" +#endif + +#define FILE_VERSION COREVERSION_NUM BUILD_NUM +#define FILE_VERSION_STR COREVERSION_NUM_STR UNICODE_AWARE_STR " build " BUILD_NUM_STR " " REVISION + +#define PRODUCT_VERSION FILE_VERSION +#define PRODUCT_VERSION_STR FILE_VERSION_STR + +#define __PLUGIN_NAME "Floating Contacts" UNICODE_AWARE_STR +#define __FILENAME "FltContacts.dll" +#define __DESC "Floating Contacts plugin for Miranda" +#define __AUTHOR "Iavor Vajarov, Kosh&chka, Victor Pavlychko" +#define __AUTHOREMAIL "ell-6@ya.ru" +#define __AUTHORWEB "http://www.miranda-im.org/" +#define __COPYRIGHT " 2002-2004 I. Vajarov (ivajarov@code.bg), 2008 Kosh&chka, V. Pavlychko" diff --git a/plugins/FloatingContacts/version.rc b/plugins/FloatingContacts/version.rc new file mode 100644 index 0000000000..8214739c31 --- /dev/null +++ b/plugins/FloatingContacts/version.rc @@ -0,0 +1,36 @@ + +#include +#include "version.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION FILE_VERSION + PRODUCTVERSION PRODUCT_VERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Author", __AUTHOR + VALUE "FileDescription", __DESC + VALUE "FileVersion", FILE_VERSION_STR + VALUE "InternalName", __PLUGIN_NAME + VALUE "LegalCopyright", __COPYRIGHT + VALUE "OriginalFilename", __FILENAME + VALUE "ProductName", __PLUGIN_NAME + VALUE "ProductVersion", PRODUCT_VERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/plugins/Gender/commonheaders.h b/plugins/Gender/commonheaders.h new file mode 100644 index 0000000000..ef43423b66 --- /dev/null +++ b/plugins/Gender/commonheaders.h @@ -0,0 +1,63 @@ +/* + Show Contact Gender plugin for Miranda-IM (www.miranda-im.org) + (c) 2006-2011 by Thief + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + File name : $URL: http://svn.miranda.im/mainrepo/gender/trunk/commonheaders.h $ + Revision : $Rev: 1687 $ + Last change on : $Date: 2011-01-22 18:44:21 +0200 (Сб, 22 янв 2011) $ + Last change by : $Author: Thief $ + +*/ + +#ifndef COMMHEADERS_H +#define COMMHEADERS_H + +#include //needed by m_utils.h +#include // needed by m_icolib.h > r9256 + +#include +#include + +//Miranda API headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//Gender SDK +#include "m_gender.h" + +//Resources +#include "resource.h" + +//external SDK headers +#include "m_updater.h" +#include "m_metacontacts.h" +#include "m_extraicons.h" + +static const int DefaultSlot = EXTRA_ICON_ADV2; +#define MODULENAME "Gender" + +#endif //COMMHEADERS_H diff --git a/plugins/Gender/docs/gender-readme.txt b/plugins/Gender/docs/gender-readme.txt new file mode 100644 index 0000000000..9b61305da1 --- /dev/null +++ b/plugins/Gender/docs/gender-readme.txt @@ -0,0 +1,62 @@ +Gender plugin for Miranda IM (http://miranda-im.org) +Homepage: http://thief.miranda.im +Version: 0.0.2.1 (c) 2006-2011 Thief +Idea by nile, icons by a0x + +This plugin shows gender icon in contact list. Nothing more ;) + +Changes: + +v0.0.2.1 ++ 64bit build ++ internal unicode support +- removed old PLUGININFO support + +v0.0.2.0 ++ added support for extraicons service plugin + +v0.0.1.9 +* gender key is now written to "UserInfo" module instead of protocol (the key doesn't get deleted on info update) (ticket #32) ++ option to draw an icon when no gender info found (ticket #33) +* look up for gender key in "UserInfo" module and then in protocol +* other small fixes + +v0.0.1.8 +- some changes to icons handling, now Miranda 0.7 is required ++ added possibility to disable contact list icon +* fixed service function + +v0.0.1.7 +- version bump (to allow update from 0.0.1.6 previously released as beta) + +v0.0.1.6 ++ metacontacts support (thanks sje for clearing things out) ++ added a service for retrieving gender icon for a contact + +v0.0.1.5 +* changed icons - now using cute icons by a0x (thanks!) + +v0.0.1.4 ++ added uuid (FB1C17E0-77FC-45A7-9C8B-E2BEF4F56B28) and MIID_GENDER interface for Miranda 0.8.x compatibility +* make menu subitem checked when gender key is found + +v0.0.1.3 +! addons release +* hide menu items for chatrooms and non-IM protocols (like weather, etc) +* icons changes in icolib reflect menuitems icons ++ option to disable menu items + +v0.0.1.2 ++ plugin now checks "UserInfo" module if gender key was not found in protocol module (FR by BraVo123) +- MinGW build + +v0.0.1.1 ++ menuitems to set gender (FR by Shaggoth) ++ langpack and readme +Happy New Year! :) + +v0.0.1.0 +- initial release + +Plugin is released under GPL licence. +http://www.gnu.org/copyleft/gpl.html \ No newline at end of file diff --git a/plugins/Gender/docs/gender-translate.txt b/plugins/Gender/docs/gender-translate.txt new file mode 100644 index 0000000000..b2f31b9876 --- /dev/null +++ b/plugins/Gender/docs/gender-translate.txt @@ -0,0 +1,24 @@ +[Gender] +[Male] +[Female] +[Undefined] +[Set Gender] +[Set Male] +[Set Female] +[Set Undefined] +[Plugin settings] +[Use] +[slot to draw the icon] +[Email] +[Protocol] +[SMS] +[Advanced 1] +[Advanced 2] +[Web] +[Client] +[Advanced 3] +[Advanced 4] +[Advanced 5] +[Enable menu items] +[No info] +[Draw an icon when gender info not found] \ No newline at end of file diff --git a/plugins/Gender/gender.rc b/plugins/Gender/gender.rc new file mode 100644 index 0000000000..651f86bd36 --- /dev/null +++ b/plugins/Gender/gender.rc @@ -0,0 +1,129 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Ukrainian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_UKR) +#ifdef _WIN32 +LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MALE ICON "icons\\male.ico" +IDI_FEMALE ICON "icons\\female.ico" +IDI_UNDEF ICON "icons\\gender.ico" +#endif // Ukrainian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_GENDER_OPT DIALOGEX 0, 0, 314, 240 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + COMBOBOX IDC_ADVICON,95,102,78,81,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP,WS_EX_CLIENTEDGE + GROUPBOX "Plugin settings",IDC_STATIC,46,78,222,100 + RTEXT "Use",IDC_USE_L,56,104,33,12 + LTEXT "slot to draw the icon",IDC_SLOT_L,179,104,76,17 + CONTROL "Enable menu items",IDC_MENUITEMS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,76,122,167,12 + LTEXT "Note: if you still don't see the icons try changing icon slot. Perhaps its used by some other plugin.", + IDC_NOTE_L,53,152,200,18 + CONTROL "Draw an icon when gender info not found", + IDC_DRAWUNDEFICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 76,138,167,12 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_GENDER_OPT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 307 + TOPMARGIN, 7 + BOTTOMMARGIN, 233 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Gender/gender_10.sln b/plugins/Gender/gender_10.sln new file mode 100644 index 0000000000..238e9b5269 --- /dev/null +++ b/plugins/Gender/gender_10.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gender_10", "gender_10.vcxproj", "{9DF8913A-99A3-40D2-86FE-585EBDDCABB2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release Unicode|Win32 = Release Unicode|Win32 + Release Unicode|x64 = Release Unicode|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Debug|Win32.ActiveCfg = Debug|Win32 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Debug|Win32.Build.0 = Debug|Win32 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Debug|x64.ActiveCfg = Debug|x64 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Debug|x64.Build.0 = Debug|x64 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release Unicode|x64.ActiveCfg = Release Unicode|x64 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release Unicode|x64.Build.0 = Release Unicode|x64 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release|Win32.ActiveCfg = Release|Win32 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release|Win32.Build.0 = Release|Win32 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release|x64.ActiveCfg = Release|x64 + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/Gender/gender_10.vcxproj b/plugins/Gender/gender_10.vcxproj new file mode 100644 index 0000000000..cc02d4a65a --- /dev/null +++ b/plugins/Gender/gender_10.vcxproj @@ -0,0 +1,263 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release Unicode + Win32 + + + Release Unicode + x64 + + + Release + Win32 + + + Release + x64 + + + + {9DF8913A-99A3-40D2-86FE-585EBDDCABB2} + Win32Proj + gender + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + Unicode + + + DynamicLibrary + MultiByte + + + DynamicLibrary + Unicode + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + true + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + false + false + false + false + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;GENDER2_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + + + true + $(OutDir)gender2.pdb + Windows + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;GENDER2_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + + + true + $(OutDir)gender2.pdb + Windows + $(IntDir)$(TargetName).lib + $(OutDir)$(TargetName)$(TargetExt) + + + + + Full + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;GENDER2_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + Size + OnlyExplicitInline + true + + + false + Windows + true + true + MachineX86 + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + Full + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;GENDER2_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + Size + OnlyExplicitInline + true + + + false + Windows + true + true + MachineX86 + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + Full + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;GENDER2_EXPORTS; _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + OnlyExplicitInline + Size + true + + + $(OutDir)$(TargetName)$(TargetExt) + false + Windows + true + true + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + Full + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_USRDLL;GENDER2_EXPORTS; _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + OnlyExplicitInline + Size + true + + + $(OutDir)$(TargetName)$(TargetExt) + false + Windows + true + true + $(IntDir)$(TargetName).lib + UseLinkTimeCodeGeneration + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/Gender/icons/female.ico b/plugins/Gender/icons/female.ico new file mode 100644 index 0000000000..fe1cbd2bce Binary files /dev/null and b/plugins/Gender/icons/female.ico differ diff --git a/plugins/Gender/icons/gender.ico b/plugins/Gender/icons/gender.ico new file mode 100644 index 0000000000..930c34279c Binary files /dev/null and b/plugins/Gender/icons/gender.ico differ diff --git a/plugins/Gender/icons/male.ico b/plugins/Gender/icons/male.ico new file mode 100644 index 0000000000..ebd0420554 Binary files /dev/null and b/plugins/Gender/icons/male.ico differ diff --git a/plugins/Gender/main.cpp b/plugins/Gender/main.cpp new file mode 100644 index 0000000000..e66d3ef41b --- /dev/null +++ b/plugins/Gender/main.cpp @@ -0,0 +1,474 @@ +/* + Show Contact Gender plugin for Miranda-IM (www.miranda-im.org) + (c) 2006-2011 by Thief + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + File name : $URL: http://svn.miranda.im/mainrepo/gender/trunk/main.cpp $ + Revision : $Rev: 1688 $ + Last change on : $Date: 2011-01-22 19:44:43 +0200 (Сб, 22 янв 2011) $ + Last change by : $Author: Thief $ + +*/ + +#include "commonheaders.h" + +HINSTANCE g_hInst; +PLUGINLINK *pluginLink; +static HANDLE hHookModulesLoaded = NULL, hSystemOKToExit = NULL, hOptInitialise = NULL, hIcoLibIconsChanged = NULL; +static HANDLE hHookExtraIconsRebuild = NULL, hHookExtraIconsApply = NULL, hContactMenu = NULL; +static HANDLE hContactMenuMale = NULL, hContactMenuFemale = NULL, hContactMenuNotDef = NULL, hHookPrebuildContactMenu = NULL; +static HANDLE hSetMale = NULL, hSetFemale = NULL, hSetUndef = NULL, hGenderGetIcon = NULL; + +HANDLE g_hExtraIcon = NULL; +HANDLE g_hIconMale, g_hIconFemale, g_hIconMenu; +IconExtraColumn g_IECMale = {0}; +IconExtraColumn g_IECFemale = {0}; +IconExtraColumn g_IECUndef = {0}; +IconExtraColumn g_IECClear = {0}; + +int clistIcon = 0; // Icon slot to use +byte bEnableClistIcon = 1; // do we need clist icon? +byte bDrawNoGenderIcon = 0; // enable icon when no info? +byte bContactMenuItems = 1; // do we need a contact menu items? +byte bMetaAvail = 0; // metacontacts installed? + +extern int onOptInitialise(WPARAM wParam, LPARAM lParam); + +PLUGININFOEX pluginInfo={ +sizeof(PLUGININFOEX), +#ifdef WIN64 + "Show Contact Gender (x64)", +#else + "Show Contact Gender", +#endif + PLUGIN_MAKE_VERSION(0,0,2,1), + "Shows contacts gender as an icon in contact list", + "Thief, idea by nile, icons by a0x", + "thief@miranda.im", + "2006-2011 Alexander Turyak", + "http://thief.miranda.im/", + UNICODE_AWARE, + 0, //doesn't replace anything built-in +#ifdef WIN64 + { 0x3a99592e, 0x20d5, 0x4b72, { 0xa5, 0x96, 0xe6, 0x7d, 0xd7, 0x13, 0xde, 0xfb } } // {3A99592E-20D5-4B72-A596-E67DD713DEFB} +#else + {0xfb1c17e0, 0x77fc, 0x45a7, {0x9c, 0x8b, 0xe2, 0xbe, 0xf4, 0xf5, 0x6b, 0x28}} /* FB1C17E0-77FC-45A7-9C8B-E2BEF4F56B28 */ +#endif +}; + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + g_hInst = hinstDLL; + return TRUE; +} + +/* 0FF3991A-5505-479D-A2E0-53DD31C6DFA7 */ +#define MIID_GENDER {0x0ff3991a, 0x5505, 0x479d, {0xa2, 0xe0, 0x53, 0xdd, 0x31, 0xc6, 0xdf, 0xa7}} + +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + static const MUUID interfaces[] = {MIID_GENDER, MIID_LAST}; + return interfaces; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +void setIcon(HANDLE hContact, unsigned int gender) +{ + if (g_hExtraIcon != NULL) + { + char *ico; + switch (gender) + { + case 77: ico = "male_icon"; break; + case 70: ico = "female_icon"; break; + default: ico = (bDrawNoGenderIcon ? "menu_icon" : NULL); break; + } + ExtraIcon_SetIcon(g_hExtraIcon, hContact, ico); + } + else + { + IconExtraColumn *col; + switch (gender) + { + case 77: col = &g_IECMale; break; + case 70: col = &g_IECFemale; break; + default: col = (bDrawNoGenderIcon ? &g_IECUndef : &g_IECClear); break; + } + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)col); + } +} + +int onExtraImageApplying(WPARAM wParam, LPARAM lParam) +{ + if (g_hExtraIcon == NULL && !bEnableClistIcon) return 0; + + HANDLE hContact = (HANDLE)wParam; + if (bMetaAvail) + { + HANDLE hMetacontact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, wParam, 0); + if (hMetacontact != NULL) hContact = hMetacontact; + } + + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + if (!proto) return 0; + + if (DBGetContactSettingByte((HANDLE)wParam, proto, "ChatRoom", 0)) return 0; + + unsigned int gender = DBGetContactSettingByte(hContact, "UserInfo", "Gender", DBGetContactSettingByte(hContact, proto, "Gender", 0)); + + setIcon(hContact, gender); + if ((HANDLE)wParam != hContact) + setIcon((HANDLE)wParam, gender); + + return 0; +} + +int onExtraImageListRebuild(WPARAM wParam, LPARAM lParam) +{ + g_IECMale.cbSize = sizeof(IconExtraColumn); + g_IECMale.ColumnType = clistIcon; + g_IECFemale.cbSize = sizeof(IconExtraColumn); + g_IECFemale.ColumnType = clistIcon; + g_IECUndef.cbSize = sizeof(IconExtraColumn); + g_IECUndef.ColumnType = clistIcon; + + if (ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) + { + if(hIcoLibIconsChanged) + { + g_IECMale.hImage = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)g_hIconMale), (LPARAM)0); + g_IECFemale.hImage = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)g_hIconFemale), (LPARAM)0); + g_IECUndef.hImage = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)g_hIconMenu), (LPARAM)0); + } + } + + return 0; +} + +// Returns gender icon for specific contact +INT_PTR GetIcon(WPARAM wParam, LPARAM lParam) +{ + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + unsigned short gender = DBGetContactSettingByte((HANDLE)wParam, "UserInfo", "Gender", DBGetContactSettingByte((HANDLE)wParam, proto, "Gender", 0)); + + if (gender > 0) + { + if (gender == 77) return CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)g_hIconMale); + else if (gender == 70) return CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)g_hIconFemale); + } + + return 0; +} + +int onPrebuildContactMenu(WPARAM wParam, LPARAM lParam) +{ + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + + if (!proto) return 0; + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(CLISTMENUITEM); + + + if (DBGetContactSettingByte((HANDLE)wParam, proto, "ChatRoom", 0) || !(CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)) + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + else + mi.flags = CMIM_FLAGS; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenu, (LPARAM)&mi); + + unsigned short gender = DBGetContactSettingByte((HANDLE)wParam, proto, "Gender", DBGetContactSettingByte((HANDLE)wParam, "UserInfo", "Gender", 0)); + + CLISTMENUITEM mitem = {0}; + mitem.cbSize = sizeof(CLISTMENUITEM); + mitem.flags = CMIM_FLAGS; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuMale, (LPARAM)&mitem); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuFemale, (LPARAM)&mitem); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuNotDef, (LPARAM)&mitem); + + mitem.flags = CMIM_FLAGS | CMIF_CHECKED; + + switch (gender) + { + case 77: + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuMale, (LPARAM)&mitem); + break; + case 70: + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuFemale, (LPARAM)&mitem); + break; + case 0: + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuNotDef, (LPARAM)&mitem); + break; + } + + return 0; +} + +void setGender(HANDLE hContact, unsigned int gender) +{ + DBWriteContactSettingByte(hContact, "UserInfo", "Gender", gender); + setIcon(hContact, gender); + + int metasnum = (bMetaAvail ? CallService(MS_MC_GETNUMCONTACTS,(WPARAM)hContact,0) : 0); + for(int i=0; iidFrom == 0) + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + HANDLE hContact; + + bDrawNoGenderIcon = IsDlgButtonChecked(hwndDlg, IDC_DRAWUNDEFICON); + + if (g_hExtraIcon == NULL) + { + clistIcon = SendMessage(GetDlgItem(hwndDlg, IDC_ADVICON), CB_GETCURSEL, 0, 0); + DBWriteContactSettingByte(NULL, MODULENAME, "AdvancedIcon", clistIcon); + + if (bEnableClistIcon) + { + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&g_IECClear); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + } + + bEnableClistIcon = (clistIcon != 0); + + if (bEnableClistIcon) + { + g_IECClear.ColumnType = clistIcon; + onExtraImageListRebuild(0,0); + } + } + + if (g_hExtraIcon != NULL || bEnableClistIcon) + { + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + onExtraImageApplying((WPARAM)hContact,0); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + } + + DBWriteContactSettingByte(NULL, MODULENAME, "ClistIcon", bEnableClistIcon); + DBWriteContactSettingByte(NULL, MODULENAME, "NoGenderIcon", bDrawNoGenderIcon); + DBWriteContactSettingByte(NULL, MODULENAME, "MenuItems", IsDlgButtonChecked(hwndDlg, IDC_MENUITEMS)); + } + return TRUE; + } + } + + case WM_DESTROY: + break; + } + return FALSE; +} + +int onOptInitialise(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = 0; + odp.hInstance = g_hInst; + odp.ptszGroup = LPGENT("Plugins"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_GENDER_OPT); + odp.ptszTitle = LPGENT("Gender"); + odp.pfnDlgProc = DlgProcOptions; + odp.flags = ODPF_BOLDGROUPS|ODPF_TCHAR; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp); + + return 0; +} diff --git a/plugins/Gender/resource.h b/plugins/Gender/resource.h new file mode 100644 index 0000000000..8ea2786991 --- /dev/null +++ b/plugins/Gender/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by gender.rc +// +#define IDD_GENDER_OPT 9 +#define IDI_MALE 101 +#define IDI_FEMALE 102 +#define IDI_UNDEF 103 +#define IDC_ADVICON 1001 +#define IDC_MENUITEMS 1002 +#define IDC_DRAWUNDEFICON 1003 +#define IDC_USE_L 1004 +#define IDC_SLOT_L 1005 +#define IDC_NOTE_L 1006 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/ProfileManager/pmanagerEx.c b/plugins/ProfileManager/pmanagerEx.c new file mode 100644 index 0000000000..63f57f5bea --- /dev/null +++ b/plugins/ProfileManager/pmanagerEx.c @@ -0,0 +1,109 @@ +/* +Miranda plugin template, originally by Richard Hughes +http://miranda-icq.sourceforge.net/ + +This file is placed in the public domain. Anybody is free to use or +modify it as they wish with no restriction. +There is no warranty. +*/ +#include +#include +#include +#include +#include +#include +#include "resource.h" + + +HINSTANCE hInst; +PLUGINLINK *pluginLink; +TCHAR fn[MAX_PATH]; +TCHAR lmn[MAX_PATH]; +TCHAR* pathn; + +#define SIZEOF(x) (sizeof(x)/sizeof(*x)) + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + "Miranda IM Profile Changer", + PLUGIN_MAKE_VERSION(0,0,0,3), + "Adds a menu item to change or load a different profile of Miranda IM.", + "Roman Gemini", + "woobind@ukr.net", + " 2008 - 2010 Roman Gemini", + "http://code.google.com/p/alfamar/", + 0, //not transient + 0, //doesn't replace anything built-in + // Generate your own unique id for your plugin. + // Do not use this UUID! + // Use uuidgen.exe to generate the uuuid + {0x7eeeb55e, 0x9d83, 0x4e1a, { 0xa1, 0x2f, 0x8f, 0x13, 0xf1, 0xa1, 0x24, 0xfb } } + +}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst=hinstDLL; + return TRUE; +} + +static int ChangePM(WPARAM wParam,LPARAM lParam) +{ + GetModuleFileName(GetModuleHandle(NULL), fn, SIZEOF(fn)); + ShellExecute(0, "open", fn, "/FORCESHOW", "", 1); + CallService("CloseAction", 0, 0); + return 0; +} + +static int LoadPM(WPARAM wParam,LPARAM lParam) +{ + GetModuleFileName(GetModuleHandle(NULL), fn, SIZEOF(fn)); + ShellExecute(0, "open", fn, "/FORCESHOW", "", 1); + return 0; +} + + +__declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +static const MUUID interfaces[] = {MIID_TESTPLUGIN, MIID_LAST}; +__declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +int __declspec(dllexport) Load(PLUGINLINK *link) +{ + CLISTMENUITEM mi; + pluginLink=link; + + CreateServiceFunction("Database/LoadPM",LoadPM); + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize=sizeof(mi); + mi.position=-500200000; + mi.flags=0; + mi.hIcon=LoadIcon(hInst, MAKEINTRESOURCE(IDI_LoadPM)); + mi.pszPopupName = "Database"; + mi.pszName=LPGEN("Load profile"); + mi.pszService="Database/LoadPM"; + CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + CreateServiceFunction("Database/ChangePM",ChangePM); + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize=sizeof(mi); + mi.position=-500200000; + mi.flags=0; + mi.hIcon=LoadIcon(hInst, MAKEINTRESOURCE(IDI_ChangePM)); + mi.pszPopupName = "Database"; + mi.pszName=LPGEN("Change profile"); + mi.pszService="Database/ChangePM"; + CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + return 0; +} + +int __declspec(dllexport) Unload(void) +{ + return 0; +} \ No newline at end of file diff --git a/plugins/ProfileManager/pmanagerEx.vcproj b/plugins/ProfileManager/pmanagerEx.vcproj new file mode 100644 index 0000000000..4c5613bdec --- /dev/null +++ b/plugins/ProfileManager/pmanagerEx.vcproj @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/ProfileManager/res/ChangePM.ico b/plugins/ProfileManager/res/ChangePM.ico new file mode 100644 index 0000000000..89b5d08f0f Binary files /dev/null and b/plugins/ProfileManager/res/ChangePM.ico differ diff --git a/plugins/ProfileManager/res/LoadPM.ico b/plugins/ProfileManager/res/LoadPM.ico new file mode 100644 index 0000000000..ec298dea37 Binary files /dev/null and b/plugins/ProfileManager/res/LoadPM.ico differ diff --git a/plugins/ProfileManager/resource.h b/plugins/ProfileManager/resource.h new file mode 100644 index 0000000000..638fcfb4f6 --- /dev/null +++ b/plugins/ProfileManager/resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDI_ChangePM 101 +#define IDI_LoadPM 102 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/ProfileManager/resource.rc b/plugins/ProfileManager/resource.rc new file mode 100644 index 0000000000..92a42063c4 --- /dev/null +++ b/plugins/ProfileManager/resource.rc @@ -0,0 +1,46 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1250) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ChangePM ICON "res/ChangePM.ico" +IDI_LoadPM ICON "res/LoadPM.ico" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Rate/commonheaders.h b/plugins/Rate/commonheaders.h new file mode 100644 index 0000000000..34aeb65dff --- /dev/null +++ b/plugins/Rate/commonheaders.h @@ -0,0 +1,78 @@ +/* + Authorization State plugin for Miranda-IM (www.miranda-im.org) + (c) 2006 by Thief + Icons by Faith Healer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + File name : $URL: http://svn.mirandaim.ru/mainrepo/authstate/trunk/commonheaders.h $ + Revision : $Rev: 222 $ + Last change on : $Date: 2006-09-26 05:54:03 +0700 (Вт, 26 сен 2006) $ + Last change by : $Author: Thief $ + +*/ + +#ifndef COMMHEADERS_H +#define COMMHEADERS_H + +//#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +//needed by m_utils.h +#include + +// needed by m_icolib.h > r9256 +#include + +//Miranda API headers +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include "resource.h" + +//external SDK headers +#include +#include +#include + +static const int DefaultSlot = EXTRA_ICON_PROTO; +#define MODULENAME "Rate" + +/* 0e2866a8-6f4c-4132-98ae-6afdb8766c48 */ +#define MIID_CONTACTSRATE {0x0e2866a8, 0x6f4c, 0x4132, {0x98, 0xae, 0x6a, 0xfd, 0xb8, 0x76, 0x6c, 0x48}} + +static struct +{ + char* szDescr; + char* szName; + int defIconID; + HANDLE hIconLibItem; +} iconList[] = +{ + { LPGEN( "Rate high" ), "rate_high", IDI_RATEHI }, + { LPGEN( "Rate medium" ), "rate_medium", IDI_RATEME }, + { LPGEN( "Rate low" ), "rate_low", IDI_RATELO }, +}; + + + +#endif //COMMHEADERS_H diff --git a/plugins/Rate/docs/Rate-readme.txt b/plugins/Rate/docs/Rate-readme.txt new file mode 100644 index 0000000000..aafc63f812 --- /dev/null +++ b/plugins/Rate/docs/Rate-readme.txt @@ -0,0 +1,49 @@ +Contacts Rate plugin for Miranda IM (http://miranda-im.org) +Version: 0.0.2.1 (c) 2007-2009 Kildor +Icons by Faith Healer + +This small plugin intended to show an icon in front of contacts which have +non-empty rating at Modern Contact List. + +http://svn.miranda.im/mainrepo/contacts_rate/trunk/ - plugin`s SVN + +I would like to say thanks to: +Faith Healer for icons +Thief for his Authstate plugin that was base for this plugin. +FYR for his clist_modern + + +Changes: + +v0.0.2.1 +- Translation fixes. + +v0.0.2.0 +- ExtraIcons plugin support (big thanks to Pescuma for patch) + +v0.0.1.5 +- fixes typos and bugs +- add support for clist_nicer and clist_mw, and handling of clist_classic + +v0.0.1.4 +- Fix for new m_cluiframes.h (need to be checked with clist_nicer) + +v0.0.1.3 +- More clean-up. + +v0.0.1.2 +- clean-up. + +v0.0.1.1 +- fix for new pluginapi +- copyrights update +- small clean-up + +v0.0.1.0 +- public release + +v0.0.0.x +- test versions, unreleased + +Plugin is released under GPL licence. +http://www.gnu.org/copyleft/gpl.html diff --git a/plugins/Rate/docs/rate.txt b/plugins/Rate/docs/rate.txt new file mode 100644 index 0000000000..e743807a44 --- /dev/null +++ b/plugins/Rate/docs/rate.txt @@ -0,0 +1 @@ +Rate 0.0.2.1 \ No newline at end of file diff --git a/plugins/Rate/icons/rate_high.ico b/plugins/Rate/icons/rate_high.ico new file mode 100644 index 0000000000..ad5fa6acf1 Binary files /dev/null and b/plugins/Rate/icons/rate_high.ico differ diff --git a/plugins/Rate/icons/rate_low.ico b/plugins/Rate/icons/rate_low.ico new file mode 100644 index 0000000000..66a340da9c Binary files /dev/null and b/plugins/Rate/icons/rate_low.ico differ diff --git a/plugins/Rate/icons/rate_med.ico b/plugins/Rate/icons/rate_med.ico new file mode 100644 index 0000000000..2b3220de1b Binary files /dev/null and b/plugins/Rate/icons/rate_med.ico differ diff --git a/plugins/Rate/main.cpp b/plugins/Rate/main.cpp new file mode 100644 index 0000000000..9810378eca --- /dev/null +++ b/plugins/Rate/main.cpp @@ -0,0 +1,289 @@ +/*==========================================================================*/ +/* + FILE DESCRIPTION: Rate main + + AUTHOR: Kildor + GROUP: The NULL workgroup + PROJECT: Contact`s rate + PART: Main + VERSION: 1.0 + CREATED: 20.12.2006 23:11:41 + + EMAIL: kostia@ngs.ru + WWW: http://kildor.miranda.im + + COPYRIGHT: (C) 2006 The NULL workgroup. All Rights Reserved. +*/ +/*--------------------------------------------------------------------------*/ +/* + Copyright (C) 2006 The NULL workgroup + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*--------------------------------------------------------------------------*/ +/* + FILE ID: $Id$ + + CHANGE LOG: + + $Log$ +*/ +#include "commonheaders.h" + +HINSTANCE g_hInst; +PLUGINLINK *pluginLink; +static HANDLE hHookModulesLoaded = NULL, hSystemOKToExit = NULL, hOptInitialise = NULL, hIcoLibIconsChanged = NULL; +static HANDLE hHookExtraIconsRebuild = NULL, hHookExtraIconsApply = NULL, hContactSettingChanged = NULL; +static HANDLE hPrebuildContactMenu = NULL; +static HANDLE hExtraIcon = NULL; +IconExtraColumn g_IECRateHigh = {0}; +IconExtraColumn g_IECRateMedium = {0}; +IconExtraColumn g_IECRateLow = {0}; +IconExtraColumn g_IECClear = {0}; +int clistIcon = 0; //Icon slot to use +byte bRate = 0; + +extern int onOptInitialise(WPARAM wParam, LPARAM lParam); + + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + "Contact`s Rate", + PLUGIN_MAKE_VERSION(0,0,2,1), + "Show rating of contact in contact list (if presents).", + "Kildor, Thief", + "kostia@ngs.ru", + " 2006-2009 Kostia Romanov, based on AuthState by Alexander Turyak", + "http://kildor.miranda.im/", + 0, // is not unicode + 0, //doesn't replace anything built-in + {0x45230488, 0x977b, 0x405b, {0x85, 0x6d, 0xea, 0x27, 0x6d, 0x70, 0x83, 0xb7}} +/* 45230488-977b-405b-856d-ea276d7083b7 */ + +}; + +extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + g_hInst = hinstDLL; + return TRUE; +} + +// +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 8, 0, 29)) + { + MessageBox( NULL, TranslateT("The plugin requires Miranda IM 0.8.0.29 or later for correct applying its preferences."), TranslateT("Contact` Rate"), + MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST ); + } + + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + static const MUUID interfaces[] = {MIID_CONTACTSRATE, MIID_LAST}; + return interfaces; +} + +int onSystemOKToExit(WPARAM wParam,LPARAM lParam) +{ + UnhookEvent(hHookModulesLoaded); + UnhookEvent(hHookExtraIconsRebuild); + UnhookEvent(hHookExtraIconsApply); + UnhookEvent(hOptInitialise); + UnhookEvent(hSystemOKToExit); + if (hIcoLibIconsChanged) UnhookEvent(hIcoLibIconsChanged); + if (hContactSettingChanged) + UnhookEvent(hContactSettingChanged); + + return 0; +} + +void setExtaIcon(HANDLE hContact, int bRate = -1, BOOL clear = TRUE) +{ + if (hContact == NULL) + return; + + if (bRate < 0) + bRate = DBGetContactSettingByte(hContact, "CList", "Rate", 0); + + if (hExtraIcon != NULL) + { + const char *icon; + switch(bRate) + { + case 3: icon = "rate_high"; break; + case 2: icon = "rate_medium"; break; + case 1: icon = "rate_low"; break; + default: icon = NULL; break; + } + + if (icon == NULL && !clear) + return; + + ExtraIcon_SetIcon(hExtraIcon, hContact, icon); + } + else + { + switch(bRate) + { + case 3: CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM) hContact, (LPARAM) &g_IECRateHigh); break; + case 2: CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM) hContact, (LPARAM) &g_IECRateMedium); break; + case 1: CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM) hContact, (LPARAM) &g_IECRateLow); break; + default: CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM) hContact, (LPARAM) &g_IECClear); break; + } + } +} + + +int onExtraImageApplying(WPARAM wParam, LPARAM lParam) +{ + setExtaIcon((HANDLE) wParam); + return 0; +} + + +int onExtraImageListRebuild(WPARAM wParam, LPARAM lParam) +{ + g_IECRateHigh.cbSize = sizeof(IconExtraColumn); + g_IECRateHigh.ColumnType = clistIcon; + g_IECRateMedium.cbSize = sizeof(IconExtraColumn); + g_IECRateMedium.ColumnType = clistIcon; + g_IECRateLow.cbSize = sizeof(IconExtraColumn); + g_IECRateLow.ColumnType = clistIcon; + + if (ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) + { + g_IECRateHigh.hImage = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)(HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM)"rate_high"), (LPARAM)0); + g_IECRateMedium.hImage = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)(HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM)"rate_medium"), (LPARAM)0); + g_IECRateLow.hImage = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)(HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM)"rate_low"), (LPARAM)0); + } + return 0; +} + + +static void init_icolib (void) +{ + SKINICONDESC sid = {0}; + char szFile[MAX_PATH]; + sid.cbSize = SKINICONDESC_SIZE_V1; + int i = 0; + + sid.pszSection = Translate("Contact Rate"); + GetModuleFileNameA(g_hInst, szFile, MAX_PATH); + sid.pszDefaultFile = szFile; + + for ( i = 0; i < SIZEOF(iconList); i++ ) { + sid.pszName = iconList[i].szName; + sid.ptszDescription = iconList[i].szDescr; + sid.iDefaultIndex = -iconList[i].defIconID; + iconList[i].hIconLibItem = (HANDLE) CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } +} + + +int onModulesLoaded(WPARAM wParam,LPARAM lParam) +{ + //IcoLib support + init_icolib(); + + + // Updater support + // switch off + if ( ServiceExists(MS_UPDATE_REGISTER)) + { + Update update = {0}; + char szVersion[16]; + + update.cbSize = sizeof(Update); + + update.szComponentName = pluginInfo.shortName; + update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion); + update.cpbVersion = (int)strlen((char *)update.pbVersion); + + update.szUpdateURL = UPDATER_AUTOREGISTER; + + // these are the three lines that matter - the archive, the page containing the version string, and the text (or data) + // before the version that we use to locate it on the page + // (note that if the update URL and the version URL point to standard file listing entries, the backend xml + // data will be used to check for updates rather than the actual web page - this is not true for beta urls) + update.szBetaUpdateURL = "http://kildor.miranda.im/miranda/rate.zip"; + update.szBetaVersionURL = "http://kildor.miranda.im/miranda/rate.txt"; + update.szBetaChangelogURL = "http://kildor.miranda.im/miranda/rate_changes.txt"; + update.pbBetaVersionPrefix = (BYTE *)"Rate "; + update.cpbBetaVersionPrefix = (int)strlen((char *)update.pbBetaVersionPrefix); + + CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); + } + + // Extra icon support + hExtraIcon = ExtraIcon_Register("contact_rate", "Contact rate", "rate_high"); + + if (hExtraIcon != NULL) + { + // Set initial value for all contacts + HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact != NULL) + { + setExtaIcon(hContact, -1, FALSE); + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } + } + else + { + hOptInitialise = HookEvent(ME_OPT_INITIALISE, onOptInitialise); + hIcoLibIconsChanged = HookEvent(ME_SKIN2_ICONSCHANGED, onExtraImageListRebuild); + hHookExtraIconsRebuild = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, onExtraImageListRebuild); + hHookExtraIconsApply = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, onExtraImageApplying); + onExtraImageListRebuild(0,0); + } + + return 0; +} + + +int onContactSettingChanged(WPARAM wParam,LPARAM lParam) +{ + DBCONTACTWRITESETTING *cws=(DBCONTACTWRITESETTING*)lParam; + + if (wParam != NULL && !lstrcmp(cws->szModule,"CList") && !lstrcmp(cws->szSetting,"Rate")) + setExtaIcon((HANDLE)wParam, cws->value.type == DBVT_DELETED ? 0 : cws->value.bVal); + + return 0; +} + + +extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) +{ + pluginLink=link; + + hHookModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, onModulesLoaded); + hSystemOKToExit = HookEvent(ME_SYSTEM_OKTOEXIT,onSystemOKToExit); + hContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, onContactSettingChanged); + + clistIcon = DBGetContactSettingByte(NULL, MODULENAME, "AdvancedIcon", DefaultSlot); + + g_IECClear.cbSize = sizeof(IconExtraColumn); + g_IECClear.ColumnType = clistIcon; + g_IECClear.hImage = (HANDLE) -1; + + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + return 0; +} diff --git a/plugins/Rate/options.cpp b/plugins/Rate/options.cpp new file mode 100644 index 0000000000..47714d6828 --- /dev/null +++ b/plugins/Rate/options.cpp @@ -0,0 +1,224 @@ +/* + Authorization State plugin for Miranda-IM (www.miranda-im.org) + (c) 2006 by Thief + Icons by Faith Healer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + File name : $URL: svn://svnsrv.mirandaim.ru/mainrepo/authstate/trunk/options.cpp $ + Revision : $Rev: 233 $ + Last change on : $Date: 2006-10-05 15:48:05 +0300 (Thu, 05 Oct 2006) $ + Last change by : $Author: Thief $ + +*/ + +#include "commonheaders.h" + +extern HINSTANCE g_hInst; +extern int onExtraImageApplying(WPARAM wParam, LPARAM lParam); +extern int onExtraImageListRebuild(WPARAM wParam, LPARAM lParam); +extern IconExtraColumn g_IECAuth, g_IECGrant, g_IECAuthGrant, g_IECClear; +extern int clistIcon; +//extern byte bUseAuthIcon, bUseGrantIcon, bContactMenuItem, bIconsForRecentContacts; + +//#define EXTRA_ICON_RES0 0 // only used by nicer +//#define EXTRA_ICON_EMAIL 1 +//#define EXTRA_ICON_WEB 2 +//#define EXTRA_ICON_SMS 3 +//#define EXTRA_ICON_ADV1 4 +//#define EXTRA_ICON_ADV2 5 +//#define EXTRA_ICON_ADV3 6 +//#define EXTRA_ICON_CLIENT 7 +//#define EXTRA_ICON_ADV4 8 +//#define EXTRA_ICON_RES1 9 // only used by nicer +//#define EXTRA_ICON_PROTO 9 // used by mwclist and modern +//#define EXTRA_ICON_RES2 10 // only used by nicer +//#define EXTRA_ICON_VISMODE 10 // only used by modern + +#define MS_SKINENG_DRAWICONEXFIX "SkinEngine/DrawIconEx_Fix" + +enum { + clist_none, + clist_modern, + clist_nicer +}; + +const char *szAdvancedIconsModern[] = { + "E-mail", + "Web page", + "Phone/SMS", + "Advanced #1", + "Advanced #2", + "Advanced #3", + "Client", + "Advanced #4", + "Protocol", + "Visibility/Chat activity" +}; +//const int cAdvancedIconsModern = sizeof(szAdvancedIconsModern) / sizeof(szAdvancedIconsModern[0]); + +const char *szAdvancedIconsNicer[] = { + "Reserved", + "E-mail", + "Homepage", + "Telephone", + "Advanced #1", + "Advanced #2", + "Client", + "Advanced #3", + "Advanced #4", + "Reserved #1", + "Reserved #2" + }; +//const int cAdvancedIconsNicer = sizeof(szAdvancedIconsNicer) / sizeof(szAdvancedIconsNicer[0]); + +INT_PTR CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static int bInitializing = 0; + static int usedClist = clist_none; + int cAdvancedIcons; +// const char **szAdvancedIcons; + + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + bInitializing = 1; + if (ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) + { + if (ServiceExists(MS_SKINENG_DRAWICONEXFIX)) + { // modern? +// SendDlgItemMessage(hwndDlg,IDC_USED_CLIST, WM_SETTEXT,0,(LPARAM)_T("Your clist: modern")); + cAdvancedIcons = SIZEOF(szAdvancedIconsModern); + usedClist = clist_modern; + } + else + { + if (ServiceExists("CLN/About")) + { + usedClist = clist_nicer; +// szAdvancedIcons = szAdvancedIconsNicer; + cAdvancedIcons = SIZEOF(szAdvancedIconsNicer); + SendDlgItemMessage(hwndDlg,IDC_USED_CLIST, WM_SETTEXT,0,(LPARAM)TranslateT("Your clist: nicer")); + } + else + { + usedClist = clist_modern; + cAdvancedIcons = SIZEOF(szAdvancedIconsModern) - 1; // mw doesn`t have last modern extraicon +// SendDlgItemMessage(hwndDlg,IDC_USED_CLIST, WM_SETTEXT,0,(LPARAM)_T("Your clist: mw")); + } + SendDlgItemMessage(hwndDlg,IDC_NOTMODERN_WARNING, WM_SETTEXT,0,(LPARAM)TranslateT("Warning: your contact list plugin doesn`t have ability to sort contacts by rate.")); + ShowWindow(GetDlgItem(hwndDlg, IDC_NOTMODERN_WARNING), SW_SHOW); + } + } + else + { + cAdvancedIcons = 0; +// SendDlgItemMessage(hwndDlg,IDC_USED_CLIST, WM_SETTEXT,0,(LPARAM)_T("Your clist: classic")); + SendDlgItemMessage(hwndDlg,IDC_NOTMODERN_WARNING, WM_SETTEXT,0,(LPARAM)TranslateT("Warning: classic contact list plugin doesn`t have ability to use extraicons")); + ShowWindow(GetDlgItem(hwndDlg, IDC_NOTMODERN_WARNING), SW_SHOW); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADVICON), 0); + } +// cAdvancedIcons = sizeof(szAdvancedIcons) / sizeof(szAdvancedIcons[0]); +// cAdvancedIcons = SIZEOF(szAdvancedIcons); + + if (usedClist != clist_none) { + for (int i = 0; i < cAdvancedIcons; i++) + { + SendMessage(GetDlgItem(hwndDlg, IDC_ADVICON), CB_ADDSTRING, 0, (LPARAM) Translate( usedClist==clist_modern ? szAdvancedIconsModern[i] : szAdvancedIconsNicer[i])); + } + + if (usedClist == clist_modern ) + SendMessage(GetDlgItem(hwndDlg, IDC_ADVICON), CB_SETCURSEL, clistIcon-1, 0); + else + SendMessage(GetDlgItem(hwndDlg, IDC_ADVICON), CB_SETCURSEL, clistIcon, 0); + } + bInitializing = 0; + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) { + case IDC_ADVICON: + { + if ((HIWORD(wParam) == EN_CHANGE) && (!bInitializing) || (HIWORD(wParam) == CBN_SELENDOK)) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + } + } + break; + } + case WM_NOTIFY: + { + if (((LPNMHDR)lParam)->idFrom == 0) + { + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + if (usedClist==clist_none) + return TRUE; + + clistIcon = SendMessage(GetDlgItem(hwndDlg, IDC_ADVICON), CB_GETCURSEL, 0, 0); + if (usedClist == clist_modern ) + clistIcon++; + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&g_IECClear); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + g_IECClear.ColumnType = clistIcon; + onExtraImageListRebuild(0,0); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + onExtraImageApplying((WPARAM)hContact,0); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } + //Store options values to DB + DBWriteContactSettingByte(NULL, MODULENAME, "AdvancedIcon", clistIcon); + } + return TRUE; + } + } + } + case WM_DESTROY: + break; + } + return FALSE; +} + +int onOptInitialise(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = 0; + odp.hInstance = g_hInst; + odp.pszGroup = Translate("Contact List"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_RATE_OPT); + odp.pszTitle = Translate("Rate"); + odp.pfnDlgProc = DlgProcOptions; + odp.flags = ODPF_BOLDGROUPS; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) &odp); + + return 0; +} diff --git a/plugins/Rate/rate.rc b/plugins/Rate/rate.rc new file mode 100644 index 0000000000..e1a75b6808 --- /dev/null +++ b/plugins/Rate/rate.rc @@ -0,0 +1,124 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Ukrainian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_UKR) +#ifdef _WIN32 +LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_RATEHI ICON "icons\\rate_high.ico" +IDI_RATELO ICON "icons\\rate_low.ico" +IDI_RATEME ICON "icons\\rate_med.ico" +#endif // Ukrainian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_RATE_OPT DIALOGEX 0, 0, 314, 240 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + COMBOBOX IDC_ADVICON,95,102,78,81,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP,WS_EX_CLIENTEDGE + GROUPBOX "Plugin settings",IDC_STATIC,46,46,222,118 + RTEXT "Use",IDC_STATIC,56,104,33,12 + LTEXT "slot to draw the icon",IDC_STATIC,179,104,76,17 + LTEXT "Warning: classic contact list plugin doesn`t have ability to use extraicons", + IDC_NOTMODERN_WARNING,77,126,171,18,NOT WS_VISIBLE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_RATE_OPT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 307 + TOPMARGIN, 7 + BOTTOMMARGIN, 233 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Rate/rate_10.sln b/plugins/Rate/rate_10.sln new file mode 100644 index 0000000000..765fedbeef --- /dev/null +++ b/plugins/Rate/rate_10.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rate", "rate_10.vcxproj", "{DB315D7D-00BB-43B2-93A6-0430CA2B9F28}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Debug|Win32.ActiveCfg = Debug|Win32 + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Debug|Win32.Build.0 = Debug|Win32 + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Debug|x64.ActiveCfg = Debug|x64 + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Debug|x64.Build.0 = Debug|x64 + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Release|Win32.ActiveCfg = Release|Win32 + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Release|Win32.Build.0 = Release|Win32 + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Release|x64.ActiveCfg = Release|x64 + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/Rate/rate_10.vcxproj b/plugins/Rate/rate_10.vcxproj new file mode 100644 index 0000000000..aa8e74a341 --- /dev/null +++ b/plugins/Rate/rate_10.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {DB315D7D-00BB-43B2-93A6-0430CA2B9F28} + Win32Proj + rate + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + true + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + + + + Disabled + ../../include;../ExternalApi;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;AUTHSTATE_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + true + Windows + 0x22620000 + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Disabled + ../../include;../ExternalApi;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;AUTHSTATE_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + true + Windows + 0x22620000 + $(IntDir)$(TargetName).lib + + + + + Full + ../../include;../ExternalApi;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;AUTHSTATE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + Size + + + NotSet + true + Windows + true + true + 0x22620000 + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Full + ../../include;../ExternalApi;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;AUTHSTATE_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + Size + + + NotSet + true + Windows + true + true + 0x22620000 + $(IntDir)$(TargetName).lib + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/Rate/rate_10.vcxproj.filters b/plugins/Rate/rate_10.vcxproj.filters new file mode 100644 index 0000000000..53188635f5 --- /dev/null +++ b/plugins/Rate/rate_10.vcxproj.filters @@ -0,0 +1,58 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {629d9113-01ed-4da4-8f68-76e949ebdb7b} + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Docs + + + Docs + + + \ No newline at end of file diff --git a/plugins/Rate/resource.h b/plugins/Rate/resource.h new file mode 100644 index 0000000000..3b27728839 --- /dev/null +++ b/plugins/Rate/resource.h @@ -0,0 +1,22 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by rate.rc +// +#define IDD_RATE_OPT 9 +#define IDI_RATEHI 101 +#define IDI_RATEME 102 +#define IDI_RATELO 103 +#define IDC_ADVICON 1001 +#define IDC_NOTMODERN_WARNING 1010 +#define IDC_USED_CLIST 1011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1013 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/TooltipNotify/doc/todo.txt b/plugins/TooltipNotify/doc/todo.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/TooltipNotify/doc/tt_wnd_def_style.txt b/plugins/TooltipNotify/doc/tt_wnd_def_style.txt new file mode 100644 index 0000000000..c47a6a363f --- /dev/null +++ b/plugins/TooltipNotify/doc/tt_wnd_def_style.txt @@ -0,0 +1,9 @@ +ws_popup +ws_visible +ws_clipsiblings +ws_border + +ws_ex_left +ws_ex_ltrreading +ws_ex_rightscrollbar +ws_ex_topmost \ No newline at end of file diff --git a/plugins/TooltipNotify/doc/ttnotify-readme.txt b/plugins/TooltipNotify/doc/ttnotify-readme.txt new file mode 100644 index 0000000000..1d2e816390 --- /dev/null +++ b/plugins/TooltipNotify/doc/ttnotify-readme.txt @@ -0,0 +1,128 @@ + + + Tooltip notify plugin for Miranda IM + ____________________________________ + + Version 0.6.0.45 + + +About +_____ + +This Miranda IM plugin popups a small tooltip above system tray area +when a contact changes his status. It's intended for and tested with ICQ +protocol mainly, so it can miswork with other protocols. + + + +Changelog +_________ + +Version 0.6.0.45 + - Individual font settings for events + +Version 0.5.0.42 + - Added idle notifications + - Using font services + +Version 0.4.0.36 + - Fixed crash with too long contact names + +Version 0.4.0.32 + - Next generation plugin interface support + - Correct unicode/ansi flag in plugin description + +Version 0.4.0.29 + - per-contact notifications ability + - ansi/unicode module check on corresponding os + - more unicode support + - internal module name changed from 'ttntfmod' to 'Tooltip Notify' + (all settings migrate automatically) + - fixed potential crash while reading font settings + - fixed memory leak + +Version 0.3.0.15 + - fixed one major unexpected crash + +Version 0.3.0.14 + - unicode support + - fixed minor bug related to settings reading + - fixed potential crash with the tooltip moving + - other minor fixes + +Version 0.2.0.2 + - obey 'suppress online notification' setting + - sound plays only if the event notification is checked + - minor stability fixes + - translation file update + +Version 0.2.0.1 + - stability fixes + +Version 0.2.0.0 + - some controls' text fields are enlarged (translators requests) + - win9x misworking fixed (not tested) + - new abilities: + - proto name prefixing + - enabled back + - work in conjunction with 'suppress online notification' + +Version 0.1.0.0 + - the whole code rewritten in cpp + - new abilities: + - suppress notifications upon connect + - typing notification + - disabled + - work in conjunction with 'suppress online notification' + +Version 0.0.6.0 + - rewritten code of the tooltip window + - tooltip dragging behavior changed (now with usual left-click) + - new options: + - double click on tooltip action + - font and color customization + - some minor fixes/changes + +Version 0.0.5.0 + - sound support for the contact events + - added a button to run the tooltip within the options dialog to test it + - some minor changes + +Version 0.0.4.3 + - protocols selection bug fixed + +Version 0.0.4.2 + - translucency options + - translation support + +Version 0.0.4.0 + - ability to select protocols to react to + - ability of custom tooltip placement + +Version 0.0.3.1 + - a little translations added + +Version 0.0.3.0 + - options moved to events->tooltip notify + - options added: + - allow tooltip duration adjusting + - conjunctive work with 'Suppress online notification' + - fixed showing a tooltip when protocol goes offline + - plugin size reduced + +Version 0.0.2.4 + - some internal fixes + + +Copyright +_________ + +Copyright (C) 2004-2008 Gneedah software (perf@mail333.com) + + + +DISCLAIMER OF WARRANTY +-------------------------------------------------------------------- + +This software is distributed "AS IS" without any warranties. +USE IT AT YOU OWN RISK. diff --git a/plugins/TooltipNotify/doc/ttnotify_translation.txt b/plugins/TooltipNotify/doc/ttnotify_translation.txt new file mode 100644 index 0000000000..2c7d965d67 --- /dev/null +++ b/plugins/TooltipNotify/doc/ttnotify_translation.txt @@ -0,0 +1,47 @@ +; This is a template for Tooltip Notify translation. + + +; ******** Plugin info ******** +;[Tooltip Notify] +;[Shows a small tooltip above system tray area when a contact status is changed] + + +; ******** Options and tooltip text ******** + +;[Notify upon the following contact status changes] +;[Online] +;[Offline] +;[Away] +;[N/A] +;[Occupied] +;[DND] +;[Free for chat] +;[Invisible] +;[All other] +;[Unknown] +;[Typing] +;[Idle] +;[Suppress notifications upon connection for] +;[sec] +;[Prefix proto name] +;[Protocols] +;[is] + +;[Duration] +;[Show tooltip for] +;[ms] +;[Duration x2 upon online event] + +;[Double click on tooltip] +;[Shows/Hides CList] +;[Opens message dialog] + +;[Misc] +;[Obey 'Suppress online notification' settings] +;[Auto positioning] +;[Transparent input] + +;[Preview] + +;[Translucency options (Windows 2000/XP only)] +;[Transparent tooltip] diff --git a/plugins/TooltipNotify/src/DbHelpers.cpp b/plugins/TooltipNotify/src/DbHelpers.cpp new file mode 100644 index 0000000000..930206486d --- /dev/null +++ b/plugins/TooltipNotify/src/DbHelpers.cpp @@ -0,0 +1,120 @@ +// DbHelpers.cpp +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "DbHelpers.h" + +typedef std::vector SettingsList; + +static int EnumSettingsProc1(const char *pszSetting, LPARAM lParam) +{ + return 0; +} + +bool ModuleSettingsExists(HANDLE hContact, const char* pszModuleName) +{ + DBCONTACTENUMSETTINGS dbces = {0}; + dbces.szModule = pszModuleName; + dbces.pfnEnumProc = EnumSettingsProc1; + + int nResult = ::CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)hContact, (LPARAM)&dbces); + return (nResult != -1); +} + +static int EnumSettingsProc2(const char *pszSetting, LPARAM lParam) +{ + SettingsList& settingsList = *((SettingsList*)lParam); + settingsList.push_back(_strdup(pszSetting)); + return 0; +} + +void DeleteModuleSettings(HANDLE hContact, const char* pszModuleName) +{ + SettingsList settingsList; + DBCONTACTENUMSETTINGS dbces = {0}; + dbces.szModule = pszModuleName; + dbces.lParam = (LPARAM)&settingsList; + dbces.pfnEnumProc = EnumSettingsProc2; + + int nResult = ::CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)hContact, (LPARAM)&dbces); + if (nResult != -1) + { + for(unsigned i=0; itype = 0; + + int rr = CallService(MS_DB_CONTACT_GETSETTING,(WPARAM)hContact,(LPARAM)&cgs); + + if (dbv->type != DBVT_UTF8) + return rr; + else + return 1; +} + +void RenameModule(HANDLE hContact, const char* pszOldName, const char* pszNewName) +{ + SettingsList settingsList; + DBCONTACTENUMSETTINGS dbces = {0}; + dbces.szModule = pszOldName; + dbces.lParam = (LPARAM)&settingsList; + dbces.pfnEnumProc = EnumSettingsProc2; + + int nResult = ::CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)hContact, (LPARAM)&dbces); + if (nResult != -1) + { + DBVARIANT dbv; + + for(unsigned i=0; iGetDllInstance(), NULL); + + SetWindowLong(m_hWnd, GWL_USERDATA, reinterpret_cast(this)); +} + + +CTooltip::~CTooltip() +{ + if (m_hWnd) DestroyWindow(m_hWnd); + if (m_hFont) DeleteObject(m_hFont); + + if (m_szText) free(m_szText); +} + +/*static*/ void CTooltip::Initialize(HMODULE hInstance) +{ + WNDCLASSEX wcexWndClass; + wcexWndClass.cbSize = sizeof(WNDCLASSEX); + wcexWndClass.style = CS_SAVEBITS; + wcexWndClass.lpfnWndProc = (WNDPROC)CTooltip::WindowProcWrapper; + wcexWndClass.cbClsExtra = 0; + wcexWndClass.cbWndExtra = 0; + wcexWndClass.hInstance = hInstance; + wcexWndClass.hIcon = 0; + wcexWndClass.hCursor = 0; + wcexWndClass.hbrBackground = 0; + wcexWndClass.lpszMenuName = 0; + wcexWndClass.lpszClassName = s_szTooltipClass; + wcexWndClass.hIconSm = 0; + RegisterClassEx(&wcexWndClass); +} + +/*static*/ void CTooltip::Deinitialize(HMODULE hInstance) +{ + UnregisterClass(s_szTooltipClass, hInstance); +} + +LRESULT CALLBACK CTooltip::WindowProcWrapper(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + CTooltip* pThis = reinterpret_cast(GetWindowLong(hWnd, GWL_USERDATA)); + return pThis->WindowProc(hWnd, message, wParam, lParam); +} + + + +LRESULT CALLBACK CTooltip::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_CREATE: + break; + + case WM_COMMAND: + break; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps); + + RECT rect; + GetClientRect(hWnd, &rect); + + rect.top += 1; + rect.left += 1; + rect.right -= 1; + rect.bottom -= 1; + + SetBkMode(hDC, TRANSPARENT); + SetTextColor(hDC, m_dwTextColor); + SelectObject(hDC, m_hFont); + DrawText(hDC, m_szText, lstrlen(m_szText), &rect, DT_CENTER|DT_VCENTER|DT_SINGLELINE); + + EndPaint(hWnd, &ps); + + break; + } + + case WM_ERASEBKGND: + { + RECT rect; + GetClientRect(hWnd, &rect); + HBRUSH hBgBrush = CreateSolidBrush(m_dwBgColor); + FillRect((HDC)wParam, &rect, hBgBrush); + DeleteObject(hBgBrush); + + return TRUE; + } + + case WM_NCHITTEST: + { + UINT uHitTest = DefWindowProc(hWnd, message, wParam, lParam); + if(uHitTest == HTCLIENT) + return HTCAPTION; + else + return uHitTest; + } + + case WM_NCLBUTTONDBLCLK: + { + m_pTooltipNotify->OnTooltipDblClicked(this); + break; + } + + case WM_SYSCOMMAND: + { + if (!m_pTooltipNotify->OnTooltipBeginMove(this)) + break; + + // doesn't return until the moving is complete + DefWindowProc(hWnd, message, wParam, lParam); + // DefWindowProc returned + m_pTooltipNotify->OnTooltipEndMove(this); + + break; + } + + case WM_DESTROY: + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; + +} + + +VOID CTooltip::Validate() +{ + m_hFont = CreateFontIndirect(&m_lfFont); + SIZE Size; + HDC hDC = GetDC(m_hWnd); + SelectObject(hDC, m_hFont); + GetTextExtentPoint32(hDC, m_szText, lstrlen(m_szText), &Size); + SetWindowPos(m_hWnd, 0, 0, 0, Size.cx+6, Size.cy+4, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW); + ReleaseDC(m_hWnd, hDC); +} + + +VOID CTooltip::Show() +{ + ShowWindow(m_hWnd, SW_SHOWNOACTIVATE); +} + + +VOID CTooltip::Hide() +{ + ShowWindow(m_hWnd, SW_HIDE); +} + + + +VOID CTooltip::set_Translucency(BYTE bAlpha) +{ + typedef BOOL (WINAPI *pfnSetLayeredWindowAttributes_t)(HWND, COLORREF, BYTE, DWORD); + pfnSetLayeredWindowAttributes_t pfnSetLayeredWindowAttributes; + + pfnSetLayeredWindowAttributes = reinterpret_cast + (GetProcAddress(GetModuleHandle(_T("user32.dll")), "SetLayeredWindowAttributes")); + + if (pfnSetLayeredWindowAttributes && + SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED) != 0) + { + pfnSetLayeredWindowAttributes(m_hWnd, RGB(0,0,0), bAlpha, LWA_ALPHA); + } +} + +VOID CTooltip::set_TransparentInput(BOOL bOnOff) +{ + if (bOnOff) + SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_TRANSPARENT); + else + SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) & ~WS_EX_TRANSPARENT); +} + + +VOID CTooltip::get_Rect(RECT *Rect) const +{ + GetWindowRect(m_hWnd, Rect); +} + +VOID CTooltip::set_Position(INT x, INT y) +{ + SetWindowPos(m_hWnd, 0, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); +} + +VOID CTooltip::set_Text(const TCHAR* szText) +{ + if (m_szText) free(m_szText); + m_szText = _tcsdup(szText); +} + diff --git a/plugins/TooltipNotify/src/Tooltip.h b/plugins/TooltipNotify/src/Tooltip.h new file mode 100644 index 0000000000..fc97348370 --- /dev/null +++ b/plugins/TooltipNotify/src/Tooltip.h @@ -0,0 +1,55 @@ +// Tooltip.h: interface for the CTooltip class. +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +class CTooltipNotify; + +class CTooltip +{ +public: + + CTooltip(CTooltipNotify *pTooltipNotify); + virtual ~CTooltip(); + + HWND GetHandle() const { return m_hWnd; } + VOID Hide(); + VOID Show(); + VOID Validate(); + VOID set_Position(INT x, INT y); + VOID get_Rect(RECT *Rect) const; + VOID set_TransparentInput(BOOL bOnOff); + VOID set_Translucency(BYTE bAlpha); + VOID set_Text(const TCHAR* szText); + VOID set_Font(const LOGFONT& Font) { m_lfFont = Font; } + VOID set_TextColor(DWORD TextColor) { m_dwTextColor = TextColor; } + VOID set_BgColor(DWORD BgColor) { m_dwBgColor = BgColor; } + + static void Initialize(HMODULE hInstance); + static void Deinitialize(HMODULE hInstance); + +private: + // prohibit copying + CTooltip(const CTooltip& rhs); + CTooltip& operator= (const CTooltip& rhs); + +private: + static LRESULT CALLBACK WindowProcWrapper(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + + HWND m_hWnd; + HFONT m_hFont; + + // tooltip parameters + DWORD m_dwTextColor; + DWORD m_dwBgColor; + LOGFONT m_lfFont; + TCHAR *m_szText; + BYTE m_bAlpha; + BOOL m_bTranspInput; + BYTE m_bLDblClick; + + CTooltipNotify *m_pTooltipNotify; + static const TCHAR *s_szTooltipClass; +}; diff --git a/plugins/TooltipNotify/src/TooltipNotify.cpp b/plugins/TooltipNotify/src/TooltipNotify.cpp new file mode 100644 index 0000000000..ac480dc1e6 --- /dev/null +++ b/plugins/TooltipNotify/src/TooltipNotify.cpp @@ -0,0 +1,1114 @@ +// TooltipNotify.cpp: implementation of the CTooltipNotify class. +// +////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "resource.h" +#include "TooltipNotify.h" +#include "Tooltip.h" +#include "Settings.h" +#include "DbHelpers.h" +#include "Utils.h" + +#define ReadSettingByte(c, d) DBGetContactSettingByte(NULL, s_szModuleName, c, d) +#define ReadSettingWord(c, d) DBGetContactSettingWord(NULL, s_szModuleName, c, d) +#define ReadSettingDword(c, d) DBGetContactSettingDword(NULL, s_szModuleName, c, d) +#define ReadSettingString(c, d) DBGetContactSettingTString(NULL, s_szModuleName, c, d) + +#define WriteSettingByte(c, d) DBWriteContactSettingByte(NULL, s_szModuleName, c, d) +#define WriteSettingWord(c, d) DBWriteContactSettingWord(NULL, s_szModuleName, c, d) +#define WriteSettingDword(c, d) DBWriteContactSettingDword(NULL, s_szModuleName, c, d) +#define WriteSettingString(c, d) DBWriteContactSettingTString(NULL, s_szModuleName, c, d) + +enum +{ + ProtoIntBit = 0x01, + ProtoUserBit = 0x02 +}; + +static const char* SND_ONLINE = "ttntfOnline"; +static const char* SND_OFFLINE = "ttntfOffline"; +static const char* SND_OTHER = "ttntfOther"; +static const char* SND_TYPING = "ttntfTyping"; +static const char* CONTACT_IGNORE_TTNOTIFY = "Ignore"; + +static const int ID_TTNTF_STATUS_TYPING = ID_STATUS_INVISIBLE+10; +static const int ID_TTNTF_STATUS_IDLE = ID_STATUS_INVISIBLE+11; +static const int ID_TTNTF_STATUS_NOT_IDLE = ID_STATUS_INVISIBLE+12; + +#define FONTSERV_GROUP _T("Tooltip Notify") +#define FONTSERV_ONLINE _T("Online") +#define FONTSERV_OFFLINE _T("Offline") +#define FONTSERV_OTHER _T("Other Status") +#define FONTSERV_TYPING _T("Typing") +#define FONTSERV_IDLE _T("Idle") + +struct FontEntry +{ + int status; + TCHAR* name; + char* fontPrefix; + char* clrPrefix; +}; + +static FontEntry s_fontTable[] = +{ + ID_STATUS_ONLINE, FONTSERV_ONLINE, "OnlineFont", "OnlineBgColor", + ID_STATUS_OFFLINE, FONTSERV_OFFLINE, "OfflineFont", "OfflineBgColor", + ID_TTNTF_STATUS_TYPING, FONTSERV_TYPING, "TypingFont", "TypingBgColor", + ID_TTNTF_STATUS_IDLE, FONTSERV_IDLE, "IdleFont", "IdleBgColor", + ID_TTNTF_STATUS_NOT_IDLE, FONTSERV_IDLE, "IdleFont", "IdleBgColor", + 0, FONTSERV_OTHER, "OtherFont", "OtherBgColor", +}; + +/*static*/ CTooltipNotify *CTooltipNotify::s_pInstance = 0; +/*static*/ const char *CTooltipNotify::s_szModuleNameOld = "ttntfmod"; +/*static*/ const char *CTooltipNotify::s_szModuleName = "TooltipNotify"; + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CTooltipNotify::CTooltipNotify(HINSTANCE hinstDLL) : + m_hDllInstance(hinstDLL), m_bNt50(IsNt50()) +{ + if (s_pInstance!=0) + throw EAlreadyExists(); + + s_pInstance = this; + + CTooltip::Initialize(m_hDllInstance); +} + +CTooltipNotify::~CTooltipNotify() +{ + EndNotifyAll(); + CTooltip::Deinitialize(m_hDllInstance); + s_pInstance=0; +} + +void CTooltipNotify::RegisterFonts() +{ + FontIDT fontId = {0}; + fontId.cbSize = sizeof(fontId); + _tcscpy(fontId.group, FONTSERV_GROUP); + strcpy(fontId.dbSettingsGroup, s_szModuleName); + fontId.flags = FIDF_DEFAULTVALID; + fontId.deffontsettings.colour = DEF_SETTING_TXTCOLOR; + fontId.deffontsettings.size = -MulDiv(DEF_SETTING_FONT_SIZE, DEF_LOGPIXELSY, 72); + fontId.deffontsettings.style = DEF_SETTING_FONT_STYLE; + fontId.deffontsettings.charset = DEF_SETTING_FONT_CHARSET; + _tcscpy(fontId.deffontsettings.szFace, DEF_SETTING_FONT_FACE); + fontId.order = 0; + _tcscpy(fontId.backgroundGroup, FONTSERV_GROUP); + + ColourIDT colorId = {0}; + colorId.cbSize = sizeof(colorId); + _tcscpy(colorId.group, FONTSERV_GROUP); + strcpy(colorId.dbSettingsGroup, s_szModuleName); + colorId.flags = 0; + colorId.defcolour = DEF_SETTING_BGCOLOR; + colorId.order = 0; + + for (int i=0; i0) + { + STooltipData *pTooltipData = new STooltipData; + pTooltipData->uiTimeout = lParam*1000; + pTooltipData->hContact = (HANDLE)wParam; + pTooltipData->iStatus = ID_TTNTF_STATUS_TYPING; + + EndNotifyAll(); + SkinPlaySound(SND_TYPING); + BeginNotify(pTooltipData); + } + else + { + EndNotifyAll(); + } + + return 0; +} + + +int CTooltipNotify::ProtoAck(WPARAM wParam, LPARAM lParam) +{ + ACKDATA *ack=(ACKDATA*)lParam; + if(ack->type != ACKTYPE_STATUS) return 0; + + WORD wNewStatus = (WORD)ack->lParam; + WORD wOldStatus = (WORD)ack->hProcess; + if (wOldStatus == wNewStatus) return 0; //Useless message. + + char *szProtocol = (char *)ack->szModule; + + if (wNewStatus == ID_STATUS_OFFLINE) + { + BYTE bProtoActive = ReadSettingByte(szProtocol, ProtoUserBit|ProtoIntBit); + bProtoActive &= ~ProtoIntBit; + WriteSettingByte(szProtocol, bProtoActive); + } + else + { + if (wOldStatus < ID_STATUS_ONLINE && wNewStatus > ID_STATUS_OFFLINE) + { + UINT_PTR idTimer = SetTimer(0, 0, m_sOptions.wStartupDelay*1000, ConnectionTimerProcWrapper); + ProtoData protoData = { _strdup(szProtocol), idTimer }; + m_mapTimerIdProto.push_back(protoData); + } + } + + return 0; +} + +int CTooltipNotify::ContactSettingChanged(WPARAM wParam, LPARAM lParam) +{ + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; + HANDLE hContact = (HANDLE)wParam; + if(hContact==NULL) return 0; + + bool idle = false; + if (lstrcmpA(cws->szSetting,"Status")==0) + idle = false; + else if (lstrcmpA(cws->szSetting,"IdleTS")==0) + idle = true; + else return 0; + + if(DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) return 0; + + const char *pszProto = cws->szModule; + if (ReadSettingByte(pszProto, ProtoUserBit|ProtoIntBit) != (ProtoUserBit|ProtoIntBit)) + { + return 0; + } + + if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0) && m_sOptions.bIgnoreUnknown) + { + return 0; + } + + if (DBGetContactSettingByte(hContact, s_szModuleName, CONTACT_IGNORE_TTNOTIFY, m_sOptions.bIgnoreNew)) + { + return 0; + } + + if (idle && !m_sOptions.bIdle) return 0; + + WORD wNewStatus = cws->value.wVal; + switch(wNewStatus) + { + case ID_STATUS_OFFLINE: + if (!m_sOptions.bOffline) return 0; + SkinPlaySound(SND_OFFLINE); + break; + + case ID_STATUS_ONLINE: + if(CallService(MS_IGNORE_ISIGNORED,(WPARAM)hContact,IGNOREEVENT_USERONLINE) && m_sOptions.bConjSOLN) return 0; + if (!m_sOptions.bOnline) return 0; + SkinPlaySound(SND_ONLINE); + break; + + default: + if (!m_sOptions.bOther) return 0; + SkinPlaySound(SND_OTHER); + break; + } + + STooltipData *pTooltipData = new STooltipData; + pTooltipData->uiTimeout = m_sOptions.wDuration * (wNewStatus==ID_STATUS_ONLINE ? (m_sOptions.bX2+1):1); + pTooltipData->hContact = hContact; + + if (idle) wNewStatus = (wNewStatus!=0 ? ID_TTNTF_STATUS_IDLE : ID_TTNTF_STATUS_NOT_IDLE); + pTooltipData->iStatus = wNewStatus; + + EndNotifyAll(); + BeginNotify(pTooltipData); + + return 0; + +} + +int CTooltipNotify::InitializeOptions(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + + ZeroMemory(&odp,sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = 100000000; + odp.hInstance = m_hDllInstance; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); + odp.ptszTitle = TranslateT("Tooltip Notify"); + odp.ptszGroup = TranslateT("Appearance"); + odp.groupPosition = 910000000; + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + odp.pfnDlgProc = CTooltipNotify::OptionsDlgProcWrapper; + ::CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + + return 0; +} + +CTooltip *CTooltipNotify::BeginNotify(STooltipData *pTooltipData) +{ + TCHAR szTooltipText[64] = {0}; + MakeTooltipString(pTooltipData->hContact, pTooltipData->iStatus, szTooltipText, 64); + + LOGFONT lf = {0}; + COLORREF textColor = 0; + COLORREF bgColor = 0; + GetFont(pTooltipData->iStatus, &lf, &textColor, &bgColor); + + CTooltip *pTooltip = new CTooltip(this); + pTooltip->set_Text(szTooltipText); + pTooltip->set_Font(lf); + pTooltip->set_BgColor(bgColor); + pTooltip->set_TextColor(textColor); + if (m_bNt50 && m_sOptions.bTransp) + pTooltip->set_Translucency(m_sOptions.bAlpha); + pTooltip->set_TransparentInput(m_bNt50 && m_sOptions.bTransp && m_sOptions.bTranspInput); + pTooltip->Validate(); + + RECT TooltipRect, WorkAreaRect; + SystemParametersInfo(SPI_GETWORKAREA, 0, &WorkAreaRect, 0); + pTooltip->get_Rect(&TooltipRect); + + int tt_width = TooltipRect.right-TooltipRect.left; + int tt_height = TooltipRect.bottom-TooltipRect.top; + + if (m_sOptions.bAutoPos || + m_sOptions.wXPos > WorkAreaRect.right-tt_width || + m_sOptions.wYPos > WorkAreaRect.bottom-tt_height) + { + pTooltip->set_Position( + WorkAreaRect.right - 10 - tt_width, + WorkAreaRect.bottom - 2 - tt_height); + } + else + { + pTooltip->set_Position(m_sOptions.wXPos, m_sOptions.wYPos); + } + + + UINT_PTR idTimer = SetTimer(0, 0, pTooltipData->uiTimeout, TooltipTimerProcWrapper); + pTooltipData->idTimer = idTimer; + pTooltipData->pTooltip = pTooltip; + + m_TooltipsList.push_back(pTooltipData); + + pTooltip->Show(); + + return pTooltip; +} + +BOOL CTooltipNotify::EndNotify(STooltipData* pTooltipData) +{ + CTooltip* pTooltip = pTooltipData->pTooltip; + + // return if the tooltip timer suspended + if (pTooltipData->idTimer == 0) return FALSE; + SuspendTimer(pTooltip); + + pTooltip->Hide(); + delete pTooltip; + delete pTooltipData; + + m_TooltipsList.erase( + std::remove(m_TooltipsList.begin(), m_TooltipsList.end(), pTooltipData), + m_TooltipsList.end()); + + return TRUE; +} + +VOID CTooltipNotify::EndNotifyAll() +{ + // iterate through active tooltips and + // remove one which do not have its timer suspended + TooltipsList::reverse_iterator mapRevIter = m_TooltipsList.rbegin(); + while (mapRevIter != m_TooltipsList.rend()) + { + STooltipData* pTooltipData = *mapRevIter; + if (EndNotify(pTooltipData)) + { + mapRevIter = m_TooltipsList.rbegin(); + } + else + { + ++mapRevIter; + } + } +} + +CTooltipNotify::MapTimerIdProtoIter CTooltipNotify::FindProtoByTimer(UINT idTimer) +{ + for ( + MapTimerIdProtoIter iter = m_mapTimerIdProto.begin(); + iter != m_mapTimerIdProto.end(); + ++iter) + { + if (iter->timerId == idTimer) + { + return iter; + } + } + + return m_mapTimerIdProto.end(); +} + +VOID CTooltipNotify::OnConnectionTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + BOOL bSuccess = KillTimer(0, idEvent); + assert(bSuccess); + + MapTimerIdProtoIter iter = FindProtoByTimer(idEvent); + assert(iter!=m_mapTimerIdProto.end()); + + BYTE bProtoActive = ReadSettingByte(iter->proto, ProtoUserBit|ProtoIntBit); + bProtoActive |= ProtoIntBit; + WriteSettingByte(iter->proto, bProtoActive); + + free((char*)iter->proto); + m_mapTimerIdProto.erase(iter); +} + + +VOID CTooltipNotify::OnTooltipTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + TooltipsList::iterator iter = FindBy(&STooltipData::idTimer, idEvent); + assert(iter!=m_TooltipsList.end()); + + STooltipData* pTooltipData = *iter; + EndNotify(pTooltipData); +} + +VOID CTooltipNotify::MigrateSettings() +{ + if (ModuleSettingsExists(NULL, s_szModuleNameOld) && !ModuleSettingsExists(NULL, s_szModuleName)) + { + RenameModule(NULL, s_szModuleNameOld, s_szModuleName); + } +} + +VOID CTooltipNotify::LoadSettings() +{ + m_sOptions.bFirstRun = ReadSettingByte("firstrun", DEF_SETTING_FIRSTRUN); + m_sOptions.bOffline = ReadSettingByte("offline", DEF_SETTING_OFFLINE); + m_sOptions.bOnline = ReadSettingByte("online", DEF_SETTING_ONLINE); + m_sOptions.bOther = ReadSettingByte("other", DEF_SETTING_OTHER); + m_sOptions.bTyping = ReadSettingByte("typing", DEF_SETTING_TYPING); + m_sOptions.bIdle = ReadSettingByte("idle", DEF_SETTING_TYPING); + m_sOptions.bX2 = ReadSettingByte("x2", DEF_SETTING_X2); + m_sOptions.bConjSOLN = ReadSettingByte("conjsoln", DEF_SETTING_CONJSOLN); + m_sOptions.bAutoPos = ReadSettingByte("autopos", DEF_SETTING_DEF_POS); + m_sOptions.bBallonTip = ReadSettingByte("balloontip", DEF_SETTING_BALLONTIP); + m_sOptions.bTransp = ReadSettingByte("transp", DEF_SETTING_TRANSP); + m_sOptions.bAlpha = ReadSettingByte("alpha", DEF_SETTING_ALPHA); + m_sOptions.bTranspInput = ReadSettingByte("transpinput", DEF_SETTING_TRANSP_INPUT); + m_sOptions.bPrefixProto = ReadSettingByte("prfxproto", DEF_SETTING_PREFIX_PROTO); + m_sOptions.bLDblClick = ReadSettingByte("ldblclick", DEF_SETTING_LDBLCLICK); + m_sOptions.wDuration = ReadSettingWord("duration", DEF_SETTING_DURATION); + m_sOptions.wXPos = ReadSettingWord("xpos", DEF_SETTING_DEF_XPOS); + m_sOptions.wYPos = ReadSettingWord("ypos", DEF_SETTING_DEF_YPOS); + m_sOptions.wStartupDelay = ReadSettingWord("suprconndelay", DEF_SETTING_STARTUP_DELAY); + m_sOptions.bIgnoreUnknown = ReadSettingByte("ignoreunknown", DEF_SETTING_IGNORE_UNKNOWN); + m_sOptions.bIgnoreNew = ReadSettingByte("ignorenew", DEF_SETTING_IGNORE_NEW); +} + +VOID CTooltipNotify::SaveSettings() +{ + WriteSettingWord("duration", m_sOptions.wDuration); + WriteSettingWord("suprconndelay", m_sOptions.wStartupDelay); + WriteSettingByte("offline", m_sOptions.bOffline); + WriteSettingByte("online", m_sOptions.bOnline); + WriteSettingByte("other", m_sOptions.bOther); + WriteSettingByte("typing", m_sOptions.bTyping); + WriteSettingByte("idle", m_sOptions.bIdle); + WriteSettingByte("prfxproto", m_sOptions.bPrefixProto); + WriteSettingByte("x2", m_sOptions.bX2); + WriteSettingByte("conjsoln", m_sOptions.bConjSOLN); + WriteSettingByte("autopos", m_sOptions.bAutoPos); + WriteSettingByte("balloontip", m_sOptions.bBallonTip); + WriteSettingByte("transp", m_sOptions.bTransp); + WriteSettingByte("alpha", m_sOptions.bAlpha); + WriteSettingByte("transpinput", m_sOptions.bTranspInput); + WriteSettingByte("ldblclick", m_sOptions.bLDblClick); + WriteSettingByte("ignoreunknown", m_sOptions.bIgnoreUnknown); + WriteSettingByte("ignorenew", m_sOptions.bIgnoreNew); +} + + +VOID CTooltipNotify::ReadSettingsFromDlg(HWND hDlg) +{ + m_sOptions.bOffline = (BYTE)(IsDlgButtonChecked(hDlg, IDC_OFFLINE) == BST_CHECKED ? 1:0); + m_sOptions.bOnline = (BYTE)(IsDlgButtonChecked(hDlg, IDC_ONLINE) == BST_CHECKED ? 1:0); + m_sOptions.bOther = (BYTE)(IsDlgButtonChecked(hDlg, IDC_OTHER) == BST_CHECKED ? 1:0); + m_sOptions.bTyping = (BYTE)(IsDlgButtonChecked(hDlg, IDC_TYPING) == BST_CHECKED ? 1:0); + m_sOptions.bIdle = (BYTE)(IsDlgButtonChecked(hDlg, IDC_IDLE) == BST_CHECKED ? 1:0); + m_sOptions.bX2 = (BYTE)(IsDlgButtonChecked(hDlg, IDC_X2) == BST_CHECKED ? 1:0); + m_sOptions.bConjSOLN = (BYTE)(IsDlgButtonChecked(hDlg, IDC_CONJSOLN) == BST_CHECKED ? 1:0); + m_sOptions.bAutoPos = (BYTE)(IsDlgButtonChecked(hDlg, IDC_AUTOPOS) == BST_CHECKED ? 1:0); + m_sOptions.bBallonTip = (BYTE)(IsDlgButtonChecked(hDlg, IDC_BALLONTIP) == BST_CHECKED ? 1:0); + m_sOptions.bTransp = (BYTE)(IsDlgButtonChecked(hDlg, IDC_TRANSPARENCY) == BST_CHECKED ? 1:0); + m_sOptions.bAlpha = (BYTE)SendDlgItemMessage(hDlg,IDC_TRANSPARENCY_SLIDER,TBM_GETPOS,0,0); + m_sOptions.bTranspInput = (BYTE)(IsDlgButtonChecked(hDlg, IDC_TRANSP_INPUT) == BST_CHECKED ? 1:0); + m_sOptions.bPrefixProto = (BYTE)(IsDlgButtonChecked(hDlg, IDC_PREFIX_PROTO) == BST_CHECKED ? 1:0); + m_sOptions.bLDblClick = (BYTE)(IsDlgButtonChecked(hDlg, IDC_RB_CLIST) == BST_CHECKED) ? SHOW_HIDE_CLIST:OPEN_MSGDLG; + m_sOptions.wDuration = LOWORD(SendDlgItemMessage(hDlg, IDC_DURATIONSPIN, UDM_GETPOS, 0, 0)); + m_sOptions.wStartupDelay = LOWORD(SendDlgItemMessage(hDlg, IDC_DELAYONCONNSPIN, UDM_GETPOS, 0, 0)); +} + +VOID CTooltipNotify::WriteSettingsToDlg(HWND hDlg) +{ + SendDlgItemMessage(hDlg, IDC_DURATIONSPIN, UDM_SETRANGE, 0, MAKELONG(550*36, 550)); + SendDlgItemMessage(hDlg, IDC_DURATIONSPIN, UDM_SETPOS, 0, MAKELONG(m_sOptions.wDuration, 0)); + SendDlgItemMessage(hDlg, IDC_DELAYONCONNSPIN, UDM_SETRANGE, 0, MAKELONG(30, 0)); + SendDlgItemMessage(hDlg, IDC_DELAYONCONNSPIN, UDM_SETPOS, 0, MAKELONG(m_sOptions.wStartupDelay, 0)); + + CheckDlgButton(hDlg, IDC_OFFLINE, m_sOptions.bOffline ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_ONLINE, m_sOptions.bOnline ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_OTHER, m_sOptions.bOther ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_TYPING, m_sOptions.bTyping ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_IDLE, m_sOptions.bIdle ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_PREFIX_PROTO, m_sOptions.bPrefixProto ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_X2, m_sOptions.bX2 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_CONJSOLN, m_sOptions.bConjSOLN ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_AUTOPOS, m_sOptions.bAutoPos ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_BALLONTIP, m_sOptions.bBallonTip ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_TRANSPARENCY, m_sOptions.bTransp ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hDlg, IDC_TRANSP_INPUT, m_sOptions.bTranspInput ? BST_CHECKED:BST_UNCHECKED); + + switch(m_sOptions.bLDblClick) + { + case SHOW_HIDE_CLIST: CheckDlgButton(hDlg, IDC_RB_CLIST, TRUE); break; + case OPEN_MSGDLG: CheckDlgButton(hDlg, IDC_RB_MSGDLG, TRUE); break; + default: CheckDlgButton(hDlg, IDC_RB_CLIST, TRUE); break; + } + + EnableWindow(GetDlgItem(hDlg, IDC_GB_TRANSP), m_bNt50); + EnableWindow(GetDlgItem(hDlg, IDC_TRANSPARENCY), m_bNt50); + EnableWindow(GetDlgItem(hDlg, IDC_TRANSPARENCY_SLIDER), m_sOptions.bTransp && m_bNt50); + EnableWindow(GetDlgItem(hDlg, IDC_TRANSPERC), m_sOptions.bTransp && m_bNt50); + EnableWindow(GetDlgItem(hDlg, IDC_TRANSP_INPUT), m_sOptions.bTransp && m_bNt50); + //EnableWindow(GetDlgItem(hDlg, IDC_GB_DBLCLICK), m_sOptions.bTranspInput); + EnableWindow(GetDlgItem(hDlg, IDC_RB_CLIST), !m_sOptions.bTranspInput); + EnableWindow(GetDlgItem(hDlg, IDC_RB_MSGDLG), !m_sOptions.bTranspInput); + + SendDlgItemMessage(hDlg, IDC_TRANSPARENCY_SLIDER, TBM_SETRANGE, FALSE, MAKELONG(1,255)); + SendDlgItemMessage(hDlg, IDC_TRANSPARENCY_SLIDER, TBM_SETPOS, TRUE, m_sOptions.bAlpha); +} + + +VOID CTooltipNotify::ValidateSettings() +{ + if (m_sOptions.wStartupDelay>30) m_sOptions.wStartupDelay=30; + if (m_sOptions.wDuration>550*36) m_sOptions.wDuration=550*36; + if (m_sOptions.wDuration<550*1) m_sOptions.wDuration=550*1; + if (!m_sOptions.bTransp) m_sOptions.bTranspInput=0; +} + + +// main options dialog +BOOL CTooltipNotify::OptionsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hDlg); + WriteSettingsToDlg(hDlg); + SendMessage(hDlg, WM_HSCROLL, 0x12345678, 0); + + return TRUE; + } + + case WM_VSCROLL: + case WM_HSCROLL: + { + TCHAR str[10]; + wsprintf(str, _T("%d%%"), 100*SendDlgItemMessage(hDlg, IDC_TRANSPARENCY_SLIDER, TBM_GETPOS, 0, 0)/255); + SetDlgItemText(hDlg, IDC_TRANSPERC, str); + if(wParam!=0x12345678) SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_TRANSPARENCY: + EnableWindow(GetDlgItem(hDlg, IDC_TRANSPERC), IsDlgButtonChecked(hDlg, IDC_TRANSPARENCY) == BST_CHECKED); + EnableWindow(GetDlgItem(hDlg, IDC_TRANSPARENCY_SLIDER), IsDlgButtonChecked(hDlg, IDC_TRANSPARENCY) == BST_CHECKED); + EnableWindow(GetDlgItem(hDlg, IDC_TRANSP_INPUT), IsDlgButtonChecked(hDlg, IDC_TRANSPARENCY) == BST_CHECKED); + CheckDlgButton(hDlg, IDC_TRANSP_INPUT, IsDlgButtonChecked(hDlg, IDC_TRANSPARENCY) == BST_CHECKED ? m_sOptions.bTranspInput : BST_UNCHECKED); + SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_TRANSP_INPUT, 0), 0); + SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); + break; + + case IDC_TRANSP_INPUT: + //EnableWindow(GetDlgItem(hDlg,IDC_GB_DBLCLICK), IsDlgButtonChecked(hDlg, IDC_TRANSP_INPUT)); + EnableWindow(GetDlgItem(hDlg,IDC_RB_CLIST), !(IsDlgButtonChecked(hDlg, IDC_TRANSP_INPUT) == BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_RB_MSGDLG), !(IsDlgButtonChecked(hDlg, IDC_TRANSP_INPUT) == BST_CHECKED)); + SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); + break; + + case IDC_BALLONTIP: + EnableWindow(GetDlgItem(hDlg,IDC_DURATION),!(IsDlgButtonChecked(hDlg,IDC_BALLONTIP)==BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_X2),!(IsDlgButtonChecked(hDlg,IDC_BALLONTIP)==BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_RB_CLIST),!(IsDlgButtonChecked(hDlg,IDC_BALLONTIP)==BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_RB_MSGDLG),!(IsDlgButtonChecked(hDlg,IDC_BALLONTIP)==BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_TRANSP_INPUT),!(IsDlgButtonChecked(hDlg,IDC_BALLONTIP)==BST_CHECKED)); + EnableWindow(GetDlgItem(hDlg,IDC_AUTOPOS),!(IsDlgButtonChecked(hDlg,IDC_BALLONTIP)==BST_CHECKED)); + SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); + break; + + case IDC_DURATION: + if (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()) return FALSE; + SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); + break; + + case IDC_DELAYONCONN: + if (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()) return FALSE; + SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); + break; + + case IDC_PREVIEW: + { + STooltipData *pTooltipData = new STooltipData; + pTooltipData->uiTimeout = m_sOptions.wDuration * (m_sOptions.bX2 ? (m_sOptions.bX2+1):1); + pTooltipData->hContact = 0; + pTooltipData->iStatus = ID_STATUS_ONLINE; + + EndNotifyAll(); + BeginNotify(pTooltipData); + break; + } + + case IDC_SEL_PROTO: + DialogBox(m_hDllInstance, MAKEINTRESOURCE(IDD_PROTOS), hDlg, (DLGPROC)CTooltipNotify::ProtosDlgProcWrapper); + break; + + case IDC_IGNORE: + DialogBox(m_hDllInstance, MAKEINTRESOURCE(IDD_CONTACTS), hDlg, (DLGPROC)CTooltipNotify::ContactsDlgProcWrapper); + break; + + default: + // activate 'apply' button + SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + + return TRUE; + } + + case WM_NOTIFY: + { + //Here we have pressed either the OK or the APPLY button. + switch(((LPNMHDR)lParam)->idFrom) + { + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + ReadSettingsFromDlg(hDlg); + SaveSettings(); + return TRUE; + + } // switch code + break; + + } //switch idFrom + + return TRUE; + } + + default: + break; + + } + + return FALSE; + +} + + +// dialog for protocols selecting +BOOL CTooltipNotify::ProtosDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + + case WM_INITDIALOG: + { + TranslateDialogDefault(hDlg); + + ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_PROTOS), LVS_EX_CHECKBOXES); + + // enum protocols currently running + int iProtoCount = 0; + PROTOCOLDESCRIPTOR **ppProtos = 0; + ::CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&iProtoCount, (LPARAM)&ppProtos); + + // and fill in the list + int iNonProtoCount = 0; + for (int i=0; i < iProtoCount; i++) + { + if (ppProtos[i]->type == PROTOTYPE_PROTOCOL) + { + LV_ITEM lvi; + + lvi.mask = LVIF_TEXT; + lvi.iSubItem = 0; + lvi.iItem = i; + lvi.lParam = i; +#ifdef _UNICODE + WCHAR wszProto[128]; + long lLen = MultiByteToWideChar(CP_ACP, 0, ppProtos[i]->szName, + strlen(ppProtos[i]->szName), wszProto, ARRAY_SIZE(wszProto)); + wszProto[lLen] = L'\0'; + + lvi.pszText = wszProto; +#else + lvi.pszText = ppProtos[lvi.iItem]->szName; +#endif + int new_item = ListView_InsertItem(GetDlgItem(hDlg,IDC_PROTOS),&lvi); + + BYTE bProtoState = ReadSettingByte(ppProtos[i]->szName, ProtoUserBit|ProtoIntBit); + BOOL bProtoEnabled = (bProtoState & ProtoUserBit) != 0; + ListView_SetCheckState(GetDlgItem(hDlg,IDC_PROTOS), i-iNonProtoCount, bProtoEnabled); + } + else + { + iNonProtoCount++; + } + } + + return TRUE; + } + + + case WM_COMMAND: + { + if (LOWORD(wParam) == IDOK) + { + int proto_count = ListView_GetItemCount(GetDlgItem(hDlg,IDC_PROTOS)); + + for (int i=0; i < proto_count; i++) + { + TCHAR szProto[64]; + + ListView_GetItemText(GetDlgItem(hDlg,IDC_PROTOS), i, 0, szProto, ARRAY_SIZE(szProto)); +#ifdef _UNICODE + char szMultiByteProto[128]; + long lLen = WideCharToMultiByte(CP_ACP, 0, szProto, lstrlen(szProto), + szMultiByteProto, sizeof(szMultiByteProto), NULL, NULL); + szMultiByteProto[lLen] = '\0'; + + BYTE bProtoState = ReadSettingByte(szMultiByteProto, ProtoUserBit|ProtoIntBit); +#else + BYTE bProtoState = ReadSettingByte(szProto, ProtoUserBit|ProtoIntBit); +#endif + + BOOL bProtoEnabled = ListView_GetCheckState(GetDlgItem(hDlg,IDC_PROTOS), i); + bProtoState = bProtoEnabled ? bProtoState|ProtoUserBit : bProtoState&~ProtoUserBit; +#ifdef _UNICODE + WriteSettingByte(szMultiByteProto, bProtoState); +#else + WriteSettingByte(szProto, bProtoState); +#endif + } + + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + + if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + + return TRUE; + } + + case WM_CLOSE: + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + + default: + break; + + } // switch (msg) + + return FALSE; + +} + +void CTooltipNotify::ResetCList(HWND hwndDlg) +{ + BOOL b = (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && + DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT)); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) b, 0); + + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETHIDEEMPTYGROUPS, 1, 0); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETLEFTMARGIN, 2, 0); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKBITMAP, 0, (LPARAM) (HBITMAP) NULL); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETINDENT, 10, 0); + + for (int i = 0; i <= FONTID_MAX; i++) + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); +} + +void CTooltipNotify::LoadList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown) +{ + if (hItemNew && !m_sOptions.bIgnoreNew) + { + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemNew, 1); + } + if (hItemUnknown && !m_sOptions.bIgnoreUnknown) + { + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemUnknown, 1); + } + + HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + do + { + HANDLE hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0); + if (hItem && !DBGetContactSettingByte(hContact, s_szModuleName, CONTACT_IGNORE_TTNOTIFY, m_sOptions.bIgnoreNew)) + { + SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItem, 1); + } + } + while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)); +} + +void CTooltipNotify::SaveList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown) +{ + if (hItemNew) + { + m_sOptions.bIgnoreNew = (BYTE) (SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemNew, 0) ? 0 : 1); + } + if (hItemUnknown) + { + m_sOptions.bIgnoreUnknown = (BYTE) (SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemUnknown, 0) ? 0 : 1); + } + + HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + do + { + HANDLE hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0); + if (hItem) + { + BYTE bChecked = (BYTE) (SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0)); + DBWriteContactSettingByte(hContact, s_szModuleName, CONTACT_IGNORE_TTNOTIFY, bChecked ? 0 : 1); + } + } + while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)); +} + + +// dialog for ignore tooltip notifications +BOOL CTooltipNotify::ContactsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hItemNew, hItemUnknown; + + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hDlg); + + CLCINFOITEM cii = { 0 }; + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX; + cii.pszText = TranslateT("** New contacts **"); + hItemNew = (HANDLE) SendDlgItemMessage(hDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii); + cii.pszText = TranslateT("** Unknown contacts **"); + hItemUnknown = (HANDLE) SendDlgItemMessage(hDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii); + + ResetCList(hDlg); + LoadList(hDlg, hItemNew, hItemUnknown); + return TRUE; + } + + + case WM_COMMAND: + { + if (LOWORD(wParam) == IDOK) + { + SaveList(hDlg, hItemNew, hItemUnknown); + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + + if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + + return TRUE; + } + + case WM_CLOSE: + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + + default: + break; + + } // switch (msg) + + return FALSE; + +} + + + +TCHAR *CTooltipNotify::StatusToString(int iStatus, TCHAR *szStatus, int iBufSize) +{ + + //iBufSize--; + + switch(iStatus) + { + case ID_STATUS_OFFLINE: + lstrcpyn(szStatus, TranslateT("Offline"), iBufSize); + break; + + case ID_STATUS_ONLINE: + lstrcpyn(szStatus, TranslateT("Online"), iBufSize); + break; + + case ID_STATUS_AWAY: + lstrcpyn(szStatus, TranslateT("Away"), iBufSize); + break; + + case ID_STATUS_NA : + lstrcpyn(szStatus, TranslateT("N/A"), iBufSize); + break; + + case ID_STATUS_OCCUPIED: + lstrcpyn(szStatus, TranslateT("Occupied"), iBufSize); + break; + + case ID_STATUS_DND: + lstrcpyn(szStatus, TranslateT("DND"), iBufSize); + break; + + case ID_STATUS_FREECHAT: + lstrcpyn(szStatus, TranslateT("Free for chat"), iBufSize); + break; + + case ID_STATUS_INVISIBLE: + lstrcpyn(szStatus, TranslateT("Invisible"), iBufSize); + break; + + case ID_TTNTF_STATUS_TYPING: + lstrcpyn(szStatus, TranslateT("Typing"), iBufSize); + break; + + case ID_TTNTF_STATUS_IDLE: + lstrcpyn(szStatus, TranslateT("Idle"), iBufSize); + break; + + case ID_TTNTF_STATUS_NOT_IDLE: + lstrcpyn(szStatus, TranslateT("Not Idle"), iBufSize); + break; + + default: + lstrcpyn(szStatus, TranslateT("Unknown"), iBufSize); + break; + } + + return szStatus; + +} + +TCHAR *CTooltipNotify::MakeTooltipString(HANDLE hContact, int iStatus, TCHAR *szString, int iBufSize) +{ + TCHAR szStatus[32]; + StatusToString(iStatus, szStatus, ARRAY_SIZE(szStatus)); + + // "proro: user is online" + const TCHAR *szFormatString = m_sOptions.bPrefixProto ? _T("%s%s%s") : _T("%.0s%.0s%s"); + const TCHAR* szIs = TranslateT("is"); + + const char* szProto = + hContact==0 ? "Proto" : (char*)::CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + const TCHAR* szContactName = + (TCHAR *)::CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR); + + memset(szString, 0, iBufSize*sizeof(TCHAR)); + +#ifdef _UNICODE + WCHAR wszProto[32]; + long lLen = MultiByteToWideChar(CP_ACP, 0, szProto, strlen(szProto), wszProto, ARRAY_SIZE(wszProto)); + wszProto[lLen] = _T('\0'); + + _sntprintf(szString, iBufSize-1, szFormatString, wszProto, _T(": "), szContactName); +#else + _sntprintf(szString, iBufSize-1, szFormatString, szProto, _T(": "), szContactName); +#endif + + TruncateWithDots(szString, iBufSize-1-_tcslen(szStatus)-_tcslen(szIs)-2); // 2 spaces around szIs + _sntprintf(szString+_tcslen(szString), iBufSize-1-_tcslen(szString), _T(" %s %s"), szIs, szStatus); + + return szString; +} + + +VOID CTooltipNotify::OnTooltipDblClicked(CTooltip *pTooltip) +{ + switch(m_sOptions.bLDblClick) + { + case SHOW_HIDE_CLIST: + ::CallService(MS_CLIST_SHOWHIDE,0,0); + break; + + case OPEN_MSGDLG: + { + TooltipsList::iterator iter = FindBy(&STooltipData::pTooltip, pTooltip); + STooltipData* pTooltipData = *iter; + WPARAM wParam = (WPARAM)pTooltipData->hContact; + if (wParam) ::CallService(MS_CLIST_CONTACTDOUBLECLICKED, wParam, 0); + break; + } + + default: + ::CallService(MS_CLIST_SHOWHIDE,0,0); + break; + } +} + + +BOOL CTooltipNotify::OnTooltipBeginMove(CTooltip *pTooltip) +{ + if (m_sOptions.bAutoPos) return FALSE; + + SuspendTimer(pTooltip); + return TRUE; +} + + +VOID CTooltipNotify::OnTooltipEndMove(CTooltip *pTooltip) +{ + RECT TooltipRect; + + pTooltip->get_Rect(&TooltipRect); + m_sOptions.wXPos = (WORD)TooltipRect.left; + m_sOptions.wYPos = (WORD)TooltipRect.top; + WriteSettingWord("xpos", m_sOptions.wXPos); + WriteSettingWord("ypos", m_sOptions.wYPos); + + ResumeTimer(pTooltip); +} + + +VOID CTooltipNotify::SuspendTimer(CTooltip *pTooltip) +{ + TooltipsList::iterator iter = FindBy(&STooltipData::pTooltip, pTooltip); + assert(iter!=m_TooltipsList.end()); + + STooltipData* pTooltipData = *iter; + + BOOL bSuccess = KillTimer(0, pTooltipData->idTimer); + assert(bSuccess); + pTooltipData->idTimer = 0; // denote that the timer is inactive +} + + +VOID CTooltipNotify::ResumeTimer(CTooltip *pTooltip) +{ + TooltipsList::iterator iter = FindBy(&STooltipData::pTooltip, pTooltip); + assert(iter!=m_TooltipsList.end()); + + STooltipData* pTooltipData = *iter; + + UINT_PTR idTimer = SetTimer(0, 0, pTooltipData->uiTimeout, TooltipTimerProcWrapper); + pTooltipData->idTimer = idTimer; +} + +template +CTooltipNotify::TooltipsList::iterator CTooltipNotify::FindBy(T STooltipData::* field, const T& value) +{ + for ( + TooltipsList::iterator iter = m_TooltipsList.begin(); + iter != m_TooltipsList.end(); + ++iter) + { + STooltipData *pTooltipData = *iter; + if (pTooltipData->*field == value) + { + return iter; + } + } + + return m_TooltipsList.end(); +} diff --git a/plugins/TooltipNotify/src/TooltipNotify.h b/plugins/TooltipNotify/src/TooltipNotify.h new file mode 100644 index 0000000000..5e17597dd6 --- /dev/null +++ b/plugins/TooltipNotify/src/TooltipNotify.h @@ -0,0 +1,143 @@ +// TooltipNotify.h: interface for the CTooltipNotify class. +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +class CTooltip; + +class CTooltipNotify +{ +private: + struct STooltipData; + +public: + CTooltipNotify(HINSTANCE hinstDLL); + virtual ~CTooltipNotify(); + + // exceptions + class EAlreadyExists {}; + + BOOL EndNotify(STooltipData* pTooltipData); + VOID EndNotifyAll(); + CTooltip *BeginNotify(STooltipData *pTooltipData); + VOID OnTooltipDblClicked(CTooltip *pTooltip); + BOOL OnTooltipBeginMove(CTooltip *pTooltip); + VOID OnTooltipEndMove(CTooltip *pTooltip); + int InitializeOptions(WPARAM wParam, LPARAM lParam); + int ContactSettingChanged(WPARAM wParam, LPARAM lParam); + int ProtoAck(WPARAM wParam, LPARAM lParam); + int ModulesLoaded(WPARAM wParam,LPARAM lParam); + int ProtoContactIsTyping(WPARAM wParam, LPARAM lParam); + + static CTooltipNotify *GetObjInstance() { return s_pInstance; } + HINSTANCE GetDllInstance() const { return m_hDllInstance; } + +private: + // prohibit copying + CTooltipNotify(const CTooltipNotify& rhs); + CTooltipNotify& operator= (const CTooltipNotify& rhs); + +private: + static CTooltipNotify *s_pInstance; + static const char *s_szModuleNameOld; + static const char *s_szModuleName; + + const HINSTANCE m_hDllInstance; + const BOOL m_bNt50; + + struct SOptions { + BYTE bFirstRun; + BYTE bOffline; + BYTE bOnline; + BYTE bOther; + BYTE bTyping; + BYTE bIdle; + BYTE bConjSOLN; + BYTE bX2; + BYTE bAutoPos; + BYTE bBallonTip; + BYTE bTransp; + BYTE bTranspInput; + BYTE bAlpha; + BYTE bLDblClick; + BYTE bPrefixProto; + WORD wDuration; + WORD wXPos; + WORD wYPos; + WORD wStartupDelay; + BYTE bIgnoreNew; + BYTE bIgnoreUnknown; + } m_sOptions; + + struct STooltipData { + CTooltip *pTooltip; + UINT_PTR idTimer; + UINT uiTimeout; + HANDLE hContact; + int iStatus; + }; + + struct ProtoData { + const char* proto; + UINT_PTR timerId; + }; + + typedef std::vector TooltipsList; + typedef TooltipsList::iterator TooltipsListIter; + typedef TooltipsList::reverse_iterator TooltipsListRevIter; + TooltipsList m_TooltipsList; + + typedef std::vector MapTimerIdProto; + typedef MapTimerIdProto::iterator MapTimerIdProtoIter; + MapTimerIdProto m_mapTimerIdProto; + + MapTimerIdProtoIter FindProtoByTimer(UINT idTimer); + template TooltipsListIter FindBy(T STooltipData::* m, const T& value); + TCHAR *StatusToString(int iStatus, TCHAR *szStatus, int iBufSize); + TCHAR *MakeTooltipString(HANDLE hContact, int iStatus, TCHAR *szString, int iBufSize); + VOID MigrateSettings(); + void RegisterFonts(); + void GetFont(int iStatus, LOGFONT* lf, COLORREF* text, COLORREF* bg); + void ResetCList(HWND hwndDlg); + void LoadList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown); + void SaveList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown); + VOID LoadSettings(); + VOID SaveSettings(); + VOID ValidateSettings(); + VOID ReadSettingsFromDlg(HWND hDlg); + VOID WriteSettingsToDlg(HWND hDlg); + + VOID SuspendTimer(CTooltip *pTooltip); + VOID ResumeTimer(CTooltip *pTooltip); + VOID OnConnectionTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); + VOID OnTooltipTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime); + + // Dialog procedures + BOOL OptionsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + BOOL ProtosDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + BOOL ContactsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + static VOID CALLBACK ConnectionTimerProcWrapper(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) + { + CTooltipNotify::GetObjInstance()->OnConnectionTimer(hwnd, uMsg, idEvent, dwTime); + } + static VOID CALLBACK TooltipTimerProcWrapper(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) + { + CTooltipNotify::GetObjInstance()->OnTooltipTimer(hwnd, uMsg, idEvent, dwTime); + } + static BOOL CALLBACK OptionsDlgProcWrapper(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) + { + return CTooltipNotify::GetObjInstance()->OptionsDlgProc(hDlg, msg, wParam, lParam); + } + static BOOL CALLBACK ProtosDlgProcWrapper(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) + { + return CTooltipNotify::GetObjInstance()->ProtosDlgProc(hDlg, msg, wParam, lParam); + } + + static BOOL CALLBACK ContactsDlgProcWrapper(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) + { + return CTooltipNotify::GetObjInstance()->ContactsDlgProc(hDlg, msg, wParam, lParam); + } + +}; diff --git a/plugins/TooltipNotify/src/Utils.cpp b/plugins/TooltipNotify/src/Utils.cpp new file mode 100644 index 0000000000..ce73dbc59b --- /dev/null +++ b/plugins/TooltipNotify/src/Utils.cpp @@ -0,0 +1,32 @@ +// +// Utils.cpp +// + +#include "stdafx.h" +#include "Utils.h" + +BOOL IsNt50() +{ + WORD wOsVersion = LOWORD(GetVersion()); + BYTE bMajorVer = LOBYTE(wOsVersion); + BYTE bMinorVer = HIBYTE(wOsVersion); + + return (bMajorVer>=5 && bMinorVer>=0); +} + +void TruncateWithDots(TCHAR* szString, int iNewLen) +{ + assert(iNewLen >= 0); + + int iOrigLen = _tcslen(szString); + if (iNewLen < iOrigLen) + { + TCHAR* p = szString+iNewLen; + *p = _T('\0'); + for(int i=0; --p>=szString && i<3; i++) + { + *p = _T('.'); + } + } +} + diff --git a/plugins/TooltipNotify/src/Utils.h b/plugins/TooltipNotify/src/Utils.h new file mode 100644 index 0000000000..d1ad4d0fe7 --- /dev/null +++ b/plugins/TooltipNotify/src/Utils.h @@ -0,0 +1,8 @@ +// +// Utils.h +// + +#pragma once + +BOOL IsNt50(); +void TruncateWithDots(TCHAR* szString, int iNewLen); \ No newline at end of file diff --git a/plugins/TooltipNotify/src/main.cpp b/plugins/TooltipNotify/src/main.cpp new file mode 100644 index 0000000000..5695120354 --- /dev/null +++ b/plugins/TooltipNotify/src/main.cpp @@ -0,0 +1,218 @@ +/*///////////////////////////////////////////// + Tooltip Notify plugin for Miranda IM +*////////////////////////////////////////////// + +#include "stdafx.h" +#include "version.h" +#include "TooltipNotify.h" + +// {5906A545-F31A-4726-B48F-03A09F060318} +static const MUUID MIID_TOOLTIPNOTIFY_UNICODE = +{ 0x5906a545, 0xf31a, 0x4726, { 0xb4, 0x8f, 0x3, 0xa0, 0x9f, 0x6, 0x3, 0x18 } }; + +// {C4475C65-630F-4e70-980F-C0CA98767110} +static const MUUID MIID_TOOLTIPNOTIFY_ANSI = +{ 0xc4475c65, 0x630f, 0x4e70, { 0x98, 0xf, 0xc0, 0xca, 0x98, 0x76, 0x71, 0x10 } }; + +// {03CD82B6-0BB5-4f26-8EB4-06CD8ECD36FF} +static const MUUID MIID_TOOLTIPNOTIFY = +{ 0x3cd82b6, 0xbb5, 0x4f26, { 0x8e, 0xb4, 0x6, 0xcd, 0x8e, 0xcd, 0x36, 0xff } }; + +static int InitializeOptions(WPARAM wParam,LPARAM lParam); +static int ModulesLoaded(WPARAM wParam,LPARAM lParam); +static int ContactSettingChanged(WPARAM wParam,LPARAM lParam); +static int ProtoAck(WPARAM,LPARAM); +static int ProtoContactIsTyping(WPARAM wParam,LPARAM lParam); + + +// Globals +PLUGINLINK *pluginLink; // cannot be static since it is used for mim service calls + +static HANDLE g_hContactSettingChanged = 0; +static HANDLE g_hOptionsInitialize = 0; +static HANDLE g_hModulesLoaded = 0; +static HANDLE g_hProtoAck = 0; +static HANDLE g_hProtoContactIsTyping = 0; +static HINSTANCE g_hInstDLL = 0; +static bool g_bRightModule = false; // i.e. ansi for win9x, and unicode for winnt + +// Main global object +static CTooltipNotify *g_pTooltipNotify = 0; + + +//================================================================================ +// plugin init/deinit routines +//================================================================================ + +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch(fdwReason) + { + case DLL_PROCESS_ATTACH: + { + DisableThreadLibraryCalls(hInstDLL); + g_hInstDLL = hInstDLL; + + OSVERSIONINFO OsVersionInfo; + OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo); + GetVersionEx(&OsVersionInfo); + +#ifdef _UNICODE + g_bRightModule = (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); +#else + g_bRightModule = (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); +#endif + + break; + } + + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} + +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + static const MUUID interfaces[] = {MIID_TOOLTIPNOTIFY, MIID_LAST}; + return interfaces; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + static char szWrongUsage9x[] = + "Warning! You are trying to use unicode version of the plugin on win9x system! " + "It can not be working here. You must use ansi version of the plugin."; + + static char szWrongUsageNt[] = + "Warning! You are using ansi version of the plugin on a unicode-aware system. " + "It is recommended to use unicode version of the plugin."; + + static char szFunctionalDescription[] = + "Shows a small tooltip above system tray area when a contact status is changed."; + + + static PLUGININFOEX sPluginInfo = + { + sizeof(PLUGININFOEX), + "Tooltip Notify", + PLUGIN_MAKE_VERSION(MAJOR,MINOR,BUILD,REVISION), // major, minor, revision, build +#ifdef _UNICODE + g_bRightModule ? szFunctionalDescription : szWrongUsage9x, +#else + g_bRightModule ? szFunctionalDescription : szWrongUsageNt, +#endif + "perf", + "perf@mail333.com", + " 2004-2008 Gneedah software", + "http://addons.miranda-im.org/details.php?action=viewfile&id=1290", + UNICODE_AWARE, + 0, //doesn't replace anything built-in +#ifdef _UNICODE + MIID_TOOLTIPNOTIFY_UNICODE +#else + MIID_TOOLTIPNOTIFY_ANSI +#endif + }; + + return &sPluginInfo; +} + +extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion) +{ + PLUGININFOEX* pPluginInfoEx = MirandaPluginInfoEx(mirandaVersion); + + static PLUGININFO sPluginInfo = + { + sizeof(PLUGININFO), + pPluginInfoEx->shortName, + pPluginInfoEx->version, + pPluginInfoEx->description, + pPluginInfoEx->author, + pPluginInfoEx->authorEmail, + pPluginInfoEx->copyright, + pPluginInfoEx->homepage, + pPluginInfoEx->flags, + pPluginInfoEx->replacesDefaultModule + }; + + return &sPluginInfo; +} + + +extern "C" int __declspec(dllexport) Load(PLUGINLINK *pLink) +{ +#ifdef _UNICODE + if (!g_bRightModule) return 0; +#else + // ansi version can work ok on winnt platform +#endif + + pluginLink = pLink; + + g_pTooltipNotify = new CTooltipNotify(g_hInstDLL); + assert(g_pTooltipNotify!=0); + + g_hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); + + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + if (g_hContactSettingChanged) UnhookEvent(g_hContactSettingChanged); + if (g_hProtoContactIsTyping) UnhookEvent(g_hProtoContactIsTyping); + if (g_hProtoAck) UnhookEvent(g_hProtoAck); + if (g_hOptionsInitialize) UnhookEvent(g_hOptionsInitialize); + if (g_hModulesLoaded) UnhookEvent(g_hModulesLoaded); + delete g_pTooltipNotify; + + return 0; +} + + + +//================================================================================ +//================================================================================ +//================================================================================ + + +int ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + g_hContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged); + g_hProtoAck = HookEvent(ME_PROTO_ACK, ProtoAck); + g_hProtoContactIsTyping = HookEvent(ME_PROTO_CONTACTISTYPING, ProtoContactIsTyping); + g_hOptionsInitialize = HookEvent(ME_OPT_INITIALISE, InitializeOptions); + + return CTooltipNotify::GetObjInstance()->ModulesLoaded(wParam, lParam); +} + + +int ProtoContactIsTyping(WPARAM wParam, LPARAM lParam) +{ + return CTooltipNotify::GetObjInstance()->ProtoContactIsTyping(wParam, lParam); +} + + +int ProtoAck(WPARAM wParam, LPARAM lParam) +{ + return CTooltipNotify::GetObjInstance()->ProtoAck(wParam, lParam); +} + + +int ContactSettingChanged(WPARAM wParam, LPARAM lParam) +{ + return CTooltipNotify::GetObjInstance()->ContactSettingChanged(wParam, lParam); +} + + +int InitializeOptions(WPARAM wParam, LPARAM lParam) +{ + return CTooltipNotify::GetObjInstance()->InitializeOptions(wParam, lParam); +} + + + + + diff --git a/plugins/TooltipNotify/src/main.rc b/plugins/TooltipNotify/src/main.rc new file mode 100644 index 0000000000..fe1fbad85f --- /dev/null +++ b/plugins/TooltipNotify/src/main.rc @@ -0,0 +1,204 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PROTOS DIALOGEX 0, 0, 106, 138 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | + WS_CAPTION | WS_SYSMENU +CAPTION "Select protocols" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,28,117,50,14 + CONTROL "List1",IDC_PROTOS,"SysListView32",LVS_LIST | + LVS_SINGLESEL | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | + WS_BORDER | WS_TABSTOP,7,7,91,103 +END + +IDD_CONTACTS DIALOGEX 0, 0, 284, 234 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | + WS_CAPTION | WS_SYSMENU +CAPTION "Choose contacts..." +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Allow tooltip notifications for the following users:", + IDC_STATIC,8,9,268,9 + CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x3da,7,23,270, + 180,WS_EX_CLIENTEDGE + DEFPUSHBUTTON "OK",IDOK,171,213,50,14 + PUSHBUTTON "Cancel",IDCANCEL,227,213,50,14 +END + +IDD_OPTIONS DIALOGEX 0, 0, 316, 250 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Notify upon the following events",IDC_STATIC,5,7,304,32, + WS_GROUP + CONTROL "Online",IDC_ONLINE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,17,46,14 + CONTROL "Offline",IDC_OFFLINE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,66,17,46,14 + CONTROL "All other",IDC_OTHER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,117,17,52,14 + CONTROL "Typing",IDC_TYPING,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,174,17,51,14 + PUSHBUTTON "Protocols",IDC_SEL_PROTO,254,162,46,14 + LTEXT "Suppress notifications upon connection for",IDC_STATIC, + 120,93,137,9 + EDITTEXT IDC_DELAYONCONN,259,91,27,12,ES_RIGHT | ES_NUMBER + CONTROL "Spin1",IDC_DELAYONCONNSPIN,"msctls_updown32", + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS | UDS_NOTHOUSANDS,280,86,11,14 + LTEXT "sec",IDC_STATIC,290,93,12,10 + CONTROL "Prefix proto name",IDC_PREFIX_PROTO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,15,163,70,11 + GROUPBOX "Duration",IDC_GB_DURATION,5,43,304,30 + LTEXT "Show tooltip for",IDC_STATIC,15,55,51,10 + EDITTEXT IDC_DURATION,69,53,36,12,ES_RIGHT | ES_NUMBER + CONTROL "Spin1",IDC_DURATIONSPIN,"msctls_updown32", + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | + UDS_ARROWKEYS | UDS_NOTHOUSANDS,100,47,10,14 + LTEXT "ms",IDC_STATIC,109,55,14,10 + CONTROL "Duration x2 upon online event",IDC_X2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,159,55,137,10 + GROUPBOX "Double click on tooltip",IDC_GB_DBLCLICK,5,78,103,54 + CONTROL "Shows/Hides CList",IDC_RB_CLIST,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,15,93,83,11 + CONTROL "Opens message dialog",IDC_RB_MSGDLG,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,15,112,88,11 + GROUPBOX "Behavior",IDC_STATIC,113,78,196,54 + GROUPBOX "Misc",IDC_STATIC,5,136,304,44 + CONTROL "Obey 'Suppress online notification' settings", + IDC_CONJSOLN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119, + 112,164,11 + CONTROL "Auto positioning",IDC_AUTOPOS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,147,75,11 + CONTROL "Transparent input",IDC_TRANSP_INPUT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,96,147,81,11 + PUSHBUTTON "Preview",IDC_PREVIEW,201,162,46,14 + GROUPBOX "Translucency options (Windows 2000/XP only)", + IDC_GB_TRANSP,5,185,304,34 + CONTROL "Transparent tooltip",IDC_TRANSPARENCY,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,15,200,73,9 + CONTROL "Slider1",IDC_TRANSPARENCY_SLIDER,"msctls_trackbar32", + TBS_TOP | TBS_NOTICKS | WS_TABSTOP,94,199,170,11 + LTEXT "000%",IDC_TRANSPERC,273,201,22,9 + PUSHBUTTON "Contacts",IDC_IGNORE,254,144,46,14 + CONTROL "Idle",IDC_IDLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 227,17,51,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PROTOS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 99 + TOPMARGIN, 7 + BOTTOMMARGIN, 131 + END + + IDD_CONTACTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 277 + TOPMARGIN, 7 + BOTTOMMARGIN, 227 + END + + IDD_OPTIONS, DIALOG + BEGIN + VERTGUIDE, 5 + VERTGUIDE, 309 + HORZGUIDE, 246 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc" +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/TooltipNotify/src/resource.h b/plugins/TooltipNotify/src/resource.h new file mode 100644 index 0000000000..d67e8c5746 --- /dev/null +++ b/plugins/TooltipNotify/src/resource.h @@ -0,0 +1,47 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by main.rc +// +#define IDD_OPTIONS 101 +#define IDD_PROTOS 103 +#define IDD_CONTACTS 104 +#define IDC_ONLINE 1002 +#define IDC_OTHER 1003 +#define IDC_OFFLINE 1004 +#define IDC_TYPING 1006 +#define IDC_IDLE 1007 +#define IDC_X2 1011 +#define IDC_CONJSOLN 1012 +#define IDC_PROTOS 1014 +#define IDC_SEL_PROTO 1015 +#define IDC_AUTOPOS 1016 +#define IDC_TRANSPARENCY_SLIDER 1017 +#define IDC_TRANSPERC 1018 +#define IDC_TRANSPARENCY 1019 +#define IDC_GB_TRANSP 1020 +#define IDC_TRANSP_INPUT 1021 +#define IDC_PREVIEW 1025 +#define IDC_RB_CLIST 1026 +#define IDC_RB_MSGDLG 1027 +#define IDC_IGNORE 1028 +#define IDC_GB_DBLCLICK 1033 +#define IDC_BALLONTIP 1034 +#define IDC_GB_DURATION 1035 +#define IDC_PREFIX_PROTO 1039 +#define IDC_CLIST 1040 +#define IDC_DURATION 1283 +#define IDC_DURATIONSPIN 1284 +#define IDC_DELAYONCONN 1285 +#define IDC_DELAYONCONNSPIN 1286 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1042 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/TooltipNotify/src/stdafx.cpp b/plugins/TooltipNotify/src/stdafx.cpp new file mode 100644 index 0000000000..cb27709b24 --- /dev/null +++ b/plugins/TooltipNotify/src/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ttnotify.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/TooltipNotify/src/stdafx.h b/plugins/TooltipNotify/src/stdafx.h new file mode 100644 index 0000000000..d77c5a3037 --- /dev/null +++ b/plugins/TooltipNotify/src/stdafx.h @@ -0,0 +1,37 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _WIN32_WINNT 0x0500 + +// Windows header files +#include +#include +#include + +// C/C++ header files +#include +#include +#include + +// Miranda IM header files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) \ No newline at end of file diff --git a/plugins/TooltipNotify/src/version.h b/plugins/TooltipNotify/src/version.h new file mode 100644 index 0000000000..9de12d2cee --- /dev/null +++ b/plugins/TooltipNotify/src/version.h @@ -0,0 +1,11 @@ +/*********************************************************************/ +// +// Tooltip Notify version file +// +/*********************************************************************/ + + +#define MAJOR 0 +#define MINOR 6 +#define BUILD 0 +#define REVISION 47 diff --git a/plugins/TooltipNotify/src/version.rc b/plugins/TooltipNotify/src/version.rc new file mode 100644 index 0000000000..da191b4d06 --- /dev/null +++ b/plugins/TooltipNotify/src/version.rc @@ -0,0 +1,52 @@ +// +// version.rc2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#include "version.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MAJOR,MINOR,BUILD,REVISION + PRODUCTVERSION MAJOR,MINOR,BUILD,REVISION + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Shows a small tooltip above system tray area when a contact status is changed." + VALUE "CompanyName", "Gneedah software" + VALUE "FileDescription", "Tooltip Notify plugin for Miranda IM." + VALUE "FileVersion", "*,*,*,*" + VALUE "InternalName", "ttnotify.dll" + VALUE "LegalCopyright", " 2004-2008 Gneedah software" + VALUE "OriginalFilename", "ttnotify.dll" + VALUE "ProductName", "Tooltip Notify" + VALUE "ProductVersion", "*,*,*,*" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/TooltipNotify/ttnotify_10.sln b/plugins/TooltipNotify/ttnotify_10.sln new file mode 100644 index 0000000000..16bad206d7 --- /dev/null +++ b/plugins/TooltipNotify/ttnotify_10.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ttnotify", "ttnotify_10.vcxproj", "{1948EAEA-4C25-4F6B-AD9E-5891F656EADA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug-Unicode|Win32 = Debug-Unicode|Win32 + Release|Win32 = Release|Win32 + Release-Unicode|Win32 = Release-Unicode|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Debug|Win32.ActiveCfg = Debug|Win32 + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Debug|Win32.Build.0 = Debug|Win32 + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Debug-Unicode|Win32.ActiveCfg = Debug-Unicode|Win32 + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Debug-Unicode|Win32.Build.0 = Debug-Unicode|Win32 + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Release|Win32.ActiveCfg = Release|Win32 + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Release|Win32.Build.0 = Release|Win32 + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Release-Unicode|Win32.ActiveCfg = Release-Unicode|Win32 + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA}.Release-Unicode|Win32.Build.0 = Release-Unicode|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/TooltipNotify/ttnotify_10.vcxproj b/plugins/TooltipNotify/ttnotify_10.vcxproj new file mode 100644 index 0000000000..dc421eac67 --- /dev/null +++ b/plugins/TooltipNotify/ttnotify_10.vcxproj @@ -0,0 +1,262 @@ + + + + + Debug-Unicode + Win32 + + + Debug + Win32 + + + Release-Unicode + Win32 + + + Release + Win32 + + + + ttnotify + {1948EAEA-4C25-4F6B-AD9E-5891F656EADA} + ttnotify + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + false + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + false + D:\SVN\Miranda\Trunk\miranda\include;$(IncludePath) + + + + Updating revision... + SubWCRev . src\version.wcr src\version.h + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;TTNOTIFY_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + true + $(OutDir)ttnotify.pdb + Windows + false + + + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Updating revision... + SubWCRev . src\version.wcr src\version.h + + + Full + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;TTNOTIFY_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + OnlyExplicitInline + Size + true + + + NotSet + %(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + false + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + Updating revision... + SubWCRev . src\version.wcr src\version.h + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;TTNOTIFY_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + true + $(OutDir)ttnotify.pdb + Windows + false + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + + + + + Full + OnlyExplicitInline + true + Size + true + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;TTNOTIFY_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Fast + + + Level3 + ProgramDatabase + true + + + NotSet + %(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + false + + + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Use + Use + Use + Use + + + Use + Use + Use + Use + + + Create + Create + Create + Create + + + Use + Use + Use + Use + + + Use + Use + Use + AssemblyAndSourceCode + Use + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/TooltipNotify/ttnotify_10.vcxproj.filters b/plugins/TooltipNotify/ttnotify_10.vcxproj.filters new file mode 100644 index 0000000000..f756faf1c4 --- /dev/null +++ b/plugins/TooltipNotify/ttnotify_10.vcxproj.filters @@ -0,0 +1,79 @@ + + + + + {c12316ee-1d9e-470b-a9d4-2f96e30ea10d} + + + {9fe30d32-97fa-41fc-8586-9f52a8580112} + + + + + src + + + src + + + src + + + src + + + src + + + src + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + src + + + + + src + + + src + + + doc + + + doc + + + doc + + + doc + + + \ No newline at end of file diff --git a/plugins/UserGuide/UserGuide_10.sln b/plugins/UserGuide/UserGuide_10.sln new file mode 100644 index 0000000000..6e11d96610 --- /dev/null +++ b/plugins/UserGuide/UserGuide_10.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UserGuide", "UserGuide_10.vcxproj", "{92E3BDEE-DD17-4619-AD61-70C0ADE04217}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Debug|Win32.ActiveCfg = Debug|Win32 + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Debug|Win32.Build.0 = Debug|Win32 + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Debug|x64.ActiveCfg = Debug|x64 + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Debug|x64.Build.0 = Debug|x64 + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Release|Win32.ActiveCfg = Release|Win32 + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Release|Win32.Build.0 = Release|Win32 + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Release|x64.ActiveCfg = Release|x64 + {92E3BDEE-DD17-4619-AD61-70C0ADE04217}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/UserGuide/UserGuide_10.vcxproj b/plugins/UserGuide/UserGuide_10.vcxproj new file mode 100644 index 0000000000..ac05a53d99 --- /dev/null +++ b/plugins/UserGuide/UserGuide_10.vcxproj @@ -0,0 +1,285 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + UserGuide + {92E3BDEE-DD17-4619-AD61-70C0ADE04217} + UserGuide + + + + DynamicLibrary + false + MultiByte + + + DynamicLibrary + false + MultiByte + + + DynamicLibrary + false + MultiByte + true + + + DynamicLibrary + false + MultiByte + true + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + false + false + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + true + true + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/UserGuide.tlb + + + + + Full + AnySuitable + true + Size + false + false + true + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;UserGuide_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0419 + + + true + false + $(IntDir)UserGuide.pdb + false + + + $(IntDir)$(TargetName).lib + MachineX86 + true + true + + + $(IntDir)$(TargetName).xml + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/UserGuide.tlb + + + + + Full + AnySuitable + true + Size + false + false + true + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;UserGuide_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0419 + + + true + false + $(IntDir)UserGuide.pdb + false + + + $(IntDir)$(TargetName).lib + true + true + + + $(IntDir)$(TargetName).xml + + + true + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/UserGuide.tlb + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;UserGuide_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0419 + + + true + true + $(IntDir)UserGuide.pdb + false + + + $(IntDir)$(TargetName).lib + MachineX86 + + + $(IntDir)$(TargetName).xml + + + true + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/UserGuide.tlb + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;UserGuide_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + true + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x0419 + + + true + true + $(IntDir)UserGuide.pdb + false + + + $(IntDir)$(TargetName).lib + + + $(IntDir)$(TargetName).xml + + + true + + + + + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + \ No newline at end of file diff --git a/plugins/UserGuide/UserGuide_10.vcxproj.filters b/plugins/UserGuide/UserGuide_10.vcxproj.filters new file mode 100644 index 0000000000..a9fe7c62a4 --- /dev/null +++ b/plugins/UserGuide/UserGuide_10.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {dcd1a3fe-3ade-453c-9845-9cb074da6b5b} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {72da96a4-67f9-49cc-94d3-6730544c949f} + h;hpp;hxx;hm;inl + + + {34beb523-18cd-4f3d-85db-ec309fbf1d1a} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/plugins/UserGuide/commonheaders.h b/plugins/UserGuide/commonheaders.h new file mode 100644 index 0000000000..4f7479c2ef --- /dev/null +++ b/plugins/UserGuide/commonheaders.h @@ -0,0 +1,10 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MIID_USERGUIDE {0x297ec1e7, 0x41b7, 0x41f9, { 0xbb, 0x91, 0xef, 0xa9, 0x50, 0x28, 0xf1, 0x6c }} //297ec1e7-41b7-41f9-bb91-efa95028f16c diff --git a/plugins/UserGuide/main.c b/plugins/UserGuide/main.c new file mode 100644 index 0000000000..853658300c --- /dev/null +++ b/plugins/UserGuide/main.c @@ -0,0 +1,130 @@ +#include "commonheaders.h" + +struct MM_INTERFACE mmi; +HINSTANCE hInst; +PLUGINLINK *pluginLink; +HANDLE hModulesLoaded; + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + "User Guide Plugin", + PLUGIN_MAKE_VERSION(0,0,0,1), + "This plug-in adds the main menu item used to view miranda-im pack user guide.", + "Yasnovidyashii", + "yasnovidyashii@gmail.com", + " 2009 Mikhail Yuriev", + "http://miranda-im.org/", + 0, //not transient + 0, //doesn't replace anything built-in + // Generate your own unique id for your plugin. + // Do not use this UUID! + // Use uuidgen.exe to generate the uuuid + MIID_USERGUIDE +}; + +static INT_PTR ShowGuideFile(WPARAM wParam,LPARAM lParam) +{ + DBVARIANT dbv = {0}; + int iRes; + + LPCSTR pszEmptySting=""; + LPSTR pszDirName, pszDirNameEx, pszFileName,pszDivider; + + REPLACEVARSDATA dat = {0}; + dat.cbSize = sizeof( dat ); + dat.dwFlags = 0; + + pszDirName=(LPSTR)mir_alloc(250*sizeof(CHAR)); + pszFileName=(LPSTR)mir_alloc(250*sizeof(CHAR)); + + iRes = DBGetContactSettingString(NULL,"UserGuide","PathToHelpFile",&dbv); + + if (iRes!=0) + { + strcpy(pszDirName, "%miranda_path%\\Plugins"); + strcpy(pszFileName, "UserGuide.chm"); + } + else + if(strcmp((dbv.pszVal),pszEmptySting)==0) + { + strcpy(pszDirName, "%miranda_path%\\Plugins"); + strcpy(pszFileName, "UserGuide.chm"); + mir_free(dbv.pszVal); + } + else + { + pszDivider = strrchr(dbv.pszVal, '\\'); + if (pszDivider == NULL) + { + pszDirName = ""; + strncpy(pszFileName, dbv.pszVal, strlen(dbv.pszVal) ); + } + else + { + strncpy(pszFileName, pszDivider+1, strlen(dbv.pszVal)-strlen(pszDivider)-1); + pszFileName[strlen(dbv.pszVal)-strlen(pszDivider)-1] = 0; + strncpy(pszDirName, dbv.pszVal, pszDivider-dbv.pszVal); + pszDirName[pszDivider-dbv.pszVal] = 0; + } + mir_free(dbv.pszVal); + } + if (ServiceExists(MS_UTILS_REPLACEVARS)) + pszDirNameEx = (char *) CallService(MS_UTILS_REPLACEVARS,(WPARAM)pszDirName,(LPARAM)&dat); + else + pszDirNameEx = mir_strdup(pszDirName); + + ShellExecuteA(NULL,"open",pszFileName,NULL,pszDirNameEx,SW_SHOW); + mir_free(pszDirName); + mir_free(pszFileName); + mir_free(pszDirNameEx); + return 0; +} + +int ModulesLoaded(WPARAM wParam,LPARAM lParam) +{ + CLISTMENUITEM mi; + + CreateServiceFunction("UserGuide/ShowGuide",ShowGuideFile); + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize=sizeof(mi); + mi.position=500000; + mi.flags=0; + mi.hIcon=LoadSkinnedIcon(SKINICON_OTHER_HELP); + mi.pszName=LPGEN("User Guide"); + mi.pszService="UserGuide/ShowGuide"; + CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + return 0; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst=hinstDLL; + return TRUE; +} + + +__declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +static const MUUID interfaces[] = {MIID_USERGUIDE, MIID_LAST}; +__declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +int __declspec(dllexport) Load(PLUGINLINK *link) +{ + pluginLink=link; + mir_getMMI(&mmi); + hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED,ModulesLoaded); + return 0; +} + +int __declspec(dllexport) Unload(void) +{ + UnhookEvent(hModulesLoaded); + return 0; +} \ No newline at end of file diff --git a/plugins/w7ui/clistproxywindow.cpp b/plugins/w7ui/clistproxywindow.cpp new file mode 100644 index 0000000000..12e5b476ed --- /dev/null +++ b/plugins/w7ui/clistproxywindow.cpp @@ -0,0 +1,292 @@ +#include "headers.h" + +CClistProxyWindow *g_clistProxyWnd = 0; +extern ITaskbarList3 *g_pTaskbarList; + +CClistProxyWindow::CClistProxyWindow() : m_overlayEvents(5) +{ + g_clistProxyWnd = this; + + m_activeOverlay = 0; + m_overlayIcon = 0; + m_overlayText = 0; + + SetWindowText(hwnd(), _T("Miranda IM")); + SendMessage(hwnd(), WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)); + SendMessage(hwnd(), WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)); + + SetEventHook(ME_CLIST_STATUSMODECHANGE, &CClistProxyWindow::OnStatusModeChanged); + SetEventHook(ME_AV_MYAVATARCHANGED, &CClistProxyWindow::OnAvatarChanged); + SetEventHook(ME_SYSTEM_MODULESLOADED, &CClistProxyWindow::OnModulesLoaded); + SetEventHook(ME_PROTO_ACCLISTCHANGED, &CClistProxyWindow::OnAccListChanged); + + SetTimer(1, 500); +} + +CClistProxyWindow::~CClistProxyWindow() +{ + KillObjectEventHooks(this); +} + +int __cdecl CClistProxyWindow::OnStatusModeChanged(WPARAM wParam, LPARAM lParam) +{ + Update(); + return 0; +} +int __cdecl CClistProxyWindow::OnAvatarChanged(WPARAM wParam, LPARAM lParam) +{ + Update(); + return 0; +} +int __cdecl CClistProxyWindow::OnModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + Update(); + return 0; +} +int __cdecl CClistProxyWindow::OnAccListChanged(WPARAM wParam, LPARAM lParam) +{ + Update(); + return 0; +} + +HANDLE CClistProxyWindow::SetEventHook(char *evt, int (__cdecl CClistProxyWindow::*fn)(WPARAM, LPARAM)) +{ + return HookEventObj(evt, *(MIRANDAHOOKOBJ *)&fn, this); +} + +void CClistProxyWindow::Flash() +{ + FlashWindow(hwnd(), TRUE); +} + +void CClistProxyWindow::SetOverlayIcon(HICON hIcon) +{ + m_overlayIcon = hIcon; + m_overlayIconHandle = 0; +} + +void CClistProxyWindow::SetOverlayIconHandle(HANDLE hIcolibIcon) +{ + m_overlayIcon = 0; + m_overlayIconHandle = hIcolibIcon; +} + +void CClistProxyWindow::AddOverlayEvent(int idx) +{ + m_overlayEvents[idx].Push(); +} + +void CClistProxyWindow::RemoveOverlayEvent(int idx) +{ + m_overlayEvents[idx].Pop(); +} + +int CClistProxyWindow::AllocateOverlayEvent(HANDLE hIcolibIcon) +{ + m_overlayEvents.insert(new COverlayEventSlot(hIcolibIcon, _T("")), m_overlayEvents.getCount()); + return m_overlayEvents.getCount() - 1; +} + +void CClistProxyWindow::Update() +{ + AddButton(LoadSkinnedIcon(SKINICON_OTHER_MIRANDA), TranslateT("Menu"), -1); + + int nAccounts = 0; + PROTOACCOUNT **accounts; + ProtoEnumAccounts(&nAccounts, &accounts); + for (int i = 0; i < nAccounts; ++i) + { + if (!accounts[i]->bIsEnabled || !accounts[i]->bIsVisible || !accounts[i]->ppro || !(accounts[i]->ppro->GetCaps(PFLAGNUM_1) & PF1_IM)) + continue; + + HICON hIcon = LoadSkinnedProtoIcon(accounts[i]->szModuleName, CallProtoService(accounts[i]->szModuleName, PS_GETSTATUS, 0, 0)); + AddButton(hIcon, accounts[i]->tszAccountName, (INT_PTR)accounts[i]->tszAccountName); + } + UpdateButtons(g_pTaskbarList); + + InvalidateThumbnail(); +} + +void CClistProxyWindow::OnActivate(HWND hwndFrom) +{ + CallService(MS_CLIST_SHOWHIDE, 0, 0); + + HWND hwndClui = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); + if (hwndFrom != hwndClui && !IsIconic(hwndClui) && IsWindowVisible(hwndClui)) + SetForegroundWindow(hwndClui); + else + SetForegroundWindow(NULL); +} + +void CClistProxyWindow::OnToolbar(int id, INT_PTR data) +{ + POINT pt; GetCursorPos(&pt); + HMENU hMenu = NULL; + HWND hwndClui = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); + + switch (data) + { + case -1: + { + hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDMAIN, 0, 0); + break; + } + + default: + { + hMenu = (HMENU)CallService(MS_CLIST_MENUGETSTATUS, 0, 0); + int nItems = GetMenuItemCount(hMenu); + for (int i = 0; i < nItems; ++i) + { + TCHAR buf[128]; + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING|MIIM_SUBMENU; + mii.dwTypeData = buf; + mii.cch = SIZEOF(buf); + GetMenuItemInfo(hMenu, i, TRUE, &mii); + + if (mii.hSubMenu && !lstrcmp(mii.dwTypeData, (TCHAR*)data)) + { + hMenu = mii.hSubMenu; + break; + } + } + } + } + + SetForegroundWindow(hwndClui); + TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwndClui, NULL); +} + +void CClistProxyWindow::OnRenderThumbnail(int width, int height) +{ + HBITMAP hbmp = CreateDwmBitmap(width, height); + HDC hdc = CreateCompatibleDC(0); + SelectObject(hdc, hbmp); + + RGBQUAD rgb0, rgb1; + rgb0.rgbRed = 0; rgb0.rgbGreen = 0; rgb0.rgbBlue = 0; + rgb1.rgbRed = 19; rgb1.rgbGreen = 58; rgb1.rgbBlue = 89; + DrawGradient(hdc, 0, 0, width, height, &rgb0, &rgb1); + + HFONT hfntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + SetTextColor(hdc, RGB(255, 255, 255)); + SetBkMode(hdc, TRANSPARENT); + + RECT rc; + SIZE sz; + SetRect(&rc, 5, 5, width-10, height-10); + + int avatarWidth = 0; + int avatarHeight = 0; + if (true) + { + AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)""); + if (ace && (ace != (AVATARCACHEENTRY *)CALLSERVICE_NOTFOUND)) + { + if (ace->bmWidth < width / 4) + { + avatarWidth = ace->bmWidth; + avatarHeight = ace->bmHeight; + } else + { + avatarWidth = width / 4; + avatarHeight = avatarWidth * ace->bmHeight / ace->bmWidth; + } + + AVATARDRAWREQUEST avdr = {0}; + avdr.cbSize = sizeof(avdr); + avdr.hContact = NULL; + avdr.hTargetDC = hdc; + avdr.rcDraw = rc; + avdr.rcDraw.bottom = avdr.rcDraw.top + avatarHeight; + avdr.rcDraw.right = avdr.rcDraw.left + avatarWidth; + avdr.dwFlags = AVDRQ_FALLBACKPROTO | AVDRQ_FORCEALPHA | AVDRQ_OWNPIC; + avdr.szProto = ""; + + avdr.alpha = 255; + CallService(MS_AV_DRAWAVATAR, 0, (LPARAM)&avdr); + + rc.left += avatarWidth + 5; + } + } + + int nAccounts = 0; + PROTOACCOUNT **accounts; + ProtoEnumAccounts(&nAccounts, &accounts); + for (int i = 0; i < nAccounts; ++i) + { + if (!accounts[i]->bIsEnabled /*|| !accounts[i]->ppro || !(accounts[i]->ppro->GetCaps(PFLAGNUM_1) & PF1_IM)*/) + continue; + + char *proto = accounts[i]->szModuleName; + + if (true) + { + TCHAR name[128]; name[0] = 0; + + CONTACTINFO ci = {0}; + ci.cbSize = sizeof(ci); + ci.hContact = NULL; + ci.szProto = proto; + ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR; + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci)) + { + switch (ci.type) + { + case CNFT_ASCIIZ: + mir_sntprintf(name, SIZEOF(name), _T("%s - %s"), accounts[i]->tszAccountName, ci.pszVal); + mir_free((void *)ci.pszVal); + break; + case CNFT_DWORD: + mir_sntprintf(name, SIZEOF(name), _T("%s - %u"), accounts[i]->tszAccountName, ci.dVal); + break; + } + + } else + { + lstrcpyn(name, accounts[i]->tszAccountName, SIZEOF(name)); + } + + RECT rcText = rc; + rcText.left += 20; + DrawText(hdc, name, -1, &rcText, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK|DT_TOP|DT_SINGLELINE); + GetTextExtentPoint32(hdc, name, lstrlen(name), &sz); + } + + if (true) + { + HICON hIcon = LoadSkinnedProtoIcon(proto, CallProtoService(proto, PS_GETSTATUS, 0, 0)); + DrawIconEx(hdc, rc.left, rc.top + (sz.cy - 16) / 2, hIcon, 16, 16, 0, NULL, DI_NORMAL); + } + + rc.top += sz.cy + 5; + } + + SelectObject(hdc, hfntSave); + + DeleteDC(hdc); + MakeBitmapOpaque(hbmp); + SetThumbnail(hbmp); + DeleteObject(hbmp); +} + +void CClistProxyWindow::OnClose() +{ + CallService("CloseAction", NULL, NULL); +} + +void CClistProxyWindow::OnTimer(int id) +{ + HANDLE hIcolibItem = m_overlayIconHandle; + for (m_activeOverlay = (m_activeOverlay + 1) % (m_overlayEvents.getCount() + 1); m_activeOverlay < m_overlayEvents.getCount(); ++m_activeOverlay) + if (m_overlayEvents[m_activeOverlay]) + { + hIcolibItem = m_overlayEvents[m_activeOverlay].GetIcon(); + break; + } + + HICON hIcon = hIcolibItem ? (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hIcolibItem) : m_overlayIcon; + if (hIcon) g_pTaskbarList->SetOverlayIcon(hwnd(), hIcon, L""); +} diff --git a/plugins/w7ui/clistproxywindow.h b/plugins/w7ui/clistproxywindow.h new file mode 100644 index 0000000000..153c59089b --- /dev/null +++ b/plugins/w7ui/clistproxywindow.h @@ -0,0 +1,64 @@ +#ifndef clistproxywindow_h__ +#define clistproxywindow_h__ + +class CClistProxyWindow: public CDwmWindow +{ +public: + CClistProxyWindow(); + ~CClistProxyWindow(); + + void Flash(); + void SetOverlayIcon(HICON hIcon); + void SetOverlayIconHandle(HANDLE hIcolibIcon); + void AddOverlayEvent(int idx); + void RemoveOverlayEvent(int idx); + int AllocateOverlayEvent(HANDLE hIcolibIcon); + +private: + class COverlayEventSlot + { + private: + HANDLE m_hIcolibItem; + TCHAR *m_overlayText; + int m_level; + + public: + COverlayEventSlot(HANDLE hIcolibItem, TCHAR *overlayText) + { + m_hIcolibItem = hIcolibItem; + m_overlayText = mir_tstrdup(overlayText); + m_level = 0; + } + ~COverlayEventSlot() { mir_free(m_overlayText); } + void Push() { m_level++; } + void Pop() { if (m_level > 0) m_level--; } + operator bool() { return m_level > 0; } + HANDLE GetIcon() { return m_hIcolibItem; } + }; + + int m_activeOverlay; + HICON m_overlayIcon; + HANDLE m_overlayIconHandle; + TCHAR *m_overlayText; + OBJLIST m_overlayEvents; + + int __cdecl OnStatusModeChanged(WPARAM wParam, LPARAM lParam); + int __cdecl OnAvatarChanged(WPARAM wParam, LPARAM lParam); + int __cdecl OnModulesLoaded(WPARAM wParam, LPARAM lParam); + int __cdecl OnAccListChanged(WPARAM wParam, LPARAM lParam); + + HANDLE SetEventHook(char *evt, int (__cdecl CClistProxyWindow::*fn)(WPARAM, LPARAM)); + + void Update(); + +protected: + void OnActivate(HWND hwndFrom); + void OnToolbar(int id, INT_PTR data); + void OnRenderThumbnail(int width, int height); + void OnClose(); + void OnTimer(int id); +}; + +extern CClistProxyWindow *g_clistProxyWnd; + +#endif // clistproxywindow_h__ diff --git a/plugins/w7ui/dwmwindow.cpp b/plugins/w7ui/dwmwindow.cpp new file mode 100644 index 0000000000..2d8dd6e9e4 --- /dev/null +++ b/plugins/w7ui/dwmwindow.cpp @@ -0,0 +1,209 @@ +#include "headers.h" + +#define WNDCLASSNAME _T("W7DwmWndClass") + +CDwmWindow::CDwmWindow() +{ + GlobalInitWndClass(); + + m_btnInitialized = false; + m_btnCount = 0; + for (int i = 0; i < SIZEOF(m_btnInfo); ++i) + { + m_btnInfo[i].iId = i; + m_btnInfo[i].dwMask = THUMBBUTTONMASK(THB_FLAGS); + m_btnInfo[i].dwFlags = THUMBBUTTONFLAGS(THBF_HIDDEN); + m_btnData[i] = 0; + } + + m_hwnd = CreateWindowEx(WS_EX_APPWINDOW|WS_EX_NOACTIVATE, WNDCLASSNAME, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, g_hInst, NULL); + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); + SetWindowPos(m_hwnd, 0, -100000, -100000, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_SHOWWINDOW); + + BOOL val = 1; + DwmSetWindowAttribute(m_hwnd, DWMWA_HAS_ICONIC_BITMAP, &val, 4); + DwmSetWindowAttribute(m_hwnd, DWMWA_FORCE_ICONIC_REPRESENTATION, &val, 4); + dwmInvalidateIconicBitmaps(m_hwnd); +} + +HBITMAP CDwmWindow::CreateDwmBitmap(int width, int height) +{ + BITMAPINFO bi; + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = width; + bi.bmiHeader.biHeight = -height; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + return CreateDIBSection(0, &bi, DIB_RGB_COLORS, NULL, 0, 0); +} + +void CDwmWindow::MakeBitmapOpaque(HBITMAP hBmp) +{ + BITMAP bmp; + GetObject(hBmp, sizeof(bmp), &bmp); + if (bmp.bmBitsPixel != 32) return; + if (bmp.bmHeight < 0) bmp.bmHeight *= -1; + + int size = bmp.bmWidth * bmp.bmHeight * 4; + BYTE *data = new BYTE[size]; + GetBitmapBits(hBmp, size, data); + for (int i = 3; i < size; i += 4) + data[i] = 255; + SetBitmapBits(hBmp, size, data); + delete [] data; + +} + +void CDwmWindow::DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1) +{ + int oldMode = SetBkMode(hdc, OPAQUE); + COLORREF oldColor = SetBkColor(hdc, 0); + + RECT rc; SetRect(&rc, x, 0, x+width, 0); + for (int i=y+height; --i >= y; ) { + COLORREF color = RGB( + ((height-i-1)*rgb0->rgbRed + i*rgb1->rgbRed) / height, + ((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height, + ((height-i-1)*rgb0->rgbBlue + i*rgb1->rgbBlue) / height); + rc.top = rc.bottom = i; + ++rc.bottom; + SetBkColor(hdc, color); + ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0); + } + + SetBkMode(hdc, oldMode); + SetBkColor(hdc, oldColor); +} + +bool CDwmWindow::AddButton(HICON hIcon, TCHAR *text, INT_PTR data, DWORD flags) +{ + if (m_btnCount == SIZEOF(m_btnInfo)) return false; + m_btnInfo[m_btnCount].dwMask = THUMBBUTTONMASK(THB_ICON|THB_TOOLTIP|THB_FLAGS); + m_btnInfo[m_btnCount].hIcon = hIcon; + lstrcpyn(m_btnInfo[m_btnCount].szTip, text, SIZEOF(m_btnInfo[m_btnCount].szTip)); + m_btnInfo[m_btnCount].dwFlags = THUMBBUTTONFLAGS(flags); + m_btnData[m_btnCount] = data; + m_btnCount++; + return true; +} + +void CDwmWindow::UpdateButtons(ITaskbarList3 *p) +{ + if (m_btnInitialized) + p->ThumbBarUpdateButtons(hwnd(), SIZEOF(m_btnInfo), m_btnInfo); + else + p->ThumbBarAddButtons(hwnd(), SIZEOF(m_btnInfo), m_btnInfo); + + m_btnCount = 0; // reset this for next iteration + m_btnInitialized = true; +} + +void CDwmWindow::SetTimer(int id, int timeout) +{ + ::SetTimer(m_hwnd, id, timeout, NULL); +} + +void CDwmWindow::KillTimer(int id) +{ + ::KillTimer(m_hwnd, id); +} + +void CDwmWindow::InvalidateThumbnail() +{ + dwmInvalidateIconicBitmaps(m_hwnd); +} + +void CDwmWindow::SetPreview(HBITMAP hbmp, int x, int y) +{ + POINT pt = { x, y }; + dwmSetIconicLivePreviewBitmap(m_hwnd, hbmp, &pt, 0); +} + +void CDwmWindow::SetThumbnail(HBITMAP hbmp) +{ + dwmSetIconicThumbnail(m_hwnd, hbmp, 0); +} + +LRESULT CDwmWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_ACTIVATE: + { + if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) + { + OnActivate((HWND)wParam); + } + break; + } + + case WM_CLOSE: + { + OnClose(); + return FALSE; + } + + case WM_DWMSENDICONICLIVEPREVIEWBITMAP: + { + OnRenderPreview(); + break; + } + + case WM_DWMSENDICONICTHUMBNAIL: + { + int width = HIWORD(lParam); + int height = LOWORD(lParam); + OnRenderThumbnail(width, height); + break; + } + + case WM_TIMER: + { + OnTimer(wParam); + break; + } + + case WM_COMMAND: + { + if (HIWORD(wParam) == THBN_CLICKED) + OnToolbar(LOWORD(wParam), m_btnData[LOWORD(wParam)]); + break; + } + } + + return DefWindowProc(m_hwnd, msg, wParam, lParam); +} + +void CDwmWindow::GlobalInitWndClass() +{ + static bool bInitialized = false; + if (bInitialized) return; + + WNDCLASSEX wcl = {0}; + wcl.cbSize = sizeof(wcl); + wcl.lpfnWndProc = GlobalWndProc; + 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 = WNDCLASSNAME; + wcl.hIconSm = NULL; + RegisterClassEx(&wcl); +} + +LRESULT CALLBACK CDwmWindow::GlobalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CDwmWindow *wnd = (CDwmWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!wnd) return DefWindowProc(hwnd, msg, wParam, lParam); + if (msg == WM_DESTROY) + { + delete wnd; + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return wnd->WndProc(msg, wParam, lParam); +} \ No newline at end of file diff --git a/plugins/w7ui/dwmwindow.h b/plugins/w7ui/dwmwindow.h new file mode 100644 index 0000000000..e795823247 --- /dev/null +++ b/plugins/w7ui/dwmwindow.h @@ -0,0 +1,59 @@ +#ifndef dwmwindow_h__ +#define dwmwindow_h__ + +class CDwmWindow +{ +public: + CDwmWindow(); + virtual ~CDwmWindow() {} + + HWND hwnd() { return m_hwnd; } + + template + static TWindow *GetWindow(HWND hwnd) + { + return (TWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + } + +protected: + // events + virtual void OnActivate(HWND hwndFrom) {} + virtual void OnClose() {} + virtual void OnRenderThumbnail(int mzxWidth, int maxHeight) {} + virtual void OnRenderPreview() {} + virtual void OnTimer(int id) {} + virtual void OnToolbar(int id, INT_PTR data) {} + + // timer stuff + void SetTimer(int id, int timeout); + void KillTimer(int id); + + // manage thumbnail and aero peek + void InvalidateThumbnail(); + void SetPreview(HBITMAP hbmp, int x, int y); + void SetThumbnail(HBITMAP hbmp); + + // manage toolbar + bool AddButton(HICON hIcon, TCHAR *text, INT_PTR data, DWORD flags = THBF_ENABLED); + void UpdateButtons(ITaskbarList3 *p); + + //utilities + static HBITMAP CreateDwmBitmap(int width, int height); + static void MakeBitmapOpaque(HBITMAP hBmp); + static void DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1); + +private: + HWND m_hwnd; + + bool m_btnInitialized; + int m_btnCount; + THUMBBUTTON m_btnInfo[7]; + INT_PTR m_btnData[7]; + + LRESULT CALLBACK WndProc(UINT msg, WPARAM wParam, LPARAM lParam); + + static void GlobalInitWndClass(); + static LRESULT CALLBACK GlobalWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +}; + +#endif // dwmwindow_h__ \ No newline at end of file diff --git a/plugins/w7ui/headers.h b/plugins/w7ui/headers.h new file mode 100644 index 0000000000..55a3480dbd --- /dev/null +++ b/plugins/w7ui/headers.h @@ -0,0 +1,81 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2003 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. +*/ + +#define _CRT_SECURE_NO_DEPRECATE + +#if defined(UNICODE) && !defined(_UNICODE) + #define _UNICODE +#endif + +#include +#define _WIN32_WINNT 0x0501 +#include +#include +#include +#include + +#include +#include +#include + +#define MIRANDA_VER 0x800 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "m_w7ui.h" + +#include "win7api.h" + +#include "jumplistarray.h" +#include "jumplistbuilder.h" +#include "jumplist.h" + +#include "subclassmgr.h" +#include "dwmwindow.h" +#include "clistproxywindow.h" +#include "srmmproxywindow.h" + +extern HINSTANCE g_hInst; diff --git a/plugins/w7ui/jumplist.cpp b/plugins/w7ui/jumplist.cpp new file mode 100644 index 0000000000..4fd1a68e9d --- /dev/null +++ b/plugins/w7ui/jumplist.cpp @@ -0,0 +1,123 @@ +#include "headers.h" + +static HANDLE hProcessJumpList = 0; + +static void ProcessJumpListImpl(char *arg) +{ + char *prefix = mir_strdup(arg); + char *argument = strchr(prefix, ':'); + if (argument) *argument++ = 0; + NotifyEventHooks(hProcessJumpList, (WPARAM)prefix, (LPARAM)argument); + mir_free(prefix); +} + +static LRESULT CALLBACK MirandaJumpListProcessorWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_COPYDATA: + { + COPYDATASTRUCT *data = (COPYDATASTRUCT *)lParam; + ProcessJumpListImpl((char *)data->lpData); + break; + } + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + +extern "C" __declspec(dllexport) void ProcessJumpList(HWND, HINSTANCE, LPSTR arg, UINT) +{ + char miranda_path[MAX_PATH]; + GetModuleFileNameA(g_hInst, miranda_path, SIZEOF(miranda_path)); + lstrcpyA(strstr(_strlwr(miranda_path), "plugins\\w7ui.dll"), "miranda32.exe"); + + if (HWND hwnd = FindWindowA("MirandaJumpListProcessor", miranda_path)) + { + COPYDATASTRUCT data = {0}; + data.dwData = 0; + data.cbData = lstrlenA(arg) + 1; + data.lpData = arg; + SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&data); + } else + { + char command[MAX_PATH * 2]; + wsprintfA(command, "\"%s\" -jump %s", miranda_path, arg); + WinExec(command, SW_SHOWNORMAL); + } +} + +static int OnJumpListItems(WPARAM, LPARAM lParam) +{ + WCHAR *category = (WCHAR *)lParam; + + if (!category) + { + MJumpList_AddItem(SKINICON_STATUS_ONLINE, TranslateT("Online"), L"status", L"online"); + MJumpList_AddItem(SKINICON_STATUS_DND, TranslateT("Do not disturb"), L"status", L"dnd"); + MJumpList_AddItem(SKINICON_STATUS_INVISIBLE, TranslateT("Invisible"), L"status", L"invisible"); + MJumpList_AddItem(SKINICON_STATUS_OFFLINE, TranslateT("Offline"), L"status", L"offline"); + return 0; + } + + return 0; +} + +static int OnJumpListProcess(WPARAM wParam, LPARAM lParam) +{ + char *prefix = (char *)wParam; + char *argument = (char *)lParam; + + if (!lstrcmpA(prefix, "status")) + { + if (!lstrcmpA(argument, "online")) + { + CallService(MS_CLIST_SETSTATUSMODE, ID_STATUS_ONLINE, 0); + } else + if (!lstrcmpA(argument, "dnd")) + { + CallService(MS_CLIST_SETSTATUSMODE, ID_STATUS_DND, 0); + } else + if (!lstrcmpA(argument, "invisible")) + { + CallService(MS_CLIST_SETSTATUSMODE, ID_STATUS_INVISIBLE, 0); + } else + if (!lstrcmpA(argument, "offline")) + { + CallService(MS_CLIST_SETSTATUSMODE, ID_STATUS_OFFLINE, 0); + } + return 1; + } + + return 0; +} + +void LoadJumpList() +{ + hProcessJumpList = CreateHookableEvent(ME_JUMPLIST_PROCESS); +} + +void InitJumpList() +{ + HookEvent(ME_JUMPLIST_BUILDITEMS, OnJumpListItems); + HookEvent(ME_JUMPLIST_PROCESS, OnJumpListProcess); + + if (char *cmd = strstr(GetCommandLineA(), " -jump ")) + ProcessJumpListImpl(cmd + 7); + + WNDCLASSEX wcx = {0}; + wcx.cbSize = sizeof(wcx); + wcx.lpfnWndProc = MirandaJumpListProcessorWndProc; + wcx.hInstance = g_hInst; + wcx.lpszClassName = _T("MirandaJumpListProcessor"); + RegisterClassEx(&wcx); + + char miranda_path[MAX_PATH]; + GetModuleFileNameA(g_hInst, miranda_path, SIZEOF(miranda_path)); + lstrcpyA(strstr(_strlwr(miranda_path), "plugins\\w7ui.dll"), "miranda32.exe"); + + HWND hwnd = CreateWindowA("MirandaJumpListProcessor", miranda_path, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, g_hInst, NULL); + ShowWindow(hwnd, SW_HIDE); + + CJumpListBuilder::Rebuild(); +} diff --git a/plugins/w7ui/jumplist.h b/plugins/w7ui/jumplist.h new file mode 100644 index 0000000000..de5a6f0548 --- /dev/null +++ b/plugins/w7ui/jumplist.h @@ -0,0 +1,7 @@ +#ifndef jumplist_h__ +#define jumplist_h__ + +void LoadJumpList(); +void InitJumpList(); + +#endif // jumplist_h__ diff --git a/plugins/w7ui/jumplistarray.cpp b/plugins/w7ui/jumplistarray.cpp new file mode 100644 index 0000000000..669a7784ef --- /dev/null +++ b/plugins/w7ui/jumplistarray.cpp @@ -0,0 +1,214 @@ +#include "headers.h" + +#pragma pack(push, 1) +typedef struct +{ + BYTE bWidth; // Width, in pixels, of the image + BYTE bHeight; // Height, in pixels, of the image + BYTE bColorCount; // Number of colors in image (0 if >=8bpp) + BYTE bReserved; // Reserved ( must be 0) + WORD wPlanes; // Color Planes + WORD wBitCount; // Bits per pixel + DWORD dwBytesInRes; // How many bytes in this resource? + DWORD dwImageOffset; // Where in the file is this image? +} ICONDIRENTRY, *LPICONDIRENTRY; + +typedef struct +{ + WORD idReserved; // Reserved (must be 0) + WORD idType; // Resource Type (1 for icons) + WORD idCount; // How many images? + ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em) +} ICONDIR, *LPICONDIR; +#pragma pack(pop) + +static void SaveIconToFile(HICON hIcon, TCHAR *szFile) +{ + ICONINFO iconInfo = {0}; + BITMAP bmpColor, bmpMask; + HANDLE hFile = 0; + HANDLE hMap = 0; + BYTE *pFile = 0; + + GetIconInfo(hIcon, &iconInfo); + GetObject(iconInfo.hbmColor, sizeof(bmpColor), &bmpColor); + GetObject(iconInfo.hbmMask, sizeof(bmpMask), &bmpMask); + + do + { + if (bmpColor.bmBitsPixel <= 8) break; + + DWORD dwColorSize = bmpColor.bmWidthBytes * bmpColor.bmHeight; + DWORD dwMaskSize = bmpMask.bmWidthBytes * bmpMask.bmHeight; + DWORD dwFileSize = sizeof(ICONDIR) + sizeof(BITMAPINFOHEADER) + dwColorSize + dwMaskSize; + + hFile = CreateFile(szFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) break; + hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwFileSize, NULL); + if (!hMap) break; + pFile = (BYTE *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0 ,0); + if (!pFile) break; + + ICONDIR iconDir = {0}; + iconDir.idCount = 1; + iconDir.idType = 1; + iconDir.idEntries[0].bWidth = bmpColor.bmWidth; + iconDir.idEntries[0].bHeight = bmpColor.bmHeight; + iconDir.idEntries[0].bColorCount = 0; + iconDir.idEntries[0].wPlanes = bmpColor.bmPlanes; + iconDir.idEntries[0].wBitCount = bmpColor.bmBitsPixel; + iconDir.idEntries[0].dwBytesInRes = sizeof(BITMAPINFOHEADER) + dwColorSize + dwMaskSize; + iconDir.idEntries[0].dwImageOffset = sizeof(ICONDIR); + MoveMemory(pFile, &iconDir, sizeof(ICONDIR)); + + BITMAPINFOHEADER iconBmp = {0}; + iconBmp.biSize = sizeof(iconBmp); + iconBmp.biWidth = bmpColor.bmWidth; + iconBmp.biHeight = bmpColor.bmHeight + bmpMask.bmHeight; + iconBmp.biPlanes = bmpColor.bmPlanes; + iconBmp.biBitCount = bmpColor.bmBitsPixel; + iconBmp.biSizeImage = dwColorSize + dwMaskSize; + MoveMemory(pFile + sizeof(ICONDIR), &iconBmp, sizeof(BITMAPINFOHEADER)); + + BYTE *buf = (BYTE *)mir_alloc(dwColorSize); + GetBitmapBits(iconInfo.hbmColor, dwColorSize, buf); + for (int row = 0; row < bmpColor.bmHeight; ++row) + { + MoveMemory( + pFile + sizeof(ICONDIR) + sizeof(BITMAPINFOHEADER) + row * bmpColor.bmWidthBytes, + buf + (bmpColor.bmHeight - row - 1) * bmpColor.bmWidthBytes, + bmpColor.bmWidthBytes); + } + mir_free(buf); + + GetBitmapBits(iconInfo.hbmMask, dwMaskSize, pFile + sizeof(ICONDIR) + sizeof(BITMAPINFOHEADER) + dwColorSize); + } while(0); + + DeleteObject(iconInfo.hbmColor); + DeleteObject(iconInfo.hbmMask); + + if (pFile) UnmapViewOfFile(pFile); + if (hMap) CloseHandle(hMap); + if (hFile && hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); +} + +CJumpListArray::CJumpListArray() +{ + CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER, IID_IObjectCollection, (void **)&m_pObjects); +} + +CJumpListArray::~CJumpListArray() +{ + if (m_pObjects) m_pObjects->Release(); +} + +void CJumpListArray::AddItemImpl(TCHAR *icon, int iIcon, TCHAR *title, TCHAR *path, TCHAR *args) +{ + IShellLink *link = NewShellLink(icon, iIcon, title, path, args); + m_pObjects->AddObject(link); + link->Release(); +} + +void CJumpListArray::AddItem(char *mir_icon, TCHAR *title, TCHAR *path, TCHAR *args) +{ + TCHAR icon[MAX_PATH]; int iIcon; + LoadMirandaIcon(mir_icon, icon, &iIcon); + AddItemImpl(icon, iIcon, title, path, args); +} + +void CJumpListArray::AddItem(int skinicon, TCHAR *title, TCHAR *path, TCHAR *args) +{ + TCHAR icon[MAX_PATH]; int iIcon; + LoadMirandaIcon(skinicon, icon, &iIcon); + AddItemImpl(icon, iIcon, title, path, args); +} + +void CJumpListArray::AddItem(char *proto, int status, TCHAR *title, TCHAR *path, TCHAR *args) +{ + TCHAR icon[MAX_PATH]; int iIcon; + LoadMirandaIcon(proto, status, icon, &iIcon); + AddItemImpl(icon, iIcon, title, path, args); +} + +IObjectArray *CJumpListArray::GetArray() +{ + IObjectArray *result = NULL; + m_pObjects->QueryInterface(IID_IObjectArray, (void **)&result); + return result; +} + +bool CJumpListArray::LoadMirandaIcon(char *mir_icon, TCHAR *icon, int *id) +{ + *id = 0; + + TCHAR *path = Utils_ReplaceVarsT(_T("%miranda_userdata%\\w7ui.IconCache")); + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)path); + + TCHAR *name = mir_a2t(mir_icon); + for (TCHAR *ch = name; *ch; ++ch) if (_tcschr(_T("\\/:*?<>|"), *ch)) *ch = _T('_'); + mir_sntprintf(icon, MAX_PATH, _T("%s\\%s.ico"), path, name); + + mir_free(name); + mir_free(path); + + HICON hIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)mir_icon); + SaveIconToFile(hIcon, icon); + + return true; +} + +bool CJumpListArray::LoadMirandaIcon(int skinicon, TCHAR *icon, int *id) +{ + *id = 0; + + TCHAR *path = Utils_ReplaceVarsT(_T("%miranda_userdata%\\w7ui.IconCache")); + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)path); + mir_sntprintf(icon, MAX_PATH, _T("%s\\skinicon$%d.ico"), path, skinicon); + mir_free(path); + + HICON hIcon = LoadSkinnedIcon(skinicon); + SaveIconToFile(hIcon, icon); + + return true; +} + +bool CJumpListArray::LoadMirandaIcon(char *proto, int status, TCHAR *icon, int *id) +{ + *id = 0; + + TCHAR *path = Utils_ReplaceVarsT(_T("%miranda_userdata%\\w7ui.IconCache")); + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)path); + mir_sntprintf(icon, MAX_PATH, _T("%s\\skinprotoicon$") _T(TCHAR_STR_PARAM) _T("$%d.ico"), path, proto, status); + mir_free(path); + + HICON hIcon = LoadSkinnedProtoIcon(proto, status); + SaveIconToFile(hIcon, icon); + + return true; +} + +IShellLink *CJumpListArray::NewShellLink(TCHAR *icon, int iIcon, TCHAR *title, TCHAR *path, TCHAR *args) +{ + IShellLink *pShellLink = NULL; + CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&pShellLink); + + pShellLink->SetPath(path); + pShellLink->SetIconLocation(icon, iIcon); + pShellLink->SetArguments(args); + pShellLink->SetShowCmd(SW_SHOWDEFAULT); + + IPropertyStore *pPropStore = NULL; + if (SUCCEEDED(pShellLink->QueryInterface(IID_IPropertyStore, (void **)&pPropStore))) + { + PROPVARIANT pv; + + InitPropVariantFromString(title, &pv); + pPropStore->SetValue(PKEY_Title, pv); + PropVariantClear(&pv); + + pPropStore->Commit(); + pPropStore->Release(); + } + + return pShellLink; +} \ No newline at end of file diff --git a/plugins/w7ui/jumplistarray.h b/plugins/w7ui/jumplistarray.h new file mode 100644 index 0000000000..c9f2a8b979 --- /dev/null +++ b/plugins/w7ui/jumplistarray.h @@ -0,0 +1,29 @@ +#ifndef jumplistarray_h__ +#define jumplistarray_h__ + +class CJumpListArray +{ +private: + IObjectCollection *m_pObjects; + +public: + CJumpListArray(); + ~CJumpListArray(); + + void AddItem(char *mir_icon, TCHAR *title, TCHAR *path, TCHAR *args); + void AddItem(int skinicon, TCHAR *title, TCHAR *path, TCHAR *args); + void AddItem(char *proto, int skinicon, TCHAR *title, TCHAR *path, TCHAR *args); + + IObjectArray *GetArray(); + +private: + void AddItemImpl(TCHAR *icon, int iIcon, TCHAR *title, TCHAR *path, TCHAR *args); + + bool LoadMirandaIcon(char *mir_icon, TCHAR *icon, int *id); + bool LoadMirandaIcon(int skinicon, TCHAR *icon, int *id); + bool LoadMirandaIcon(char *proto, int status, TCHAR *icon, int *id); + + static IShellLink *NewShellLink(TCHAR *icon, int iIcon, TCHAR *title, TCHAR *path, TCHAR *args); +}; + +#endif // jumplistarray_h__ diff --git a/plugins/w7ui/jumplistbuilder.cpp b/plugins/w7ui/jumplistbuilder.cpp new file mode 100644 index 0000000000..5e5f1d9f65 --- /dev/null +++ b/plugins/w7ui/jumplistbuilder.cpp @@ -0,0 +1,127 @@ +#include "headers.h" + +CJumpListBuilder *CJumpListBuilder::m_instance = 0; + +CJumpListBuilder::CJumpListBuilder() +{ + m_hBuildCategories = CreateHookableEvent(ME_JUMPLIST_BUILDCATEGORIES); + m_hBuildItems = CreateHookableEvent(ME_JUMPLIST_BUILDITEMS); + CreateSvc(MS_JUMPLIST_REBUILD, &CJumpListBuilder::Rebuild); + CreateSvc(MS_JUMPLIST_ADDCATEGORY, &CJumpListBuilder::AddCategory); + CreateSvc(MS_JUMPLIST_ADDITEM, &CJumpListBuilder::AddItem); +} + +CJumpListBuilder::~CJumpListBuilder() +{ + KillObjectServices(this); + DestroyHookableEvent(m_hBuildCategories); + DestroyHookableEvent(m_hBuildItems); +} + +void CJumpListBuilder::BuildJumpList() +{ + m_lists = new LIST(5, _tcscmp); + NotifyEventHooks(m_hBuildCategories, 0, 0); + + UINT maxSlots; + IObjectArray *pRemoved; + CoCreateInstance(CLSID_CustomDestinationList, NULL, CLSCTX_INPROC_SERVER, IID_ICustomDestinationList, (void **)&m_pList); + m_pList->BeginList(&maxSlots, IID_IObjectArray, (void **)&pRemoved); + BuildCategory(NULL); + for (int i = 0; i < m_lists->getCount(); ++i) + BuildCategory((*m_lists)[i]); + m_pList->CommitList(); + m_pList->Release(); + pRemoved->Release(); + + m_lists->destroy(); + delete m_lists; +} + +int __cdecl CJumpListBuilder::Rebuild(WPARAM wParam, LPARAM lParam) +{ + BuildJumpList(); + return 0; +} + +int __cdecl CJumpListBuilder::AddCategory(WPARAM wParam, LPARAM lParam) +{ + TCHAR *category = (TCHAR *)lParam; + if (!m_lists->find(category)) m_lists->insert(mir_wstrdup(category)); + return 0; +} + +int __cdecl CJumpListBuilder::AddItem(WPARAM wParam, LPARAM lParam) +{ + MIRANDAJUMPLISTITEM *item = (MIRANDAJUMPLISTITEM *)lParam; + switch (item->iconSource) + { + case MIS_ICOLIB: + m_pCurrentList->AddItem(item->iconName, item->szTitle, _T("rundll32.exe"), BuildJumpListCommand(item->szPrefix, item->szArgument)); + break; + case MIS_GENERAL: + m_pCurrentList->AddItem(item->iconIdx, item->szTitle, _T("rundll32.exe"), BuildJumpListCommand(item->szPrefix, item->szArgument)); + break; + case MIS_PROTOCOL: + m_pCurrentList->AddItem(item->iconName, item->iconIdx, item->szTitle, _T("rundll32.exe"), BuildJumpListCommand(item->szPrefix, item->szArgument)); + break; + } + return 0; +} + +void CJumpListBuilder::BuildCategory(TCHAR *category) +{ + m_pCurrentList = new CJumpListArray; + NotifyEventHooks(m_hBuildItems, 0, (LPARAM)category); + + if (category) + m_pList->AppendCategory(category, m_pCurrentList->GetArray()); + else + m_pList->AddUserTasks(m_pCurrentList->GetArray()); + delete m_pCurrentList; + +} + +TCHAR *CJumpListBuilder::BuildJumpListCommand(TCHAR *prefix, TCHAR *argument) +{ + TCHAR path[MAX_PATH]; + GetModuleFileName(g_hInst, path, SIZEOF(path)); + mir_sntprintf(m_cmdBuf, SIZEOF(m_cmdBuf), _T("\"%s\",ProcessJumpList %s:%s"), path, prefix, argument); + return m_cmdBuf; +} + +HANDLE CJumpListBuilder::CreateSvc(char *svc, int (__cdecl CJumpListBuilder::*fn)(WPARAM, LPARAM)) +{ + return CreateServiceFunctionObj(svc, *(MIRANDASERVICEOBJ *)&fn, this); +} + +/* +static TCHAR *BuildJumpListCommand(TCHAR *buf, int size, TCHAR *arg); + +static void SetupTasks() +{ + TCHAR buf[MAX_PATH * 2]; + + CJumpListArray tasks; + tasks.AddItem(SKINICON_STATUS_ONLINE, TranslateT("Online"), _T("rundll32.exe"), BuildJumpListCommand(buf, SIZEOF(buf), _T("status:online"))); + tasks.AddItem(SKINICON_STATUS_DND, TranslateT("Do not disturb"), _T("rundll32.exe"), BuildJumpListCommand(buf, SIZEOF(buf), _T("status:dnd"))); + tasks.AddItem(SKINICON_STATUS_INVISIBLE, TranslateT("Invisible"), _T("rundll32.exe"), BuildJumpListCommand(buf, SIZEOF(buf), _T("status:invisible"))); + tasks.AddItem(SKINICON_STATUS_OFFLINE, TranslateT("Offline"), _T("rundll32.exe"), BuildJumpListCommand(buf, SIZEOF(buf), _T("status:offline"))); + +// CJumpListArray contacts; +// contacts.AddItem("core_status_*0", TranslateT("Nickname"), L"taskhost.exe", L"profile.dat -contact:hcontact"); + + UINT maxSlots; + IObjectArray *pRemoved; + + ICustomDestinationList *pList; + CoCreateInstance(CLSID_CustomDestinationList, NULL, CLSCTX_INPROC_SERVER, IID_ICustomDestinationList, (void **)&pList); + pList->BeginList(&maxSlots, IID_IObjectArray, (void **)&pRemoved); + pList->AddUserTasks(tasks.GetArray()); +// pList->AppendCategory(L"Contacts", contacts.GetArray()); + pList->CommitList(); + pList->Release(); + + pRemoved->Release(); +} +*/ \ No newline at end of file diff --git a/plugins/w7ui/jumplistbuilder.h b/plugins/w7ui/jumplistbuilder.h new file mode 100644 index 0000000000..f0e1cbd438 --- /dev/null +++ b/plugins/w7ui/jumplistbuilder.h @@ -0,0 +1,47 @@ +#ifndef jumplistbuilder_h__ +#define jumplistbuilder_h__ + +class CJumpListBuilder +{ +public: + static void Load() + { + m_instance = new CJumpListBuilder; + } + + static void Unload() + { + delete m_instance; + } + + static void Rebuild() + { + m_instance->BuildJumpList(); + } + +private: + static CJumpListBuilder *m_instance; + + LIST *m_lists; + ICustomDestinationList *m_pList; + CJumpListArray *m_pCurrentList; + TCHAR m_cmdBuf[MAX_PATH * 2]; + + HANDLE m_hBuildCategories; + HANDLE m_hBuildItems; + + CJumpListBuilder(); + ~CJumpListBuilder(); + void BuildJumpList(); + + int __cdecl Rebuild(WPARAM wParam, LPARAM lParam); + int __cdecl AddCategory(WPARAM wParam, LPARAM lParam); + int __cdecl AddItem(WPARAM wParam, LPARAM lParam); + + void BuildCategory(TCHAR *category); + + TCHAR *BuildJumpListCommand(TCHAR *prefix, TCHAR *argument); + HANDLE CreateSvc(char *svc, int (__cdecl CJumpListBuilder::*fn)(WPARAM, LPARAM)); +}; + +#endif // jumplistbuilder_h__ diff --git a/plugins/w7ui/main.cpp b/plugins/w7ui/main.cpp new file mode 100644 index 0000000000..a8763a60a6 --- /dev/null +++ b/plugins/w7ui/main.cpp @@ -0,0 +1,93 @@ +/* +Miranda core extensions + +Copyright 2000-2007 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 "headers.h" +#include + +int LoadW7UI(); +int UnloadW7UI(); + +PLUGINLINK* pluginLink; +HINSTANCE g_hInst; + +struct LIST_INTERFACE li; +struct MM_INTERFACE mmi; + +// {3625ACB8-794C-4727-88EA-76DBBAC6D200} +#define MIID_W7UI { 0x3625acb8, 0x794c, 0x4727, { 0x88, 0xea, 0x76, 0xdb, 0xba, 0xc6, 0xd2, 0x0 } } + + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + "Windows 7 UI", + PLUGIN_MAKE_VERSION(0, 0, 0, 1), + "Provides support for Windows 7 Taskbar feautures such as Aero Peek, Overlay icons, Jump Lists, Progress Bar", + "nullbie, persei", + "nullbie@miranda.im", + "2009 Victor Pavlychko, Vitaliy Igonin", + "http://nullbie.miranda.im", + UNICODE_AWARE, + 0, // replace internal version (if any) +#ifdef _UNICODE + // {D38EEB0B-B8EE-4177-B9E5-91EBE101E054} + { 0xd38eeb0b, 0xb8ee, 0x4177, { 0xb9, 0xe5, 0x91, 0xeb, 0xe1, 0x1, 0xe0, 0x54 } } +#else + // {DEB3FAFA-6B24-4db3-AA34-9EC27B868B50} + { 0xdeb3fafa, 0x6b24, 0x4db3, { 0xaa, 0x34, 0x9e, 0xc2, 0x7b, 0x86, 0x8b, 0x50 } } +#endif +}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + g_hInst = hinstDLL; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID *MirandaPluginInterfaces(void) +{ + static const MUUID interfaces[] = { MIID_W7UI, MIID_LAST }; + return interfaces; +} + +extern "C" __declspec(dllexport) int Load(PLUGINLINK * link) +{ + if (!IsWinVer7Plus()) return 1; + + pluginLink = link; + mir_getLI(&li); + mir_getMMI(&mmi); + + LoadW7UI(); + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + UnloadW7UI(); + return 0; +} diff --git a/plugins/w7ui/srmmproxywindow.cpp b/plugins/w7ui/srmmproxywindow.cpp new file mode 100644 index 0000000000..a70ca1b672 --- /dev/null +++ b/plugins/w7ui/srmmproxywindow.cpp @@ -0,0 +1,374 @@ +#include "headers.h" + +extern int g_eventSlotMessage; +extern ITaskbarList3 *g_pTaskbarList; + +/////////////////////////////////////////////////////////////////////////////// +// srmm processing + +CSrmmProxyWindow::CSrmmProxyWindow(HANDLE hContact, HWND hwndWindow, HWND hwndParent) +{ + m_hContact = hContact; + m_hwndWindow = hwndWindow; + m_hwndParent = hwndParent; + + m_hbmpPreview = NULL; + m_refreshPreview = true; + + m_bActive = false; + m_bUnread = false; + m_bTyping = false; + + UpdateIcon(); + SetWindowText(hwnd(), (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)m_hContact, GCDNF_TCHAR)); + SetTimer(1, 1000); + + SetEventHook(ME_DB_EVENT_ADDED, &CSrmmProxyWindow::OnDbEventAdded); + SetEventHook(ME_DB_CONTACT_SETTINGCHANGED, &CSrmmProxyWindow::OnDbSettingChanged); + SetEventHook(ME_AV_AVATARCHANGED, &CSrmmProxyWindow::OnAvatarChanged); + SetEventHook(ME_PROTO_CONTACTISTYPING, &CSrmmProxyWindow::OnContactTyping); + + AddButton(LoadSkinnedIcon(SKINICON_OTHER_USERDETAILS), TranslateT("User Details"), 1, THBF_DISMISSONCLICK); + AddButton(LoadSkinnedIcon(SKINICON_OTHER_HISTORY), TranslateT("History"), 2, THBF_DISMISSONCLICK); + AddButton(LoadSkinnedIcon(SKINICON_EVENT_FILE), TranslateT("File"), 3, THBF_DISMISSONCLICK); + UpdateButtons(g_pTaskbarList); +} + +CSrmmProxyWindow::~CSrmmProxyWindow() +{ + DeleteObject(m_hbmpPreview); + KillObjectEventHooks(this); +} + + +void CSrmmProxyWindow::Refresh() +{ + InvalidateThumbnail(); + m_refreshPreview = true; +} + +int __cdecl CSrmmProxyWindow::OnDbEventAdded(WPARAM wParam, LPARAM lParam) +{ + if ((HANDLE)wParam == m_hContact) + { + Refresh(); + + if (!m_bUnread && !IsActive()) + { + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if (!CallService(MS_DB_EVENT_GET, (WPARAM)lParam, (LPARAM)&dbei)) + if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_READ|DBEF_SENT))) + { + g_clistProxyWnd->Flash(); + g_clistProxyWnd->AddOverlayEvent(g_eventSlotMessage); + m_bUnread = true; + UpdateIcon(); + } + } + } + return 0; +} + +int __cdecl CSrmmProxyWindow::OnDbSettingChanged(WPARAM wParam, LPARAM lParam) +{ + if ((HANDLE)wParam == m_hContact) + { + UpdateIcon(); + Refresh(); + } + return 0; +} + +int __cdecl CSrmmProxyWindow::OnAvatarChanged(WPARAM wParam, LPARAM lParam) +{ + if ((HANDLE)wParam == m_hContact) + Refresh(); + return 0; +} + +int __cdecl CSrmmProxyWindow::OnContactTyping(WPARAM wParam, LPARAM lParam) +{ + if ((HANDLE)wParam == m_hContact) + { + m_bTyping = lParam ? true : false; + UpdateIcon(); + } + return 0; +} + +HANDLE CSrmmProxyWindow::SetEventHook(char *evt, int (__cdecl CSrmmProxyWindow::*fn)(WPARAM, LPARAM)) +{ + return HookEventObj(evt, *(MIRANDAHOOKOBJ *)&fn, this); +} + +void CSrmmProxyWindow::OnTabActive() +{ + m_bActive = true; + if (m_bUnread) + { + g_clistProxyWnd->RemoveOverlayEvent(g_eventSlotMessage); + m_bUnread = false; + UpdateIcon(); + } +} + +void CSrmmProxyWindow::OnTabInactive() +{ + m_bActive = false; +} + +bool CSrmmProxyWindow::IsActive() +{ + for (HWND hwnd = GetFocus(); hwnd; hwnd = GetParent(hwnd)) + if (hwnd == m_hwndWindow) + return m_bActive = true; + return m_bActive = false; +} + +void CSrmmProxyWindow::UpdateIcon() +{ + HICON hIcon; + if (m_bTyping) + { + hIcon = LoadSkinnedIcon(SKINICON_OTHER_TYPING); + } else + if (m_bUnread) + { + hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE); + } else + { + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)m_hContact, 0); + if (!szProto) return; + int iStatus = DBGetContactSettingWord(m_hContact, szProto, "Status", ID_STATUS_OFFLINE); + hIcon = (HICON)LoadSkinnedProtoIcon(szProto, iStatus); + } + + SendMessage(hwnd(), WM_SETICON, ICON_BIG, (LPARAM)hIcon); + SendMessage(hwnd(), WM_SETICON, ICON_SMALL, (LPARAM)hIcon); +} + +void CSrmmProxyWindow::OnActivate(HWND hwndFrom) +{ + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)m_hContact, 0); +} + +void CSrmmProxyWindow::OnToolbar(int id, INT_PTR data) +{ + POINT pt; GetCursorPos(&pt); + HMENU hMenu = NULL; + HWND hwndClui = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); + + switch (data) + { + case 1: + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)m_hContact, 0); + break; + + case 2: + CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)m_hContact, 0); + break; + + case 3: + CallService(MS_FILE_SENDFILE, (WPARAM)m_hContact, 0); + break; + } +} + +void CSrmmProxyWindow::OnRenderThumbnail(int width, int height) +{ + HBITMAP hbmp = CreateDwmBitmap(width, height); + HDC hdc = CreateCompatibleDC(0); + SelectObject(hdc, hbmp); + + RGBQUAD rgb0, rgb1; + rgb0.rgbRed = 0; rgb0.rgbGreen = 0; rgb0.rgbBlue = 0; + rgb1.rgbRed = 19; rgb1.rgbGreen = 58; rgb1.rgbBlue = 89; + DrawGradient(hdc, 0, 0, width, height, &rgb0, &rgb1); + + HFONT hfntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + SetTextColor(hdc, RGB(255, 255, 255)); + SetBkMode(hdc, TRANSPARENT); + + RECT rc; + SIZE sz; + SetRect(&rc, 5, 5, width-10, height-10); + + int avatarWidth = 0; + int avatarHeight = 0; + if (true) + { + AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)m_hContact, 0); + if (ace && (ace != (AVATARCACHEENTRY *)CALLSERVICE_NOTFOUND)) + { + if (ace->bmWidth < width / 4) + { + avatarWidth = ace->bmWidth; + avatarHeight = ace->bmHeight; + } else + { + avatarWidth = width / 4; + avatarHeight = avatarWidth * ace->bmHeight / ace->bmWidth; + } + + AVATARDRAWREQUEST avdr = {0}; + avdr.cbSize = sizeof(avdr); + avdr.hContact = m_hContact; + avdr.hTargetDC = hdc; + avdr.rcDraw = rc; + avdr.rcDraw.bottom = avdr.rcDraw.top + avatarHeight; + avdr.rcDraw.right = avdr.rcDraw.left + avatarWidth; + avdr.dwFlags = AVDRQ_FALLBACKPROTO | AVDRQ_FORCEALPHA; + + avdr.alpha = 255; + CallService(MS_AV_DRAWAVATAR, 0, (LPARAM)&avdr); + + rc.left += avatarWidth + 5; + } + } + + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)m_hContact, 0); + + if (true) + { + CONTACTINFO ci = {0}; + ci.cbSize = sizeof(ci); + ci.hContact = m_hContact; + ci.szProto = proto; + ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR; + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) + { + TCHAR name[128]; name[0] = 0; + switch (ci.type) + { + case CNFT_ASCIIZ: + mir_sntprintf(name, SIZEOF(name), _T("%s"), ci.pszVal); + mir_free((void *)ci.pszVal); + break; + case CNFT_DWORD: + mir_sntprintf(name, SIZEOF(name), _T("%u"), ci.dVal); + break; + } + + TextOut(hdc, rc.left + 20, rc.top, name, lstrlen(name)); + GetTextExtentPoint32(hdc, name, lstrlen(name), &sz); + } + } + + if (true) + { + HIMAGELIST hIml = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0); + int iIcon = CallService(MS_CLIST_GETCONTACTICON, (WPARAM)m_hContact, 0); + ImageList_Draw(hIml, iIcon, hdc, rc.left, rc.top + (sz.cy - 16) / 2, ILD_TRANSPARENT); + } + + rc.top += sz.cy + 5; + + rc.left += 10; + + struct + { + TCHAR *text; + bool out; + } msgs[10] = {0}; + + if (true) + { + int hMsgs = 0; + int n = 0; + HANDLE hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)m_hContact, 0); + while (hEvent) + { + BYTE buf[1024]; + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = sizeof(buf); + dbei.pBlob = buf; + if (!CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei)) + { + if (dbei.eventType == EVENTTYPE_MESSAGE) + { + msgs[n].text = DbGetEventTextT(&dbei, CP_ACP); + msgs[n].out = dbei.flags & DBEF_SENT ? true : false; + + RECT rcCopy = rc; + hMsgs += DrawText(hdc, msgs[n].text, -1, &rcCopy, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK|DT_TOP|DT_CALCRECT); + if (n && hMsgs > rc.bottom - rc.top) + { + mir_free(msgs[n].text); + msgs[n].text = 0; + break; + } + + hMsgs += 3; + + if (++n >= SIZEOF(msgs)) break; + } + } + hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hEvent, 0); + } + } + + if (true) + { + for (int i = SIZEOF(msgs); i--; ) + { + if (!msgs[i].text) continue; + + TCHAR szDir[] = { (msgs[i].out ? (WCHAR)0xbb : (WCHAR)0xab), 0 }; + rc.left -= 10; + DrawText(hdc, szDir, -1, &rc, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK|DT_TOP); + rc.left += 10; + + rc.top += 3 + DrawText(hdc, msgs[i].text, -1, &rc, DT_LEFT|DT_NOPREFIX|DT_WORDBREAK|DT_TOP); + mir_free(msgs[i].text); + } + } + + SelectObject(hdc, hfntSave); + + DeleteDC(hdc); + MakeBitmapOpaque(hbmp); + SetThumbnail(hbmp); + DeleteObject(hbmp); +} + +void CSrmmProxyWindow::OnRenderPreview() +{ + if (!m_hbmpPreview) return; + + RECT rc; + GetWindowRect(m_hwndWindow, &rc); + MapWindowPoints(NULL, m_hwndParent, (POINT *)&rc, 2); + SetPreview(m_hbmpPreview, rc.left, rc.top); +} + +void CSrmmProxyWindow::OnTimer(int) +{ + g_pTaskbarList->UnregisterTab(m_hwndParent); + + if (!m_refreshPreview) return; + if (!IsWindowVisible(m_hwndWindow) || !IsWindowVisible(m_hwndParent) || IsIconic(m_hwndParent)) return; + if (m_hbmpPreview) DeleteObject(m_hbmpPreview); + + m_refreshPreview = false; + + RECT rc; + GetWindowRect(m_hwndWindow, &rc); + + m_hbmpPreview = CreateDwmBitmap(rc.right - rc.left, rc.bottom - rc.top); + HDC hdc = CreateCompatibleDC(0); + HBITMAP hbmpSave = (HBITMAP)SelectObject(hdc, m_hbmpPreview); + PrintWindow(m_hwndWindow, hdc, PW_CLIENTONLY); + SelectObject(hdc, hbmpSave); + DeleteDC(hdc); + + MakeBitmapOpaque(m_hbmpPreview); + + InvalidateThumbnail(); +} + +void CSrmmProxyWindow::OnClose() +{ + SendMessage(m_hwndWindow, WM_CLOSE, 1, 0); +} \ No newline at end of file diff --git a/plugins/w7ui/srmmproxywindow.h b/plugins/w7ui/srmmproxywindow.h new file mode 100644 index 0000000000..f1c447d4e8 --- /dev/null +++ b/plugins/w7ui/srmmproxywindow.h @@ -0,0 +1,42 @@ +#ifndef srmmproxywindow_h__ +#define srmmproxywindow_h__ + +class CSrmmProxyWindow: public CDwmWindow +{ +public: + CSrmmProxyWindow(HANDLE hContact, HWND hwndWindow, HWND hwndParent); + ~CSrmmProxyWindow(); + + void OnTabActive(); + void OnTabInactive(); + +private: + HANDLE m_hContact; + HWND m_hwndWindow, m_hwndParent; + HBITMAP m_hbmpPreview; + bool m_refreshPreview; + bool m_bActive, m_bUnread, m_bTyping; + + void Refresh(); + + int __cdecl OnDbEventAdded(WPARAM wParam, LPARAM lParam); + int __cdecl OnDbSettingChanged(WPARAM wParam, LPARAM lParam); + int __cdecl OnAvatarChanged(WPARAM wParam, LPARAM lParam); + int __cdecl OnContactTyping(WPARAM wParam, LPARAM lParam); + + HANDLE SetEventHook(char *evt, int (__cdecl CSrmmProxyWindow::*fn)(WPARAM, LPARAM)); + + void UpdateIcon(); + + bool IsActive(); + +protected: + void OnActivate(HWND hwndFrom); + void OnToolbar(int id, INT_PTR data); + void OnRenderThumbnail(int width, int height); + void OnRenderPreview(); + void OnTimer(int); + void OnClose(); +}; + +#endif // srmmproxywindow_h__ diff --git a/plugins/w7ui/subclassmgr.cpp b/plugins/w7ui/subclassmgr.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/w7ui/subclassmgr.h b/plugins/w7ui/subclassmgr.h new file mode 100644 index 0000000000..1cf2433254 --- /dev/null +++ b/plugins/w7ui/subclassmgr.h @@ -0,0 +1,71 @@ +#ifndef subclassmgr_h__ +#define subclassmgr_h__ + +struct TSubclassData +{ + WNDPROC oldWndProc; + LPARAM lParam; +}; + +typedef LRESULT (*TSubclassProc)(MSG *msg, TSubclassData *data); + +class CSubclassMgr +{ +public: + static void Subclass(HWND hwnd, TSubclassProc newWndProc, LPARAM lParam) + { + TWindowInfo *wi = new TWindowInfo; + wi->hwnd = hwnd; + wi->newWndProc = newWndProc; + wi->lParam = lParam; + Instance().m_windows.insert(wi); + wi->oldWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)GlobalSubclassProc); + } + +private: + CSubclassMgr(): m_windows(5, TWindowInfo::Compare) {} + CSubclassMgr(const CSubclassMgr &); + CSubclassMgr &operator=(const CSubclassMgr &); + + static CSubclassMgr &Instance() + { + static CSubclassMgr theInstance; + return theInstance; + } + + struct TWindowInfo + { + HWND hwnd; + WNDPROC oldWndProc; + TSubclassProc newWndProc; + LPARAM lParam; + + static int Compare(const TWindowInfo *p1, const TWindowInfo *p2) + { + return (int)p1->hwnd - (int)p2->hwnd; + } + }; + + OBJLIST m_windows; + + static LRESULT CALLBACK GlobalSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) + { + TWindowInfo search = { hwnd }; + TWindowInfo *wnd = Instance().m_windows.find(&search); + if (!wnd) return DefWindowProc(hwnd, message, wParam, lParam); + + MSG msg = { hwnd, message, wParam, lParam }; + TSubclassData data = { wnd->oldWndProc, wnd->lParam }; + LRESULT result = wnd->newWndProc(&msg, &data); + + if (message == WM_DESTROY) + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)wnd->oldWndProc); + Instance().m_windows.remove(wnd); + } + + return result; + } +}; + +#endif // subclassmgr_h__ diff --git a/plugins/w7ui/w7ui.cpp b/plugins/w7ui/w7ui.cpp new file mode 100644 index 0000000000..afce9b65eb --- /dev/null +++ b/plugins/w7ui/w7ui.cpp @@ -0,0 +1,180 @@ +#include "headers.h" + +ITaskbarList3 *g_pTaskbarList = NULL; +UINT g_wm_TaskbarButtonCreated = 0; +HANDLE hSrmmWindows = NULL; + +int g_eventSlotTyping = 0; +int g_eventSlotMessage = 0; + +void InitJumpList(); + +static LRESULT CALLBACK W7UIHostWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +static LRESULT CALLBACK W7SrmmProxyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static int OnModulesLoaded(WPARAM, LPARAM); +static int OnProcessSrmmEvent(WPARAM, LPARAM lParam); +static int OnStatusModeChanged(WPARAM wParam, LPARAM); + +int LoadW7UI() +{ + CoInitialize(NULL); + + CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&g_pTaskbarList); + g_pTaskbarList->HrInit(); + + g_wm_TaskbarButtonCreated = RegisterWindowMessage(_T("TaskbarButtonCreated")); + + CJumpListBuilder::Load(); + LoadJumpList(); + + HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + HookEvent(ME_CLIST_STATUSMODECHANGE, OnStatusModeChanged); + + hSrmmWindows = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + new CClistProxyWindow(); + + return 0; +} + +int UnloadW7UI() +{ + CJumpListBuilder::Unload(); + return 0; +} + +static int OnContactIsTyping(WPARAM wParam, LPARAM lParam) +{ + if (!wParam) return 0; + + if (lParam) g_clistProxyWnd->AddOverlayEvent(g_eventSlotTyping); + else g_clistProxyWnd->RemoveOverlayEvent(g_eventSlotTyping); + + return 0; +} + +static int OnModulesLoaded(WPARAM, LPARAM) +{ + InitJumpList(); + g_eventSlotMessage = g_clistProxyWnd->AllocateOverlayEvent(LoadSkinnedIconHandle(SKINICON_EVENT_MESSAGE)); + g_eventSlotTyping = g_clistProxyWnd->AllocateOverlayEvent(LoadSkinnedIconHandle(SKINICON_OTHER_TYPING)); + OnStatusModeChanged(CallService(MS_CLIST_GETSTATUSMODE, 0, 0), 0); + HookEvent(ME_MSG_WINDOWEVENT, OnProcessSrmmEvent); + HookEvent(ME_PROTO_CONTACTISTYPING, OnContactIsTyping); + return 0; +} + +static LRESULT SrmmSubclassProc(MSG *msg, TSubclassData *data) +{ + HWND hwndProxy = WindowList_Find(hSrmmWindows, (HANDLE)data->lParam); + CSrmmProxyWindow *wnd = CDwmWindow::GetWindow(hwndProxy); + + if (wnd) + { + switch (msg->message) + { + case WM_SETFOCUS: + wnd->OnTabActive(); + break; + case WM_ACTIVATE: + switch (msg->wParam) + { + case WA_ACTIVE: + case WA_CLICKACTIVE: + wnd->OnTabActive(); + break; + case WA_INACTIVE: + wnd->OnTabInactive(); + } + break; + case WM_NCACTIVATE: + if (msg->wParam) + wnd->OnTabActive(); + else + wnd->OnTabInactive(); + break; + } + } + + return CallWindowProc(data->oldWndProc, msg->hwnd, msg->message, msg->wParam, msg->lParam); +} + +static HWND FindParent(HWND hwnd) +{ + while (1) + { + HWND hwndParent = GetParent(hwnd); + if (hwndParent == NULL) + return hwnd; + hwnd = hwndParent; + } +} + +int OnProcessSrmmEvent(WPARAM, LPARAM lParam) +{ + MessageWindowEventData *evt = (MessageWindowEventData *)lParam; + + switch (evt->uType) + { + case MSG_WINDOW_EVT_OPENING: + { + CSubclassMgr::Subclass(evt->hwndWindow, SrmmSubclassProc, (LPARAM)evt->hContact); + break; + } + + case MSG_WINDOW_EVT_OPEN: + { + HWND hwndParent = FindParent(evt->hwndWindow); + if (hwndParent != evt->hwndWindow) + { + SetWindowLong(hwndParent, GWL_EXSTYLE, GetWindowLong(hwndParent, GWL_EXSTYLE) & ~WS_EX_APPWINDOW); + CSrmmProxyWindow *wnd = new CSrmmProxyWindow(evt->hContact, evt->hwndWindow, hwndParent); + HWND hwndProxy = wnd->hwnd(); + g_pTaskbarList->UnregisterTab(hwndParent); + g_pTaskbarList->RegisterTab(hwndProxy, hwndParent); + g_pTaskbarList->SetTabOrder(hwndProxy, 0); + g_pTaskbarList->SetTabActive(hwndProxy, hwndParent, TBATF_USEMDITHUMBNAIL); + WindowList_Add(hSrmmWindows, hwndProxy, evt->hContact); + } + break; + } + + case MSG_WINDOW_EVT_CLOSING: + { + HWND hwndProxy = WindowList_Find(hSrmmWindows, evt->hContact); + if (hwndProxy) + { + WindowList_Remove(hSrmmWindows, hwndProxy); + g_pTaskbarList->UnregisterTab(hwndProxy); + DestroyWindow(hwndProxy); + } + break; + } + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// status processing + +int OnStatusModeChanged(WPARAM wParam, LPARAM) +{ + static int icons[] = + { + SKINICON_STATUS_OFFLINE, + SKINICON_STATUS_ONLINE, + SKINICON_STATUS_AWAY, + SKINICON_STATUS_DND, + SKINICON_STATUS_NA, + SKINICON_STATUS_OCCUPIED, + SKINICON_STATUS_FREE4CHAT, + SKINICON_STATUS_INVISIBLE, + SKINICON_STATUS_ONTHEPHONE, + SKINICON_STATUS_OUTTOLUNCH, + }; + + g_clistProxyWnd->SetOverlayIcon(LoadSkinnedIcon(icons[wParam - ID_STATUS_OFFLINE])); + + return 0; +} diff --git a/plugins/w7ui/w7ui_10.sln b/plugins/w7ui/w7ui_10.sln new file mode 100644 index 0000000000..025cd91ade --- /dev/null +++ b/plugins/w7ui/w7ui_10.sln @@ -0,0 +1,37 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "w7ui", "w7ui_10.vcxproj", "{86704897-EABF-439D-BE0E-52CEA67C2C43}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Win32 = Debug Unicode|Win32 + Debug Unicode|x64 = Debug Unicode|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release Unicode|Win32 = Release Unicode|Win32 + Release Unicode|x64 = Release Unicode|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug Unicode|x64.ActiveCfg = Debug Unicode|x64 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug Unicode|x64.Build.0 = Debug Unicode|x64 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug|Win32.ActiveCfg = Debug|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug|Win32.Build.0 = Debug|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug|x64.ActiveCfg = Debug|x64 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Debug|x64.Build.0 = Debug|x64 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release Unicode|x64.ActiveCfg = Release Unicode|x64 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release Unicode|x64.Build.0 = Release Unicode|x64 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release|Win32.ActiveCfg = Release|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release|Win32.Build.0 = Release|Win32 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release|x64.ActiveCfg = Release|x64 + {86704897-EABF-439D-BE0E-52CEA67C2C43}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/w7ui/w7ui_10.vcxproj b/plugins/w7ui/w7ui_10.vcxproj new file mode 100644 index 0000000000..9f35dff44e --- /dev/null +++ b/plugins/w7ui/w7ui_10.vcxproj @@ -0,0 +1,364 @@ + + + + + Debug Unicode + Win32 + + + Debug Unicode + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Unicode + Win32 + + + Release Unicode + x64 + + + Release + Win32 + + + Release + x64 + + + + w7ui + {86704897-EABF-439D-BE0E-52CEA67C2C43} + w7ui + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + true + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + false + false + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + $(IntDir)$(TargetName).lib + + + + + Full + true + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + OnlyExplicitInline + Size + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + true + true + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Full + true + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + OnlyExplicitInline + Size + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + true + true + $(IntDir)$(TargetName).lib + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Disabled + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + $(IntDir)$(TargetName).lib + + + + + Full + Size + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + OnlyExplicitInline + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + true + true + MachineX86 + $(IntDir)$(TargetName).lib + + + + + Full + Size + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;W7UI_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + OnlyExplicitInline + + + msimg32.lib;dwmapi.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies) + true + Windows + true + true + $(IntDir)$(TargetName).lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/w7ui/win7api.cpp b/plugins/w7ui/win7api.cpp new file mode 100644 index 0000000000..dcfb6058ec --- /dev/null +++ b/plugins/w7ui/win7api.cpp @@ -0,0 +1,25 @@ +#include + +//extern "C" const CLSID CLSID_TaskbarList = {0x56fdf344,0xfd6d,0x11d0,{0x95,0x8a,0x00,0x60,0x97,0xc9,0xa0,0x90}}; // 56fdf344-fd6d-11d0-958a-006097c9a090; +//extern "C" const IID IID_ITaskbarList = {0x56FDF342,0xFD6D,0x11d0,{0x95,0x8A,0x00,0x60,0x97,0xC9,0xA0,0x90}}; // 56FDF342-FD6D-11d0-958A-006097C9A090; +//extern "C" const IID IID_ITaskbarList2 = {0x602D4995,0xB13A,0x429b,{0xA6,0x6E,0x19,0x35,0xE4,0x4F,0x43,0x17}}; // 602D4995-B13A-429b-A66E-1935E44F4317; +//extern "C" const IID IID_ICustomDestinationList = {0x6332debf,0x87b5,0x4670,{0x90,0xc0,0x5e,0x57,0xb4,0x08,0xa4,0x9e}}; // 6332debf-87b5-4670-90c0-5e57b408a49e +//extern "C" const IID IID_IObjectArray = {0x92CA9DCD,0x5622,0x4bba,{0xA8,0x05,0x5E,0x9F,0x54,0x1B,0xD8,0xC9}}; // 92CA9DCD-5622-4bba-A805-5E9F541BD8C9 +//extern "C" const IID IID_IObjectCollection = {0x5632b1a4,0xe38a,0x400a,{0x92,0x8a,0xd4,0xcd,0x63,0x23,0x02,0x95}}; // 5632b1a4-e38a-400a-928a-d4cd63230295 +//extern "C" const IID IID_ITaskbarList3 = {0xea1afb91,0x9e28,0x4b86,{0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf}}; // ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf +extern "C" const CLSID CLSID_CustomDestinationList = {0x77f10cf0,0x3db5,0x4966,{0xb5,0x20,0xb7,0xc5,0x4f,0xd3,0x5e,0xd6}}; +//extern "C" const CLSID CLSID_EnumerableObjectCollection = {0x2d3468c1,0x36a7,0x43b6,{0xac,0x24,0xd3,0xf0,0x2f,0xd9,0x60,0x7a}}; + +HRESULT (WINAPI *dwmInvalidateIconicBitmaps)(HWND) = + (HRESULT (WINAPI *)(HWND))GetProcAddress(LoadLibraryA("dwmapi.dll"), "DwmInvalidateIconicBitmaps"); +HRESULT (WINAPI *dwmSetIconicThumbnail)(HWND, HBITMAP, DWORD) = + (HRESULT (WINAPI *)(HWND, HBITMAP, DWORD))GetProcAddress(LoadLibraryA("dwmapi.dll"), "DwmSetIconicThumbnail"); +HRESULT (WINAPI *dwmSetIconicLivePreviewBitmap)(HWND, HBITMAP, LPPOINT, DWORD) = + (HRESULT (WINAPI *)(HWND, HBITMAP, LPPOINT, DWORD))GetProcAddress(LoadLibraryA("dwmapi.dll"), "DwmSetIconicLivePreviewBitmap"); + +HANDLE (STDAPICALLTYPE *openThemeData)(HWND, LPCWSTR) = + (HANDLE (STDAPICALLTYPE *)(HWND, LPCWSTR))GetProcAddress(LoadLibraryA("uxtheme.dll"), "OpenThemeData"); +HRESULT (STDAPICALLTYPE *drawThemeTextEx)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const struct _DTTOPTS *) = + (HRESULT (STDAPICALLTYPE *)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const struct _DTTOPTS *))GetProcAddress(LoadLibraryA("uxtheme.dll"), "DrawThemeTextEx"); +HRESULT (STDAPICALLTYPE *closeThemeData)(HANDLE) = + (HRESULT (STDAPICALLTYPE *)(HANDLE))GetProcAddress(LoadLibraryA("uxtheme.dll"), "CloseThemeData"); diff --git a/plugins/w7ui/win7api.h b/plugins/w7ui/win7api.h new file mode 100644 index 0000000000..f9fa806335 --- /dev/null +++ b/plugins/w7ui/win7api.h @@ -0,0 +1,38 @@ +#ifndef win7api_h__ +#define win7api_h__ + +#define WM_DWMSENDICONICTHUMBNAIL 0x0323 +#define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326 + +#define DWMWA_HAS_ICONIC_BITMAP 10 + +#define DWM_SIT_DISPLAYFRAME 0x00000001 + +enum TBATFLAG +{ TBATF_USEMDITHUMBNAIL = 0x1, + TBATF_USEMDILIVEPREVIEW = 0x2 +}; + +#define THBN_CLICKED 0x1800 + +extern HRESULT (WINAPI *dwmInvalidateIconicBitmaps)(HWND); +extern HRESULT (WINAPI *dwmSetIconicThumbnail)(HWND, HBITMAP, DWORD); +extern HRESULT (WINAPI *dwmSetIconicLivePreviewBitmap)(HWND, HBITMAP, LPPOINT, DWORD); + +extern HANDLE (STDAPICALLTYPE *openThemeData)(HWND, LPCWSTR); +extern HRESULT (STDAPICALLTYPE *drawThemeTextEx)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const struct _DTTOPTS *); +extern HRESULT (STDAPICALLTYPE *closeThemeData)(HANDLE); + +extern "C" const IID IID_ICustomDestinationList; +extern "C" const IID IID_IObjectArray; +extern "C" const IID IID_IObjectCollection; +extern "C" const IID IID_ITaskbarList3; +extern "C" const CLSID CLSID_CustomDestinationList; +extern "C" const CLSID CLSID_EnumerableObjectCollection; + +#include "win7api_IObjectArray.h" +#include "win7api_IObjectCollection.h" +#include "win7api_ICustomDestinationList.h" +//#include "win7api_ITaskbarList3.h" + +#endif // win7api_h__ diff --git a/plugins/w7ui/win7api_ICustomDestinationList.h b/plugins/w7ui/win7api_ICustomDestinationList.h new file mode 100644 index 0000000000..6d3f770d29 --- /dev/null +++ b/plugins/w7ui/win7api_ICustomDestinationList.h @@ -0,0 +1,34 @@ +#ifndef __ICustomDestinationList_INTERFACE_DEFINED__ +#define __ICustomDestinationList_INTERFACE_DEFINED__ + +typedef /* [v1_enum] */ enum tagKNOWNDESTCATEGORY { + KDC_FREQUENT = 1, + KDC_RECENT = (KDC_FREQUENT + 1) +} KNOWNDESTCATEGORY; + +MIDL_INTERFACE("6332debf-87b5-4670-90c0-5e57b408a49e") +ICustomDestinationList : public IUnknown { + public: + virtual HRESULT STDMETHODCALLTYPE SetAppID( + /* [string][in] */__RPC__in_string LPCWSTR pszAppID) = 0; + virtual HRESULT STDMETHODCALLTYPE BeginList( + /* [out] */ __RPC__out UINT *pcMaxSlots, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + virtual HRESULT STDMETHODCALLTYPE AppendCategory( + /* [string][in] */ __RPC__in_string LPCWSTR pszCategory, + /* [in] */ __RPC__in_opt IObjectArray *poa) = 0; + virtual HRESULT STDMETHODCALLTYPE AppendKnownCategory( + /* [in] */ KNOWNDESTCATEGORY category) = 0; + virtual HRESULT STDMETHODCALLTYPE AddUserTasks( + /* [in] */ __RPC__in_opt IObjectArray *poa) = 0; + virtual HRESULT STDMETHODCALLTYPE CommitList(void) = 0; + virtual HRESULT STDMETHODCALLTYPE GetRemovedDestinations( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + virtual HRESULT STDMETHODCALLTYPE DeleteList( + /* [string][in] */ __RPC__in_string LPCWSTR pszAppID) = 0; + virtual HRESULT STDMETHODCALLTYPE AbortList(void) = 0; +}; + +#endif // __ICustomDestinationList_INTERFACE_DEFINED__ diff --git a/plugins/w7ui/win7api_IObjectArray.h b/plugins/w7ui/win7api_IObjectArray.h new file mode 100644 index 0000000000..2102276989 --- /dev/null +++ b/plugins/w7ui/win7api_IObjectArray.h @@ -0,0 +1,15 @@ +#ifndef __IObjectArray_INTERFACE_DEFINED__ +#define __IObjectArray_INTERFACE_DEFINED__ + +MIDL_INTERFACE("92CA9DCD-5622-4bba-A805-5E9F541BD8C9") +IObjectArray : public IUnknown { + public: + virtual HRESULT STDMETHODCALLTYPE GetCount( + /* [out] */ __RPC__out UINT *pcObjects) = 0; + virtual HRESULT STDMETHODCALLTYPE GetAt( + /* [in] */ UINT uiIndex, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; +}; + +#endif // __IObjectArray_INTERFACE_DEFINED__ diff --git a/plugins/w7ui/win7api_IObjectCollection.h b/plugins/w7ui/win7api_IObjectCollection.h new file mode 100644 index 0000000000..71b37d0e99 --- /dev/null +++ b/plugins/w7ui/win7api_IObjectCollection.h @@ -0,0 +1,16 @@ +#ifndef __IObjectCollection_INTERFACE_DEFINED__ +#define __IObjectCollection_INTERFACE_DEFINED__ + +MIDL_INTERFACE("5632b1a4-e38a-400a-928a-d4cd63230295") +IObjectCollection : public IObjectArray { + public: + virtual HRESULT STDMETHODCALLTYPE AddObject( + /* [in] */ __RPC__in_opt IUnknown *punk) = 0; + virtual HRESULT STDMETHODCALLTYPE AddFromArray( + /* [in] */ __RPC__in_opt IObjectArray *poaSource) = 0; + virtual HRESULT STDMETHODCALLTYPE RemoveObjectAt( + /* [in] */ UINT uiIndex) = 0; + virtual HRESULT STDMETHODCALLTYPE Clear(void) = 0; +}; + +#endif // __IObjectCollection_INTERFACE_DEFINED__ diff --git a/plugins/w7ui/win7api_ITaskbarList3.h b/plugins/w7ui/win7api_ITaskbarList3.h new file mode 100644 index 0000000000..8c39fb5c41 --- /dev/null +++ b/plugins/w7ui/win7api_ITaskbarList3.h @@ -0,0 +1,65 @@ +#ifndef __ITaskbarList3_FWD_DEFINED__ +#define __ITaskbarList3_FWD_DEFINED__ +typedef interface ITaskbarList3 ITaskbarList3; +#endif /* __ITaskbarList3_FWD_DEFINED__ */ + +/* interface ITaskbarList3 */ +/* [object][uuid] */ + +MIDL_INTERFACE("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf") +ITaskbarList3 : public ITaskbarList2 +{ +public: + virtual HRESULT STDMETHODCALLTYPE SetProgressValue( + /* [in] */ __RPC__in HWND hwnd, + /* [in] */ ULONGLONG ullCompleted, + /* [in] */ ULONGLONG ullTotal) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetProgressState( + /* [in] */ __RPC__in HWND hwnd, + /* [in] */ TBPFLAG tbpFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE RegisterTab( + /* [in] */ __RPC__in HWND hwndTab, + /* [in] */ __RPC__in HWND hwndMDI) = 0; + + virtual HRESULT STDMETHODCALLTYPE UnregisterTab( + /* [in] */ __RPC__in HWND hwndTab) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTabOrder( + /* [in] */ __RPC__in HWND hwndTab, + /* [in] */ __RPC__in HWND hwndInsertBefore) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetTabActive( + /* [in] */ __RPC__in HWND hwndTab, + /* [in] */ __RPC__in HWND hwndMDI, + /* [in] */ TBATFLAG tbatFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE ThumbBarAddButtons( + /* [in] */ __RPC__in HWND hwnd, + /* [in] */ UINT cButtons, + /* [size_is][in] */ __RPC__in_ecount_full(cButtons) LPTHUMBBUTTON pButton) = 0; + + virtual HRESULT STDMETHODCALLTYPE ThumbBarUpdateButtons( + /* [in] */ __RPC__in HWND hwnd, + /* [in] */ UINT cButtons, + /* [size_is][in] */ __RPC__in_ecount_full(cButtons) LPTHUMBBUTTON pButton) = 0; + + virtual HRESULT STDMETHODCALLTYPE ThumbBarSetImageList( + /* [in] */ __RPC__in HWND hwnd, + /* [in] */ __RPC__in_opt HIMAGELIST himl) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetOverlayIcon( + /* [in] */ __RPC__in HWND hwnd, + /* [in] */ __RPC__in HICON hIcon, + /* [string][in] */ __RPC__in_string LPCWSTR pszDescription) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetThumbnailTooltip( + /* [in] */ __RPC__in HWND hwnd, + /* [string][in] */ __RPC__in_string LPCWSTR pszTip) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetThumbnailClip( + /* [in] */ __RPC__in HWND hwnd, + /* [in] */ __RPC__in RECT *prcClip) = 0; + +}; -- cgit v1.2.3