diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_online/Setup | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_online/Setup')
26 files changed, 7113 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_online/Setup/SetupGroupFilter.h b/Src/Plugins/Library/ml_online/Setup/SetupGroupFilter.h new file mode 100644 index 00000000..feb4be24 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/SetupGroupFilter.h @@ -0,0 +1,91 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPFILTER_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPFILTER_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <vector> + +class ifc_omservice; + +class __declspec(novtable) SetupGroupFilter +{ +public: + typedef enum + { + serviceIgnore = 0x00000000, + serviceInclude = 0x00000001, + serviceForceSubscribe = 0x00000002, + serviceForceUnsubscribe = 0x00000004, + } FilterResult; +protected: + SetupGroupFilter(const GUID *filterId); + virtual ~SetupGroupFilter(); + +public: + static HRESULT CreateInstance(const GUID *filterId, SetupGroupFilter **instance); + +public: + virtual ULONG AddRef(); + virtual ULONG Release(); + + virtual HRESULT GetId(GUID *filterId); + + virtual HRESULT Initialize() = 0; + virtual HRESULT ProcessService(ifc_omservice *service, UINT *filterResult) = 0; + +protected: + typedef std::vector<UINT> ServiceIdList; + static BOOL CALLBACK AppendServiceIdCallback(UINT serviceId, void *data); + +protected: + ULONG ref; + GUID id; +}; + + +// {2F45FBDF-4372-4def-B20C-C6F1BAE5AE85} +static const GUID FUID_SetupFeaturedGroupFilter = +{ 0x2f45fbdf, 0x4372, 0x4def, { 0xb2, 0xc, 0xc6, 0xf1, 0xba, 0xe5, 0xae, 0x85 } }; + + +class SetupFeaturedGroupFilter : public SetupGroupFilter +{ +protected: + SetupFeaturedGroupFilter(); + ~SetupFeaturedGroupFilter(); +public: + static HRESULT CreateInstance(SetupFeaturedGroupFilter **instance); + +public: + HRESULT Initialize(); + HRESULT ProcessService(ifc_omservice *service, UINT *filterResult); + +protected: + ServiceIdList filterList; +}; + +// {7CA8722D-8B11-43a0-8F55-533C9DE3D73E} +static const GUID FUID_SetupKnownGroupFilter = +{ 0x7ca8722d, 0x8b11, 0x43a0, { 0x8f, 0x55, 0x53, 0x3c, 0x9d, 0xe3, 0xd7, 0x3e } }; + + +class SetupKnownGroupFilter : public SetupGroupFilter +{ +protected: + SetupKnownGroupFilter(); + ~SetupKnownGroupFilter(); +public: + static HRESULT CreateInstance(SetupKnownGroupFilter **instance); + +public: + HRESULT Initialize(); + HRESULT ProcessService(ifc_omservice *service, UINT *filterResult); + +protected: + ServiceIdList filterList; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPFILTER_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setup.cpp b/Src/Plugins/Library/ml_online/Setup/setup.cpp new file mode 100644 index 00000000..e8497306 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setup.cpp @@ -0,0 +1,71 @@ +#define GUID_DEFINE +#include "../../winamp/setup/svc_setup.h" +#undef GUID_DEFINE + +#include "./setupPage.h" + +#include "../api__ml_online.h" + + +static HRESULT Setup_RegisterPage() +{ + HRESULT hr; + svc_setup *setupSvc; + SetupPage *page; + + + if (FAILED(WasabiApi_LoadDefaults()) || + NULL == OMBROWSERMNGR || + NULL == OMSERVICEMNGR || + NULL == OMUTILITY) + { + return E_UNEXPECTED; + } + + setupSvc = QueryWasabiInterface(svc_setup, UID_SVC_SETUP); + if (NULL == setupSvc) + return E_POINTER; + + page = SetupPage::CreateInstance(); + if (NULL == page) + hr = E_OUTOFMEMORY; + else + { + // try to insert before 'feedback' (if present) + // otherwise dump at the end of the pages list. + int index = 0xFFFFF; + if (FAILED(setupSvc->GetPageCount(&index))) + index = 0xFFFFF; + else if (index > 0 && index == 3) + index--; + + hr = setupSvc->InsertPage(page, &index); + if (SUCCEEDED(hr)) + setupSvc->AddJob((ifc_setupjob*)page); + + page->Release(); + } + + ReleaseWasabiInterface(UID_SVC_SETUP, setupSvc); + + return hr; +} + +EXTERN_C _declspec(dllexport) BOOL RegisterSetup(HINSTANCE hInstance, api_service *waServices) +{ + // check the current date and if past November 30th 2013 + // then we will prevent the online page from being shown + time_t now = time(0); + struct tm *tn = localtime(&now); + tn->tm_sec = tn->tm_min = tn->tm_hour = 0; + + if (mktime(tn) >= 1387497600) + return FALSE; + + if (FAILED(WasabiApi_Initialize(hInstance, waServices))) + return FALSE; + + BOOL result = SUCCEEDED(Setup_RegisterPage()); + WasabiApi_Release(); + return result; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetails.cpp b/Src/Plugins/Library/ml_online/Setup/setupDetails.cpp new file mode 100644 index 00000000..5e1b7be2 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetails.cpp @@ -0,0 +1,80 @@ +#include "./common.h" +#include "./setupDetails.h" +#include "./setupServicePanel.h" + +EXTERN_C ATOM DETAILS_PROP = 0; +HMODULE hEditModule = NULL; + + +BOOL SetupDetails_Initialize() +{ + if (0 == DETAILS_PROP) + { + DETAILS_PROP = GlobalAddAtom(L"omSetupDetailsProp"); + if (0 == DETAILS_PROP) return FALSE; + } + + if (NULL == (hEditModule = LoadLibrary(L"riched20.dll"))) + return FALSE; + + return TRUE; +} + +void SetupDetails_Uninitialize() +{ + if (NULL != hEditModule) + { + FreeLibrary(hEditModule); + hEditModule = NULL; + } + + if (0 != DETAILS_PROP) + { + GlobalDeleteAtom(DETAILS_PROP); + DETAILS_PROP = 0; + } +} + +void SetupDetails_SetDescription(HWND hEdit, LPCWSTR pszText) +{ + SetWindowText(hEdit, pszText); + + DWORD originalStyle = GetWindowStyle(hEdit); + DWORD windowStyle = originalStyle & ~WS_VSCROLL; + + INT lineCount = (INT)SendMessage(hEdit, EM_GETLINECOUNT, 0, 0L); + if (lineCount > 0) + { + INT charIndex = (INT)SendMessage(hEdit, EM_LINEINDEX, (WPARAM)(lineCount - 1), 0L); + if (-1 != charIndex) + { + LRESULT result = SendMessage(hEdit, EM_POSFROMCHAR, charIndex, 0L); + POINTS pts = MAKEPOINTS(result); + RECT clientRect; + if (GetClientRect(hEdit, &clientRect) && pts.y > (clientRect.bottom - 14)) + { + windowStyle |= WS_VSCROLL; + } + } + } + + if (windowStyle != originalStyle) + { + SetWindowLongPtr(hEdit, GWL_STYLE, windowStyle); + SetWindowPos(hEdit, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED); + } + + ShowWindow(hEdit, SW_HIDE); + if (0 != ShowWindow(hEdit, (L'\0' != *pszText) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hEdit, NULL, TRUE); +} + +HWND SetupDetails_CreateServiceView(HWND hParent, LPCWSTR pszName, ifc_omservice *service) +{ + return ServicePanel::CreateInstance(hParent, pszName, service, NULL); +} + +BOOL SetupDetails_GetUniqueName(HWND hwnd, LPWSTR pszBuffer, UINT cchBufferMax) +{ + return (BOOL)SendMessage(hwnd, NSDM_GETUNIQUENAME, (WPARAM)cchBufferMax, (LPARAM)pszBuffer); +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetails.h b/Src/Plugins/Library/ml_online/Setup/setupDetails.h new file mode 100644 index 00000000..2afd1b48 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetails.h @@ -0,0 +1,30 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPDETAILS_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPDETAILS_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> + +class ifc_omservice; +class SetupGroup; +class SetupListboxItem; + +#define NSDM_FIRST (WM_APP + 7) +#define NSDM_GETUNIQUENAME (NSDM_FIRST + 0) + +EXTERN_C ATOM DETAILS_PROP; + +BOOL SetupDetails_Initialize(); +void SetupDetails_Uninitialize(); + + +HWND SetupDetails_CreateServiceView(HWND hParent, LPCWSTR pszName, ifc_omservice *service); +HWND SetupDetails_CreateGroupView(HWND hParent, LPCWSTR pszName, SetupGroup *group); +BOOL SetupDetails_GetUniqueName(HWND hwnd, LPWSTR pszBuffer, UINT cchBufferMax); + +// internal +void SetupDetails_SetDescription(HWND hEdit, LPCWSTR pszText); + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPDETAILS_HEADER diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetailsGroup.cpp b/Src/Plugins/Library/ml_online/Setup/setupDetailsGroup.cpp new file mode 100644 index 00000000..38ca9943 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetailsGroup.cpp @@ -0,0 +1,284 @@ +#include "./setupDetails.h" +#include "../common.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include "../../winamp/commandLink.h" +#include "./setupGroup.h" + +#include <commctrl.h> +#include <strsafe.h> + +#ifndef IDC_HELPLINK +#define IDC_HELPLINK 10000 +#endif + +struct GROUPDETAILSCREATEPARAM +{ + GROUPDETAILSCREATEPARAM() : group(NULL), name(NULL) {} + + SetupGroup *group; + LPCWSTR name; +}; + +struct GROUPDETAILS +{ + GROUPDETAILS() : group(NULL), name(NULL), fontTitle(NULL) {} + + SetupGroup *group; + LPWSTR name; + HFONT fontTitle; +}; + +#define GetDetails(__hwnd) ((GROUPDETAILS*)GetPropW((__hwnd), MAKEINTATOM(DETAILS_PROP))) + +static INT_PTR WINAPI GroupDetails_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +HWND SetupDetails_CreateGroupView(HWND hParent, LPCWSTR pszName, SetupGroup *group) +{ + GROUPDETAILSCREATEPARAM param; + param.group = group; + param.name = pszName; + return WASABI_API_CREATEDIALOGPARAMW(IDD_SETUP_GROUPDETAILS, hParent, GroupDetails_DialogProc, (LPARAM)¶m); +} + +static void GroupDetails_SetTitle(HWND hwnd, SetupGroup *group) +{ + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hTitle) return; + + WCHAR szBuffer[128] = {0}; + if (NULL == group || + FAILED(group->GetLongName(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + GROUPDETAILS *details = GetDetails(hwnd); + if (NULL != details && NULL == details->fontTitle) + { + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Arial Bold"); + lf.lfWidth = 0; + lf.lfWeight = FW_DONTCARE; + lf.lfHeight += (lf.lfHeight < 0) ? -2 : +2; + lf.lfQuality = 5/*ANTIALIASED_QUALITY*/; + details->fontTitle = CreateFontIndirect(&lf); + } + + if (NULL != details->fontTitle) + { + SendMessage(hTitle, WM_SETFONT, (WPARAM)details->fontTitle, 0L); + } + } + + SetWindowText(hTitle, szBuffer); + InvalidateRect(hTitle, NULL, TRUE); +} + +static void GroupDetails_SetDescription(HWND hwnd, SetupGroup *group) +{ + HWND hDescription = GetDlgItem(hwnd, IDC_DESCRIPTION); + if (NULL == hDescription) return; + + WCHAR szBuffer[4096] = {0}; + if (NULL == group || + FAILED(group->GetDescription(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + SetupDetails_SetDescription(hDescription, szBuffer); +} + +static BOOL GroupDetails_ShowHelp(HWND hwnd) +{ + INT result = (INT)(INT_PTR)ShellExecuteW(hwnd, L"open", + L"https://help.winamp.com/hc/articles/8112753225364-Online-Services-Security", + NULL, NULL, SW_SHOWNORMAL); + return (result > 32); +} + +static void GroupDetails_UpdateLayout(HWND hwnd, BOOL fRedraw) +{ + RECT clientRect, rect; + if(FALSE == GetClientRect(hwnd, &clientRect)) + return; + + + UINT commonFlags = SWP_NOACTIVATE | SWP_NOZORDER; + if (FALSE != fRedraw) commonFlags |= SWP_NOREDRAW; + + LONG bottomLine = clientRect.bottom; + + HWND hControl; + SIZE linkSize; + RECT linkMargins; + + if (NULL != (hControl = GetDlgItem(hwnd, IDC_HELPLINK)) && + CommandLink_GetIdealSize(hControl, &linkSize)) + { + if (!CommandLink_GetMargins(hControl, &linkMargins)) + SetRectEmpty(&linkMargins); + + if (linkSize.cy > 0) + bottomLine -= linkSize.cy; + + SetWindowPos(hControl, NULL, clientRect.left + 4, bottomLine, linkSize.cx, linkSize.cy, commonFlags); + } + else + { + ZeroMemory(&linkSize, sizeof(linkSize)); + SetRectEmpty(&linkMargins); + } + + if (NULL != (hControl = GetDlgItem(hwnd, IDC_HELPTEXT))) + { + LONG x = clientRect.left + 4 + linkSize.cx/* - linkMargins.right*/; + LONG y = 0; + + HDC hdc = GetDCEx(hControl, NULL, DCX_CACHE | DCX_WINDOW | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT font = (HFONT)SendMessage(hControl, WM_GETFONT, 0, 0L); + HFONT originalFont = (HFONT)SelectObject(hdc, font); + + TEXTMETRICW tm; + if (GetTextMetricsW(hdc, &tm)) + y = tm.tmHeight; + + SelectObject(hdc, originalFont); + ReleaseDC(hControl, hdc); + } + + SetWindowPos(hControl, NULL, x, clientRect.bottom - linkMargins.bottom - y, clientRect.right - x, y, commonFlags); + } + + if (NULL != (hControl = GetDlgItem(hwnd, IDC_DESCRIPTION)) && + FALSE != GetWindowRect(hControl, &rect)) + { + MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rect, 2); + SetWindowPos(hControl, NULL, rect.left, rect.right, rect.right - rect.left, bottomLine - rect.top, + commonFlags | SWP_NOMOVE); + } +} + +static INT_PTR GroupDetails_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam) +{ + GROUPDETAILSCREATEPARAM *param = (GROUPDETAILSCREATEPARAM*)lParam; + + GROUPDETAILS *details = (GROUPDETAILS*)calloc(1, sizeof(GROUPDETAILS)); + if (NULL == details) return FALSE; + + if (!SetProp(hwnd, MAKEINTATOM(DETAILS_PROP), details)) + return FALSE; + + if (NULL != param) + { + if (NULL != param->group) + { + details->group = param->group; + details->group->AddRef(); + } + + details->name = Plugin_CopyString(param->name); + } + + HINSTANCE winampInstance = (NULL != WASABI_API_APP) ? WASABI_API_APP->main_gethInstance() : NULL; + if (NULL != winampInstance) + { + WCHAR szBuffer[256] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_CLICKHERE, szBuffer, ARRAYSIZE(szBuffer)); + HWND hLink = CreateWindowExW(WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT, NWC_COMMANDLINKW, szBuffer, + WS_VISIBLE | WS_CHILD | WS_TABSTOP | CLS_ALWAYSUNDERLINE | CLS_DEFAULTCOLORS /* | CLS_HOTTRACK */, + 0, 0, 0, 0, hwnd, (HMENU)IDC_HELPLINK, winampInstance, NULL); + + if (NULL != hLink) + { + SendMessageW(hLink, WM_SETFONT, (WPARAM)SendMessageW(hwnd, WM_GETFONT, 0, 0L), 0L); + } + } + + GroupDetails_UpdateLayout(hwnd, FALSE); + + if (NULL != param) + { + GroupDetails_SetTitle(hwnd, param->group); + GroupDetails_SetDescription(hwnd, param->group); + } + + return FALSE; +} + +static void GroupDetails_OnDestroy(HWND hwnd) +{ + GROUPDETAILS *details = GetDetails(hwnd); + RemoveProp(hwnd, MAKEINTATOM(DETAILS_PROP)); + + if (NULL != details) + { + if (NULL != details->group) + details->group->Release(); + if (NULL != details->fontTitle) + DeleteObject(details->fontTitle); + + Plugin_FreeString(details->name); + } +} + + +static INT_PTR GroupDetails_OnDialogColor(HWND hwnd, HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hControl); + return 0; +} + + +static INT_PTR GroupDetails_OnStaticColor(HWND hwnd, HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hControl); + return 0; +} + +static LRESULT GroupDetails_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh) +{ + switch(controlId) + { + case IDC_HELPLINK: + if (NM_CLICK == pnmh->code) + GroupDetails_ShowHelp(hwnd); + return TRUE; + } + return 0; +} + +static BOOL GroupDetails_OnGetUniqueName(HWND hwnd, LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return FALSE; + + GROUPDETAILS *details = GetDetails(hwnd); + return SUCCEEDED(StringCchCopy(pszBuffer, cchBufferMax, + (NULL != details && NULL != details->name) ? details->name : L"")); +} +static INT_PTR WINAPI GroupDetails_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return GroupDetails_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: GroupDetails_OnDestroy(hwnd); break; + case WM_CTLCOLORDLG: return GroupDetails_OnDialogColor(hwnd, (HDC)wParam, (HWND)lParam); + case WM_CTLCOLORSTATIC: return GroupDetails_OnStaticColor(hwnd, (HDC)wParam, (HWND)lParam); + case WM_NOTIFY: MSGRESULT(hwnd, GroupDetails_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam)); + + case NSDM_GETUNIQUENAME: MSGRESULT(hwnd, GroupDetails_OnGetUniqueName(hwnd, (LPWSTR)lParam, (UINT)wParam)); + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupDetailsService.cpp b/Src/Plugins/Library/ml_online/Setup/setupDetailsService.cpp new file mode 100644 index 00000000..3e3907fa --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupDetailsService.cpp @@ -0,0 +1,596 @@ +#include "./setupDetails.h" +#include "../common.h" +#include "../resource.h" +#include "../wasabi.h" + +#include <ifc_omservice.h> +#include <ifc_omservicedetails.h> +#include <ifc_omcachemanager.h> +#include <ifc_omserviceevent.h> +#include <ifc_omcachegroup.h> +#include <ifc_omcacherecord.h> +#include <ifc_imageloader.h> +#include <ifc_omgraphics.h> +#include <ifc_omserviceeventmngr.h> + +#include <shlwapi.h> +#include <strsafe.h> + + + +#define GetPanel(__hwnd) ((ServicePanel*)GetPropW((__hwnd), MAKEINTATOM(DETAILS_PROP))) + +#define GET_IDETAILS(__service, __details)\ + (NULL != (service) && SUCCEEDED((service)->QueryInterface(IFC_OmServiceDetails, (void**)&(__details)))) + +static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + + +HWND OmSetupDetails_CreateServiceView(HWND hParent, ifc_omservice *service) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_SETUP_SERVICEDETAILS, hParent, ServicePanel_DialogProc, (LPARAM)service); +} + +static HFONT ServicePanel_PickTitleFont(HWND hwnd, LPCWSTR pszTitle, INT cchTitle, INT maxWidth) +{ + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + + LOGFONT lf; + if (0 == GetObject(dialogFont, sizeof(LOGFONT), &lf)) + return NULL; + + HFONT titleFont = NULL; + if (cchTitle > 0) + { + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Arial Bold"); + lf.lfWidth = 0; + lf.lfWeight = FW_DONTCARE; + lf.lfQuality = 5/*ANTIALIASED_QUALITY*/; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT origFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT); + SIZE textSize; + + INT heightLimit = (lf.lfHeight < 0) ? 1 : -1; + lf.lfHeight += (lf.lfHeight < 0) ? -2 : +2; + do + { + textSize.cx = 0; + if (NULL != titleFont) DeleteObject(titleFont); + titleFont = CreateFontIndirect(&lf); + if (NULL != titleFont) + { + SelectObject(hdc, titleFont); + GetTextExtentPoint32(hdc, pszTitle, cchTitle, &textSize); + } + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + + } while(textSize.cx > maxWidth && lf.lfHeight != heightLimit); + + if (0 == textSize.cx) + { + DeleteObject(titleFont); + titleFont = NULL; + } + + SelectObject(hdc, origFont); + ReleaseDC(hwnd, hdc); + } + } + } + + if (NULL == titleFont && + 0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + titleFont = CreateFontIndirect(&lf); + } + return titleFont; +} + +static void ServicePanel_SetServiceName(HWND hwnd, ifc_omservice *service) +{ + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hTitle) return; + + WCHAR szBuffer[128]; + if (NULL == service || + FAILED(service->GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + + + SERVICEDETAILS *details = GetDetails(hwnd); + if (NULL != details) + { + INT cchBuffer = lstrlen(szBuffer); + RECT rc; + GetClientRect(hTitle, &rc); + HFONT titleFont = ServicePanel_PickTitleFont(hwnd, szBuffer, cchBuffer, rc.right - rc.left); + if (NULL != titleFont) + { + if (NULL != details->fontTitle) DeleteObject(details->fontTitle); + details->fontTitle = titleFont; + SendMessage(hTitle, WM_SETFONT, (WPARAM)details->fontTitle, 0L); + } + } + + SetWindowText(hTitle, szBuffer); + InvalidateRect(hTitle, NULL, TRUE); +} + + +static void ServicePanel_SetServiceDescription(HWND hwnd, ifc_omservice *service) +{ + HWND hDescription = GetDlgItem(hwnd, IDC_DESCRIPTION); + if (NULL == hDescription) return; + + WCHAR szBuffer[4096] = {0}; + + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + details->GetDescription(szBuffer, ARRAYSIZE(szBuffer)); + details->Release(); + } + + OmSetupDetails_SetDescription(hDescription, szBuffer); +} + +static LPCWSTR ServicePanel_FormatDate(LPCWSTR pszDate, LPWSTR pszBuffer, INT cchBufferMax) +{ + SYSTEMTIME st; + ZeroMemory(&st, sizeof(SYSTEMTIME)); + LPCWSTR cursor; + + cursor = pszDate; + INT index = 0; + + for(;;) + { + + INT iVal; + + if (FALSE == StrToIntEx(cursor, STIF_DEFAULT, &iVal) || iVal < 1) + { + index = 0; + break; + } + + if (0 == index) + { + if (iVal < 2000 || iVal > 2100) + break; + st.wYear = iVal; + index++; + } + else if (1 == index) + { + if (iVal < 1 || iVal > 12) + break; + st.wMonth = iVal; + index++; + } + else if (2 == index) + { + if (iVal < 1 || iVal > 31) + break; + st.wDay = iVal; + index++; + } + else + { + index = 0; + break; + } + + while(L'\0' != *cursor && L'-' != *cursor) cursor++; + if (L'-' == *cursor) cursor++; + if (L'\0' == *cursor) + break; + + } + + if (3 == index && + 0 != GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuffer, cchBufferMax)) + { + return pszBuffer; + } + + return pszDate; +} + + + +static HRESULT ServicePanel_GetFullName(ifc_omservicedetails *details, LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + *pszBuffer = L'\0'; + + HRESULT hr = S_OK; + if (NULL != details) + { + hr = details->GetAuthorFirst(pszBuffer, cchBufferMax); + if (SUCCEEDED(hr)) + { + UINT cchBuffer = lstrlen(pszBuffer); + LPWSTR cursor = pszBuffer + cchBuffer; + size_t remaining = cchBufferMax - cchBuffer; + + if (cursor != pszBuffer) + { + hr = StringCchCopyEx(cursor, remaining, L" ", &cursor, &remaining, 0); + if (SUCCEEDED(hr)) + { + hr = details->GetAuthorLast(cursor, (UINT)remaining); + if (FAILED(hr) || L'\0' == *cursor) + { + pszBuffer[cchBuffer] = L'\0'; + } + } + } + } + } + return hr; +} + +static void ServicePanel_SetServiceMeta(HWND hwnd, ifc_omservice *service) +{ + HWND hMeta = GetDlgItem(hwnd, IDC_SERVICEMETA); + if (NULL == hMeta) return; + + WCHAR szBuffer[512] = {0}; + + ifc_omservicedetails *svcdetails = 0; + if (GET_IDETAILS(service, svcdetails)) + { + HRESULT hr = S_OK; + LPWSTR cursor = szBuffer; + WCHAR szValue[256] = {0}, szPrefix[64] = {0}; + size_t remaining = ARRAYSIZE(szBuffer); + + if (SUCCEEDED(ServicePanel_GetFullName(svcdetails, szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_BYAUTHOR, szPrefix, ARRAYSIZE(szPrefix)); + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, szValue); + } + + if (SUCCEEDED(svcdetails->GetUpdated(szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + if (cursor != szBuffer) + hr = StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE); + + if (SUCCEEDED(hr)) + { + WCHAR szDate[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_LASTUPDATED, szPrefix, ARRAYSIZE(szPrefix)); + StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, ServicePanel_FormatDate(szValue, szDate, ARRAYSIZE(szDate))); + } + } + + svcdetails->Release(); + + } + + SERVICEDETAILS *details = GetDetails(hwnd); + if (NULL != details && NULL == details->fontMeta) + { + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Tahoma"); + lf.lfWidth = 0; + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + lf.lfQuality = ANTIALIASED_QUALITY; + details->fontMeta = CreateFontIndirect(&lf); + } + + if (NULL != details->fontMeta) + { + SendMessage(hMeta, WM_SETFONT, (WPARAM)details->fontMeta, 0L); + } + } + + SetWindowText(hMeta, szBuffer); + if (0 != ShowWindow(hMeta, (L'\0' != szBuffer[0]) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hMeta, NULL, TRUE); +} + +static void ServicePanel_SetThumbnail(HWND hwnd, ifc_omservice *service) +{ + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL == hThumbnail) return; + + SendMessage(hThumbnail, WM_SETREDRAW, FALSE, 0L); + + HBITMAP hBitmap; + + BITMAPINFOHEADER header; + void *pixelData; + + WCHAR szPath[2048]; + + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + if (SUCCEEDED(details->GetThumbnail(szPath, ARRAYSIZE(szPath)))) + { + ifc_omcachemanager *cacheManager; + if (SUCCEEDED(OMUTILITY->GetCacheManager(&cacheManager))) + { + ifc_omcachegroup *cacheGroup; + if (SUCCEEDED(cacheManager->Find(L"thumbnail", TRUE, &cacheGroup, NULL))) + { + ifc_omcacherecord *cacheRecord; + if (SUCCEEDED(cacheGroup->Find(szPath, TRUE, &cacheRecord, FALSE))) + { + cacheRecord->Release(); + } + cacheGroup->Release(); + } + cacheManager->Release(); + } + } + details->Release(); + } + + ifc_omimageloader *imageLoader; + if (SUCCEEDED(OMUTILITY->QueryImageLoader(NULL, szPath, FALSE, &imageLoader))) + { + if (FAILED(imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData))) + hBitmap = NULL; + imageLoader->Release(); + } + + if (NULL == hBitmap && + SUCCEEDED(OMUTILITY->QueryImageLoader(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_SERVICE64X64_IMAGE), FALSE, &imageLoader))) + { + if (FAILED(imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData))) + hBitmap = NULL; + imageLoader->Release(); + } + + HBITMAP hTest = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); + if (NULL != hTest) + DeleteObject(hTest); + + if (NULL != hBitmap) + { + hTest = (HBITMAP)SendMessage(hThumbnail, STM_GETIMAGE, IMAGE_BITMAP, 0L); + if (hTest != hBitmap) + { // this is XP and up image copy was created and alpha channel will be handled properly + DeleteObject(hBitmap); + } + else + { // fix alpha channel + if (32 == header.biBitCount) + { + HDC hdcFixed = CreateCompatibleDC(NULL); + if (NULL != hdcFixed) + { + BITMAPINFOHEADER headerFixed; + CopyMemory(&headerFixed, &header, sizeof(BITMAPINFOHEADER)); + BYTE *pixelsFixed; + INT cx = header.biWidth; + INT cy = abs(header.biHeight); + HBITMAP bitmapFixed = CreateDIBSection(NULL, (LPBITMAPINFO)&headerFixed, DIB_RGB_COLORS, (void**)&pixelsFixed, NULL, 0); + + if (NULL != bitmapFixed) + { + HBITMAP bitmapOrig = (HBITMAP)SelectObject(hdcFixed, bitmapFixed); + HBRUSH hb = (HBRUSH)SendMessage(hwnd, WM_CTLCOLORDLG, (WPARAM)hdcFixed, (LPARAM)hwnd); + if (NULL == hb) + hb = GetSysColorBrush(COLOR_3DFACE); + RECT rect; + SetRect(&rect, 0, 0, cx, cy); + FillRect(hdcFixed, &rect, hb); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + HDC hdcSrc = CreateCompatibleDC(NULL); + if (NULL != hdcSrc) + { + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(hdcSrc, hBitmap); + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + + RECT blendRect; + SetRect(&blendRect, 0, 0, cx, cy); + + graphics->Premultiply((BYTE*)pixelData, cx, cy); + graphics->AlphaBlend(hdcFixed, &blendRect, hdcSrc, &blendRect, bf); + + SelectObject(hdcSrc, bitmapSrcOrig); + DeleteDC(hdcSrc); + } + graphics->Release(); + } + + SelectObject(hdcFixed, bitmapOrig); + SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bitmapFixed); + DeleteObject(hBitmap); + + } + DeleteDC(hdcFixed); + } + } + } + } + + RECT clientRect; + if (GetClientRect(hThumbnail, &clientRect)) + { + INT cx = clientRect.right - clientRect.left; + INT cy = clientRect.bottom - clientRect.top; + if (64 != cx || 64 != cy) + { + SetWindowPos(hThumbnail, NULL, 0, 0, 64, 64, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + SendMessage(hThumbnail, WM_SETREDRAW, TRUE, 0L); + + if (0 != ShowWindow(hThumbnail, (NULL != hBitmap) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hThumbnail, NULL, TRUE); +} + + +static void CALLBACK ServicePanel_OnServiceNotify(UINT serviceUid, UINT callbackType, UINT callbackParam, ULONG_PTR user) +{ + HWND hwnd = (HWND)user; + if (NULL == hwnd) return; + + SERVICEDETAILS *details = GetDetails(hwnd); + + if (NULL == details || + NULL == details->service || + serviceUid != details->service->GetId()) + { + return; + } + + switch(callbackType) + { + case OmService::eventServiceModified: + if (0 != (OmService::modifiedName & callbackParam)) + ServicePanel_SetServiceName(hwnd, details->service); + if (0 != (OmService::modifiedDescription & callbackParam)) + ServicePanel_SetServiceDescription(hwnd, details->service); + if (0 != ((OmService::modifiedAuthor | OmService::modifiedDate) & callbackParam)) + ServicePanel_SetServiceMeta(hwnd, details->service); + if (0 != (OmService::modifiedThumbnail & callbackParam)) + ServicePanel_SetThumbnail(hwnd, details->service); + break; + } +} + +static INT_PTR ServicePanel_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam) +{ + ifc_omservice *service = (ifc_omservice*)lParam; + + SERVICEDETAILS *details = (SERVICEDETAILS*)malloc(sizeof(SERVICEDETAILS)); + if (NULL == details) return FALSE; + ZeroMemory(details, sizeof(SERVICEDETAILS)); + + if (!SetProp(hwnd, MAKEINTATOM(DETAILS_PROP), details)) + return FALSE; + + details->service = service; + details->service->AddRef(); + + ServicePanel_SetServiceName(hwnd, service); + ServicePanel_SetServiceDescription(hwnd, service); + ServicePanel_SetThumbnail(hwnd, service); + ServicePanel_SetServiceMeta(hwnd, service); + + if (NULL != service) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->GetEventManager(&eventManager))) + { + if (SUCCEEDED(eventManager->RegisterHandler(eventHander))) + { + details->eventHandler = eventHandler; + } + else + { + eventHandler->Release(); + } + } + } + + return FALSE; +} + +static void ServicePanel_OnDestroy(HWND hwnd) +{ + OMSERVICEMNGR->UnregisterCallback(ServicePanel_OnServiceNotify, (ULONG_PTR)hwnd); + + SERVICEDETAILS *details = GetDetails(hwnd); + RemoveProp(hwnd, MAKEINTATOM(DETAILS_PROP)); + + if (NULL != details) + { + if (NULL != details->service) + details->service->Release(); + if (NULL != details->fontTitle) + DeleteObject(details->fontTitle); + if (NULL != details->fontMeta) + DeleteObject(details->fontMeta); + } + + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL != hThumbnail) + { + HBITMAP hBitmap = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, 0L); + if (NULL != hBitmap) + DeleteObject(hBitmap); + } +} + + +static INT_PTR ServicePanel_OnDialogColor(HWND hwnd, HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hControl); + return 0; +} + + +static INT_PTR ServicePanel_OnStaticColor(HWND hwnd, HDC hdc, HWND hControl) +{ + INT_PTR result = 0; + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + result = (INT_PTR)SendMessage(hParent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hControl); + + INT controlId = GetDlgCtrlID(hControl); + switch(controlId) + { + case IDC_SERVICEMETA: + { + COLORREF rgbBk = GetBkColor(hdc); + COLORREF rgbFg = GetTextColor(hdc); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + graphics->BlendColor(rgbFg, rgbBk, 180, &rgbFg); + graphics->Release(); + } + + SetTextColor(hdc, rgbFg); + } + break; + } + return result; +} + +static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return ServicePanel_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: ServicePanel_OnDestroy(hwnd); break; + case WM_CTLCOLORDLG: return ServicePanel_OnDialogColor(hwnd, (HDC)wParam, (HWND)lParam); + case WM_CTLCOLORSTATIC: return ServicePanel_OnStaticColor(hwnd, (HDC)wParam, (HWND)lParam); + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroup.cpp b/Src/Plugins/Library/ml_online/Setup/setupGroup.cpp new file mode 100644 index 00000000..bf1faf28 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroup.cpp @@ -0,0 +1,929 @@ +#include "./setupGroup.h" +#include "./setupGroupFilter.h" +#include "./setupListboxLabel.h" +#include "./setupDetails.h" +#include "./setupPage.h" +#include "../common.h" +#include "../api__ml_online.h" +#include "../resource.h" +#include "../serviceHost.h" +#include "../serviceHelper.h" + +#include "../../nu/menuHelpers.h" +#include <vector> + +#include <ifc_omservice.h> +#include <ifc_omstorage.h> +#include <ifc_omstorageasync.h> +#include <ifc_omserviceenum.h> +#include <ifc_omfilestorage.h> + +#include <shlwapi.h> +#include <strsafe.h> +#include <algorithm> + +typedef std::vector<ifc_omservice*> ServiceList; + +#define GROUP_MARGINCX 0 +#define GROUP_MARGINCY 1 + +#define TEXT_OFFSET_LEFT 2 +#define TEXT_OFFSET_BOTTOM 2 +#define TEXT_ALIGN (TA_LEFT | TA_BOTTOM) + +SetupGroup::SetupGroup(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle) + : ref(1), id(groupId), name(NULL), flags(0), emptyLabel(NULL), errorCode(S_OK), hPage(NULL), + longName(NULL), description(NULL), address(NULL), loadResult(NULL), style(fStyle), loadComplete(NULL) +{ + name = Plugin_DuplicateResString(pszName); + address = Plugin_DuplicateResString(pszAddress); + this->storageId = (NULL != storageId) ? *storageId : GUID_NULL; + this->filterId = (NULL != filterId) ? *filterId : GUID_NULL; + + InitializeCriticalSection(&lock); +} + +SetupGroup::~SetupGroup() +{ + Plugin_FreeResString(name); + Plugin_FreeResString(address); + + SetLongName(NULL); + SetDescription(NULL); + + EnterCriticalSection(&lock); + + size_t index = list.size(); + while(index--) + { + list[index]->Release(); + } + + if (NULL != emptyLabel) + emptyLabel->Release(); + + if (NULL != loadResult) + { + ifc_omstorage *storage; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage); + if (SUCCEEDED(hr)) + { + storage->RequestAbort(loadResult, TRUE); + } + + loadResult->Release(); + loadResult = NULL; + } + + if (NULL != loadComplete) + CloseHandle(loadComplete); + + LeaveCriticalSection(&lock); + + DeleteCriticalSection(&lock); + +} + +SetupGroup *SetupGroup::CreateInstance(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle) +{ + return new SetupGroup(groupId, pszName, pszAddress, storageId, filterId, fStyle); +} + +ULONG SetupGroup::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupGroup::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +HRESULT SetupGroup::GetName(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + if (NULL != name) + { + if (IS_INTRESOURCE(name)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)name, pszBuffer, cchBufferMax); + hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + else + { + hr = StringCchCopyW(pszBuffer, cchBufferMax, name); + } + } + else + { + hr = StringCchCopyW(pszBuffer, cchBufferMax, L"Unknown"); + } + return hr; +} + +HRESULT SetupGroup::GetLongName(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + if (NULL == longName) + return GetName(pszBuffer, cchBufferMax); + + if (IS_INTRESOURCE(longName)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)longName, pszBuffer, cchBufferMax); + hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + else + { + hr = StringCchCopyW(pszBuffer, cchBufferMax, longName); + } + return hr; +} + +HRESULT SetupGroup::GetDescription(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + HRESULT hr; + + if (NULL != description && IS_INTRESOURCE(description)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)description, pszBuffer, cchBufferMax); + hr = (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + else + { + hr = StringCchCopyEx(pszBuffer, cchBufferMax, description, NULL, NULL, STRSAFE_IGNORE_NULLS); + } + return hr; +} +size_t SetupGroup::GetRecordCount() +{ + return list.size(); +} + +size_t SetupGroup::GetListboxCount() +{ + if (0 != (flagCollapsed & flags)) return 0; + size_t listSize = list.size(); + + if (0 == listSize) + { + return (NULL != emptyLabel && FALSE == emptyLabel->IsNameNull()) ? 1 : 0; + } + + return listSize; +} + +SetupListboxItem *SetupGroup::GetListboxItem(size_t index) +{ + if (0 != (flagCollapsed & flags)) return NULL; + size_t listSize = list.size(); + + if (0 == listSize) + { + return (NULL != emptyLabel && FALSE == emptyLabel->IsNameNull()) ? emptyLabel : NULL; + } + return list[index]; +} + +BOOL SetupGroup::IsModified() +{ + size_t index = list.size(); + while(index--) + { + if (list[index]->IsModified()) + return TRUE; + } + + return FALSE; +} + +BOOL SetupGroup::IsExpanded() +{ + return (0 == (flagCollapsed & flags)); +} + +void SetupGroup::SetExpanded(BOOL fExpanded) +{ + if ((FALSE == fExpanded) == (FALSE == IsExpanded())) + return; + + if (FALSE == fExpanded) + flags |= flagCollapsed; + else + flags &= ~flagCollapsed; +} + +void SetupGroup::Clear(BOOL fInvalidate) +{ + size_t index = list.size(); + if (0 == index) return; + + EnterCriticalSection(&lock); + + while(index--) + { + SetupRecord *record = list[index]; + if (NULL != record) + { + record->Release(); + } + } + list.clear(); + + LeaveCriticalSection(&lock); + + SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_EMPTYGROUP), FALSE); + + if (FALSE != fInvalidate && NULL != hPage) + PostMessage(hPage, SPM_UPDATELIST, (WPARAM)id, NULL); +} + +static void CALLBACK SetupGroup_LoadCallback(ifc_omstorageasync *result) +{ + if (NULL == result) return; + SetupGroup *group; + if (SUCCEEDED(result->GetData((void**)&group)) && NULL != group) + { + group->OnLoadCompleted(); + } +} + + +__inline static int __cdecl SetupGroup_AlphabeticalSorter(const void *elem1, const void *elem2) +{ + SetupRecord *record1 = (SetupRecord*)elem1; + SetupRecord *record2 = (SetupRecord*)elem2; + + if (NULL == record1 || NULL == record2) + return (INT)(INT_PTR)(record1 - record2); + + ifc_omservice *svc1 = record1->GetService(); + ifc_omservice *svc2 = record2->GetService(); + + if (NULL == svc1 || NULL == svc2) + return (INT)(INT_PTR)(svc1 - svc2); + + WCHAR szBuffer1[256] = {0}, szBuffer2[256] = {0}; + if (FAILED(svc1->GetName(szBuffer1, ARRAYSIZE(szBuffer1)))) + szBuffer1[0] = L'\0'; + if (FAILED(svc2->GetName(szBuffer2, ARRAYSIZE(szBuffer2)))) + szBuffer2[0] = L'\0'; + + return CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, szBuffer1, -1, szBuffer2, -1) - 2; +} + +__inline static bool __cdecl SetupGroup_AlphabeticalSorter_V2(const void* elem1, const void* elem2) +{ + return SetupGroup_AlphabeticalSorter(elem1, elem2) < 0; +} +void SetupGroup::OnLoadCompleted() +{ + ifc_omstorage *storage; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage); + if (SUCCEEDED(hr)) + { + ifc_omserviceenum *serviceEnum; + hr = storage->EndLoad(loadResult, &serviceEnum); + if (SUCCEEDED(hr)) + { + SetupGroupFilter *filter; + if (FAILED(SetupGroupFilter::CreateInstance(&filterId, &filter))) + { + filter = NULL; + } + else if (FAILED(filter->Initialize())) + { + filter->Release(); + filter = NULL; + } + + EnterCriticalSection(&lock); + + ifc_omservice *service; + UINT filterResult, defaultFilter; + defaultFilter = SetupGroupFilter::serviceInclude; + if (0 != (styleDefaultUnsubscribed & style)) + defaultFilter |= SetupGroupFilter::serviceForceUnsubscribe; + else if (0 != (styleDefaultSubscribed & style)) + defaultFilter |= SetupGroupFilter::serviceForceSubscribe; + + while(S_OK == serviceEnum->Next(1, &service, NULL)) + { + + filterResult = defaultFilter; + if (NULL != filter && FAILED(filter->ProcessService(service, &filterResult))) + filterResult = defaultFilter; + + if (0 == (SetupGroupFilter::serviceInclude & filterResult)) + { + service->Release(); + service = NULL; + continue; + } + + if (0 != (SetupGroupFilter::serviceForceUnsubscribe & filterResult)) + ServiceHelper_Subscribe(service, TRUE, 0); + else if (0 != (SetupGroupFilter::serviceForceSubscribe & filterResult)) + ServiceHelper_Subscribe(service, FALSE, 0); + + if (0 != (styleSaveAll & style)) + ServiceHelper_MarkModified(service, (UINT)-1, (UINT)-1); + + SetupRecord *record = SetupRecord::CreateInstance(service); + if (NULL != record) + { + if (0 != (SetupGroupFilter::serviceForceUnsubscribe & filterResult)) + record->SetSelected(FALSE); + else if (0 != (SetupGroupFilter::serviceForceSubscribe & filterResult)) + record->SetSelected(TRUE); + list.push_back(record); + } + + service->Release(); + } + + if (0 != (styleSortAlphabetically & style)) + { + //qsort(list.first(), list.size(), sizeof(SetupRecord*), SetupGroup_AlphabeticalSorter); + std::sort(list.begin(), list.end(), SetupGroup_AlphabeticalSorter_V2); + } + + LeaveCriticalSection(&lock); + + serviceEnum->Release(); + if (NULL != filter) + filter->Release(); + } + + storage->Release(); + } + + EnterCriticalSection(&lock); + + loadResult->Release(); + loadResult = NULL; + + if (NULL != loadComplete) + { + SetEvent(loadComplete); + CloseHandle(loadComplete); + loadComplete = NULL; + } + + LeaveCriticalSection(&lock); + + LPCWSTR pszText = MAKEINTRESOURCE(((FAILED(hr)) ? IDS_SETUP_GROUPLOADFAILED : IDS_SETUP_EMPTYGROUP)); + SetEmptyText( pszText, TRUE); +} + +HRESULT SetupGroup::RequestReload() +{ + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + HRESULT hr; + + EnterCriticalSection(&lock); + + if (NULL != loadResult) + hr = E_PENDING; + else + { + if (NULL != loadComplete) + { + CloseHandle(loadComplete); + loadComplete = NULL; + } + + Clear(FALSE); + SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_LOADINGGROUP), TRUE); + + ifc_omstorage *storage; + hr = OMSERVICEMNGR->QueryStorage(&storageId, &storage); + if (SUCCEEDED(hr)) + { + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + hr = storage->BeginLoad(address, serviceHost, SetupGroup_LoadCallback, this, &loadResult); + storage->Release(); + + if (NULL != serviceHost) + serviceHost->Release(); + } + + if (FAILED(hr)) + { + SetEmptyText(MAKEINTRESOURCE(IDS_SETUP_GROUPLOADFAILED), TRUE); + } + } + + LeaveCriticalSection(&lock); + + return hr; +} + +void SetupGroup::SetPageWnd(HWND hPage) +{ + this->hPage = hPage; +} + +HRESULT SetupGroup::SignalLoadCompleted(HANDLE event) +{ + HRESULT hr; + if (NULL == event) return E_INVALIDARG; + + EnterCriticalSection(&lock); + + if (NULL == loadResult) + { + SetEvent(event); + hr = S_OK; + } + else + { + if (NULL != loadComplete) + CloseHandle(loadComplete); + + if (FALSE == DuplicateHandle(GetCurrentProcess(), event, GetCurrentProcess(), &loadComplete, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + DWORD error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + } + + hr = S_OK; + } + + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT SetupGroup::Save(SetupLog *log) +{ + HRESULT hr(S_OK); + size_t index = list.size(); + while(index--) + { + if (FAILED(list[index]->Save(log))) + hr = E_FAIL; + } + return hr; +} + +void SetupGroup::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut) +{ + COLORREF rgbBk, rgbText; + + + if (0 != (ODS_DISABLED & state)) + { + rgbBk = GetBkColor(hdc); + rgbText = GetSysColor(COLOR_GRAYTEXT); + } + else + { + if (0 != (ODS_SELECTED & state)) + { + if (0 == (ODS_INACTIVE & state)) + { + rgbBk = GetSysColor(COLOR_HIGHLIGHT); + rgbText = GetSysColor(COLOR_HIGHLIGHTTEXT); + } + else + { + rgbBk = GetSysColor(COLOR_3DFACE); + rgbText = GetSysColor(COLOR_WINDOWTEXT); + } + } + else + { + rgbBk = GetSysColor(COLOR_WINDOW); + rgbText = GetSysColor(COLOR_WINDOWTEXT); + } + } + + if (NULL != rgbBkOut) *rgbBkOut = rgbBk; + if (NULL != rgbTextOut) *rgbTextOut = rgbText; +} + +HBRUSH SetupGroup::GetBrush(HDC hdc, UINT state) +{ + if (0 != (ODS_DISABLED & state)) + { + return GetSysColorBrush(COLOR_WINDOW); + } + if (0 != (ODS_COMBOBOXEDIT & state)) + { + return GetSysColorBrush(COLOR_WINDOWTEXT); + } + if (0 != (ODS_SELECTED & state)) + { + return GetSysColorBrush( (0 == (ODS_INACTIVE & state)) ? COLOR_HIGHLIGHT : COLOR_3DFACE); + } + + return GetSysColorBrush(COLOR_WINDOW); +} + +BOOL SetupGroup::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) +{ + HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return FALSE; + + HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont()); + SIZE imageSize; + if (!instance->GetExpandboxMetrics(hdc, IsExpanded(), &imageSize)) + ZeroMemory(&imageSize, sizeof(SIZE)); + + if (NULL != cy) + { + *cy = 0; + TEXTMETRIC tm; + if (GetTextMetrics(hdc, &tm)) + { + *cy = tm.tmHeight + tm.tmExternalLeading; + if (imageSize.cy > (INT)*cy) *cy = imageSize.cy; + *cy += GROUP_MARGINCY*2; + } + } + + if (NULL != cx) + { + *cx = imageSize.cx; + WCHAR szBuffer[128] = {0}; + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + INT cchBuffer = lstrlenW(szBuffer); + SIZE textSize; + if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize)) + { + *cx += textSize.cx; + } + } + if (0 != *cx) *cx += GROUP_MARGINCX*2; + } + + SelectObject(hdc, originalFont); + ReleaseDC(instance->GetHwnd(), hdc); + return TRUE; +} + + +static void SetupGroup_DrawFrame(HDC hdc, const RECT *prc, INT width, COLORREF rgbFrame) +{ + if (width > 0) + { + COLORREF rgbOld = SetBkColor(hdc, rgbFrame); + + RECT rcPart; + SetRect(&rcPart, prc->left, prc->top, prc->right, prc->top + width); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + SetRect(&rcPart, prc->left, prc->bottom - width, prc->right, prc->bottom); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + SetRect(&rcPart, prc->left, prc->top + width, prc->left + width, prc->bottom - width); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + SetRect(&rcPart, prc->right - width, prc->top + width, prc->right, prc->bottom - width); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL); + + if (rgbOld != rgbFrame) + SetBkColor(hdc, rgbOld); + } +} +BOOL SetupGroup::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) +{ + LONG paintLeft = prc->left + GROUP_MARGINCX; + RECT partRect; + + SetRectEmpty(&partRect); + + COLORREF rgbBk, rgbText; + GetColors(hdc, state, &rgbBk, &rgbText); + + COLORREF origBk = SetBkColor(hdc, rgbBk); + COLORREF origText = SetTextColor(hdc, rgbText); + UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN); + + HRGN backRgn, rgn; + backRgn = CreateRectRgnIndirect(prc); + rgn = CreateRectRgn(0,0,0,0); + + SetRectEmpty(&partRect); + if (instance->GetExpandboxMetrics(hdc, IsExpanded(), (((SIZE*)&partRect) + 1))) + { + INT space = (prc->bottom - prc->top) - (partRect.bottom- partRect.top); + INT offsetY = space / 2 + space%2; + if (offsetY < 0) offsetY = 0; + OffsetRect(&partRect, paintLeft, prc->top + offsetY); + if (instance->DrawExpandbox(hdc, IsExpanded(), &partRect, rgbBk, rgbText)) + { + paintLeft = partRect.right; + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + } + + WCHAR szBuffer[128] = {0}; + INT cchBuffer = 0; + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + cchBuffer = lstrlenW(szBuffer); + + SetRect(&partRect, paintLeft, prc->top, prc->right, prc->bottom); + if (ExtTextOut(hdc, partRect.left + TEXT_OFFSET_LEFT, partRect.bottom - TEXT_OFFSET_BOTTOM, + ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL)) + { + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + + + COLORREF rgbLine = ColorAdjustLuma(rgbBk, -150, TRUE); + if (rgbLine != rgbBk) + { + RECT lineRect; + SetRect(&lineRect, prc->left, prc->bottom - 1, prc->right, prc->bottom); + + SetBkColor(hdc, rgbLine); + if (ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &lineRect, NULL, 0, NULL)) + { + if (SetRectRgn(rgn, lineRect.left, lineRect.top, lineRect.right, lineRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + SetBkColor(hdc, rgbBk); + } + + if (0 != (flagMenuActive & flags)) + { + COLORREF rgbFrame = rgbLine; //ColorAdjustLuma(GetSysColor(COLOR_HIGHLIGHT), 100, TRUE); + SetupGroup_DrawFrame(hdc, prc, 1, rgbFrame); + if (SetRectRgn(rgn, prc->left + 1, prc->top + 1, prc->right - 1, prc->bottom - 1)) + CombineRgn(backRgn, backRgn, rgn, RGN_AND); + } + + + if (NULL != backRgn) + { + FillRgn(hdc, backRgn, GetBrush(hdc, state)); + DeleteObject(backRgn); + } + if (NULL != rgn) + DeleteObject(rgn); + + + + if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state)) + DrawFocusRect(hdc, prc); + + if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign); + if (origBk != rgbBk) SetBkColor(hdc, origBk); + if (origText != rgbText) SetTextColor(hdc, origText); + return TRUE; +} + +INT_PTR SetupGroup::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) +{ + switch(vKey) + { + case VK_SPACE: + InvertExpanded(instance); + return -2; + } + return -1; +} +BOOL SetupGroup::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupGroup::MouseLeave(SetupListbox *instance, const RECT *prcItem) +{ + return FALSE; +} +BOOL SetupGroup::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupGroup::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupGroup::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + InvertExpanded(instance); + return TRUE; +} + +BOOL SetupGroup::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return TRUE; +} + +BOOL SetupGroup::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + HMENU hMenu = instance->GetContextMenu(SetupListbox::menuGroupContext); + if (NULL == hMenu) + return FALSE; + + hMenu = MenuHelper_DuplcateMenu(hMenu); + if (NULL == hMenu) return FALSE; + + MENUITEMINFO mi; + mi.cbSize = sizeof(MENUITEMINFO); + mi.fMask = MIIM_STATE; + GetMenuItemInfo(hMenu, ID_GROUP_TOGGLE, FALSE, &mi); + + mi.fMask = 0; + if (0 == (MFS_DEFAULT & mi.fState)) + { + mi.fMask |= MIIM_STATE; + mi.fState |= MFS_DEFAULT; + } + + WCHAR szBuffer[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(((IsExpanded()) ? IDS_COLLAPSE : IDS_EXPAND), szBuffer, ARRAYSIZE(szBuffer)); + mi.fMask |= MIIM_STRING; + mi.dwTypeData = szBuffer; + + if (0 != mi.fMask) + SetMenuItemInfo(hMenu, ID_GROUP_TOGGLE, FALSE, &mi); + + if (0 == list.size()) + { + EnableMenuItem(hMenu, ID_GROUP_SELECTALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + EnableMenuItem(hMenu, ID_GROUP_UNSELECTALL, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + } + + if (0 != (flagLoading & flags)) + { + EnableMenuItem(hMenu, ID_GROUP_RELOAD, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + } + + MapWindowPoints(instance->GetHwnd(), HWND_DESKTOP, &pt, 1); + + flags |= flagMenuActive; + instance->InvalidateRect(prcItem, TRUE); + + INT cmd = TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, instance->GetHwnd(), NULL); + if (0 != cmd) + { + Command(instance, cmd, 0); + } + + DestroyMenu(hMenu); + + flags &= ~flagMenuActive; + instance->InvalidateRect(prcItem, TRUE); + + return TRUE; +} + +void SetupGroup::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) +{ +} + +void SetupGroup::InvertExpanded(SetupListbox *instance) +{ + if (FALSE != IsExpanded()) + ValidateSelection(instance); + + SetExpanded(!IsExpanded()); + if (NULL != instance) + { + instance->UpdateCount(); + UpdateWindow(instance->GetHwnd()); + } +} +void SetupGroup::SelectAll(SetupListbox *instance, BOOL fSelect) +{ + size_t index = list.size(); + + INT baseIndex; + if (NULL == instance || FALSE == instance->GetIndex(this, &baseIndex)) + baseIndex = -1; + else + baseIndex++; + + while(index--) + { + SetupRecord *record = list[index]; + if (NULL != record && !record->IsDisabled()) + { + if ((FALSE == fSelect) != (FALSE == record->IsSelected())) + { + record->SetSelected(fSelect); + if (0 == (flagCollapsed & flags) && NULL != instance && -1 != baseIndex) + { + instance->InvalidateItem((INT)(baseIndex + index), TRUE); + } + } + } + } +} + + +void SetupGroup::SetEmptyText(LPCWSTR pszText, BOOL fInvalidate) +{ + if (NULL == emptyLabel) + emptyLabel = SetupListboxLabel::CreateInstance(pszText); + else + emptyLabel->SetName(pszText); + + if (FALSE != fInvalidate && NULL != hPage) + PostMessage(hPage, SPM_UPDATELIST, (WPARAM)id, NULL); +} + +HWND SetupGroup::CreateDetailsView(HWND hParent) +{ + WCHAR szName[64] = {0}; + if (FALSE == GetUniqueName(szName, ARRAYSIZE(szName))) + szName[0] = L'\0'; + + return SetupDetails_CreateGroupView(hParent, szName, this); +} + +BOOL SetupGroup::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer || + FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"grp_id_%d", id))) + { + return FALSE; + } + return TRUE; +} + + +void SetupGroup::SetLongName(LPCWSTR pszText) +{ + if (NULL != longName && !IS_INTRESOURCE(longName)) + Plugin_FreeString(longName); + longName = NULL; + + if (NULL != pszText) + longName = (IS_INTRESOURCE(pszText)) ? (LPWSTR)pszText : Plugin_CopyString(pszText); +} + +void SetupGroup::SetDescription(LPCWSTR pszText) +{ + if (NULL != description && !IS_INTRESOURCE(description)) + Plugin_FreeString(description); + description = NULL; + if (NULL != pszText) + description = (IS_INTRESOURCE(pszText)) ? (LPWSTR)pszText : Plugin_CopyString(pszText); +} + +void SetupGroup::ValidateSelection(SetupListbox *instance) +{ + if (NULL == instance) + return; + + SetupListboxItem *selection = instance->GetSelection(); + if (NULL != selection) + { + EnterCriticalSection(&lock); + size_t index = list.size(); + while(index--) + { + if (list[index] == selection) + { + instance->SetSelection(this); + break; + } + } + + LeaveCriticalSection(&lock); + } +} + +void SetupGroup::Command(SetupListbox *instance, INT commandId, INT eventId) +{ + switch(commandId) + { + case ID_GROUP_TOGGLE: + InvertExpanded(instance); + break; + case ID_GROUP_SELECTALL: + SelectAll(instance, TRUE); + break; + case ID_GROUP_UNSELECTALL: + SelectAll(instance, FALSE); + break; + case ID_GROUP_RELOAD: + ValidateSelection(instance); + RequestReload(); + break; + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroup.h b/Src/Plugins/Library/ml_online/Setup/setupGroup.h new file mode 100644 index 00000000..ce3f3c5f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroup.h @@ -0,0 +1,131 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUP_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUP_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupRecord.h" +#include "./setupListbox.h" +#include <vector> + +class SetupListboxLabel; +class SetupLog; +class SetupPage; +class ifc_omstorage; + +class SetupGroup : public SetupListboxItem +{ +public: + typedef enum + { + styleDefaultUnsubscribed = 0x00000001, + styleDefaultSubscribed = 0x00000002, + styleSortAlphabetically = 0x00000008, + styleSaveAll = 0x00000010, + } GroupStyles; +protected: + typedef enum + { + flagCollapsed = 0x0001, + flagMenuActive = 0x0002, + flagLoading = 0x0004, + } GroupFlags; + +protected: + SetupGroup(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle); + ~SetupGroup(); + +public: + static SetupGroup *CreateInstance(INT groupId, LPCWSTR pszName, LPCWSTR pszAddress, const GUID *storageId, const GUID *filterId, UINT fStyle); + +public: + ULONG AddRef(); + ULONG Release(); + + INT GetId() { return id; } + HRESULT GetName(LPWSTR pszBuffer, INT cchBufferMax); + HRESULT GetLongName(LPWSTR pszBuffer, INT cchBufferMax); + HRESULT GetDescription(LPWSTR pszBuffer, INT cchBufferMax); + + size_t GetRecordCount(); + SetupRecord *GetRecord(size_t index) { return list[index]; } + + size_t GetListboxCount(); + SetupListboxItem *GetListboxItem(size_t index); + + BOOL IsModified(); + + BOOL IsExpanded(); + void SetExpanded(BOOL fExpanded); + void SelectAll(SetupListbox *instance, BOOL fSelect); + + HRESULT RequestReload(); + HRESULT Save(SetupLog *log); + + + void SetEmptyText(LPCWSTR pszText, BOOL fInvalidate); + void SetLongName(LPCWSTR pszText); + void SetDescription(LPCWSTR pszText); + + void GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut); + HBRUSH GetBrush(HDC hdc, UINT state); + + HRESULT SignalLoadCompleted(HANDLE event); + void ValidateSelection(SetupListbox *instance); + + /* SetupListboxItem */ + BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy); + BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state); + INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey); + BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem); + BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured); + BOOL IsDisabled() { return FALSE; } + void Command(SetupListbox *instance, INT commandId, INT eventId); + HWND CreateDetailsView(HWND hParent); + BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + + void SetError(HRESULT code) { errorCode = code; } + HRESULT GetError() { return errorCode; } + + void Clear(BOOL fInvalidate); + + void SetPageWnd(HWND hPage); + +protected: + void InvertExpanded(SetupListbox *instance); + void OnLoadCompleted(); + + +private: + friend static void CALLBACK SetupGroup_LoadCallback(ifc_omstorageasync *result); + + +protected: + ULONG ref; + INT id; + LPWSTR name; + LPWSTR longName; + LPWSTR description; + UINT style; + UINT flags; + LPWSTR address; + GUID storageId; + GUID filterId; + HRESULT errorCode; + std::vector<SetupRecord*> list; + SetupListboxLabel *emptyLabel; + CRITICAL_SECTION lock; + ifc_omstorageasync *loadResult; + HWND hPage; + HANDLE loadComplete; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUP_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroupFilter.cpp b/Src/Plugins/Library/ml_online/Setup/setupGroupFilter.cpp new file mode 100644 index 00000000..c4d4311f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroupFilter.cpp @@ -0,0 +1,226 @@ +#include "./setupGroupFilter.h" +#include "../api__ml_online.h" +#include "../serviceHost.h" +#include "../config.h" + +#include <ifc_omservice.h> +#include <ifc_omstorage.h> +#include <ifc_omserviceenum.h> +#include <ifc_omfilestorage.h> + + +SetupGroupFilter::SetupGroupFilter(const GUID *filterId) + : ref(1) +{ + id = (NULL != filterId) ? *filterId : GUID_NULL; +} + +SetupGroupFilter::~SetupGroupFilter() +{ +} + +HRESULT SetupGroupFilter::CreateInstance(const GUID *filterId, SetupGroupFilter **instance) +{ + if (NULL == filterId) + { + *instance = NULL; + return E_INVALIDARG; + } + + if (FALSE != IsEqualGUID(*filterId, FUID_SetupFeaturedGroupFilter)) + return SetupFeaturedGroupFilter::CreateInstance((SetupFeaturedGroupFilter**)instance); + if (FALSE != IsEqualGUID(*filterId, FUID_SetupKnownGroupFilter)) + return SetupKnownGroupFilter::CreateInstance((SetupKnownGroupFilter**)instance); + + *instance = NULL; + return E_NOINTERFACE; +} + +ULONG SetupGroupFilter::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupGroupFilter::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +HRESULT SetupGroupFilter::GetId(GUID *filterId) +{ + if (NULL == filterId) + return E_POINTER; + *filterId = id; + return S_OK; +} + +BOOL CALLBACK SetupGroupFilter::AppendServiceIdCallback(UINT serviceId, void *data) +{ + ServiceIdList *list = (ServiceIdList*)data; + if (NULL == list) return FALSE; + list->push_back(serviceId); + return TRUE; +} + +SetupFeaturedGroupFilter::SetupFeaturedGroupFilter() + : SetupGroupFilter(&FUID_SetupFeaturedGroupFilter) +{ +} + +SetupFeaturedGroupFilter::~SetupFeaturedGroupFilter() +{ +} + +HRESULT SetupFeaturedGroupFilter::CreateInstance(SetupFeaturedGroupFilter **instance) +{ + if (NULL == instance) + return E_POINTER; + + *instance = new SetupFeaturedGroupFilter(); + if (NULL == *instance) return E_OUTOFMEMORY; + + return S_OK; +} + +HRESULT SetupFeaturedGroupFilter::Initialize() +{ + HRESULT hr; + ifc_omstorage *storage; + + filterList.clear(); + + if (NULL == OMSERVICEMNGR) + return E_UNEXPECTED; + + hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageIni, &storage); + if(FAILED(hr)) + return hr; + + ServiceHost *serviceHost; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + ifc_omserviceenum *serviceEnum; + hr = storage->Load(L"*.ini", serviceHost, &serviceEnum); + if(SUCCEEDED(hr)) + { + ifc_omservice *service; + while(S_OK == serviceEnum->Next(1, &service, NULL) && NULL != service) + { + filterList.push_back(service->GetId()); + } + serviceEnum->Release(); + } + storage->Release(); + + ServiceIdList promoList; + Config_ReadServiceIdList("Setup", "featuredExtra", ',', AppendServiceIdCallback, &promoList); + + ServiceIdList historyList; + Config_ReadServiceIdList("Setup", "featuredHistory", ',', AppendServiceIdCallback, &historyList); + + size_t index = historyList.size(); + size_t filterIndex, filterSize = filterList.size(); + + while(index--) + { + size_t promoSize = promoList.size(); + for(filterIndex = 0; filterIndex < promoSize; filterIndex++) + { + if (promoList[filterIndex] == historyList[index]) + { + promoList.erase(promoList.begin() + filterIndex); + break; + } + } + if (filterIndex == promoSize) + { + for(filterIndex = 0; filterIndex < filterSize; filterIndex++) + { + if (filterList[filterIndex] == historyList[index]) + break; + } + + if (filterIndex == filterSize) + filterList.push_back(historyList[index]); + } + } + + return hr; +} + +HRESULT SetupFeaturedGroupFilter::ProcessService(ifc_omservice *service, UINT *filterResult) +{ + if (NULL == service) + return E_INVALIDARG; + + if (NULL == filterResult) + return E_POINTER; + + size_t index = filterList.size(); + while(index--) + { + if (filterList[index] == service->GetId()) + { + filterList.erase(filterList.begin() + index); + *filterResult = serviceIgnore; + break; + } + } + return S_OK; +} + +SetupKnownGroupFilter::SetupKnownGroupFilter() + : SetupGroupFilter(&FUID_SetupKnownGroupFilter) +{ +} + +SetupKnownGroupFilter::~SetupKnownGroupFilter() +{ +} + +HRESULT SetupKnownGroupFilter::CreateInstance(SetupKnownGroupFilter **instance) +{ + if (NULL == instance) + return E_POINTER; + + *instance = new SetupKnownGroupFilter(); + if (NULL == *instance) return E_OUTOFMEMORY; + + return S_OK; +} + +HRESULT SetupKnownGroupFilter::Initialize() +{ + Config_ReadServiceIdList("Setup", "featuredExtra", ',', AppendServiceIdCallback, &filterList); + return S_OK; +} + +HRESULT SetupKnownGroupFilter::ProcessService(ifc_omservice *service, UINT *filterResult) +{ + if (NULL == service) + return E_INVALIDARG; + + if (NULL == filterResult) + return E_POINTER; + + size_t index = filterList.size(); + while(index--) + { + if (filterList[index] == service->GetId()) + { + filterList.erase(filterList.begin() + index); + *filterResult &= ~serviceForceUnsubscribe; + *filterResult |= serviceForceSubscribe; + break; + } + } + + return S_OK; +} diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroupList.cpp b/Src/Plugins/Library/ml_online/Setup/setupGroupList.cpp new file mode 100644 index 00000000..9ee1de1f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroupList.cpp @@ -0,0 +1,190 @@ +#include "./setupGroupList.h" +#include "../api__ml_online.h" +#include <strsafe.h> + +SetupGroupList::SetupGroupList() + : ref(1) +{ +} + +SetupGroupList::~SetupGroupList() +{ + size_t index = list.size(); + while(index--) + { + list[index]->Release(); + } +} + +SetupGroupList *SetupGroupList::CreateInstance() +{ + return new SetupGroupList(); +} + +ULONG SetupGroupList::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupGroupList::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +BOOL SetupGroupList::AddGroup(SetupGroup *group) +{ + if (NULL == group) return FALSE; + list.push_back(group); + group->AddRef(); + return TRUE; +} +size_t SetupGroupList::GetGroupCount() +{ + return list.size(); +} + +BOOL SetupGroupList::IsModified() +{ + size_t index = list.size(); + while(index--) + { + if (list[index]->IsModified()) + return TRUE; + } + + return FALSE; +} + +BOOL SetupGroupList::FindGroupIndex(SetupGroup *group, size_t *groupIndex) +{ + if (NULL == group) return FALSE; + + size_t index = list.size(); + while(index--) + { + if (list[index] == group) + { + if (NULL != groupIndex) + *groupIndex = index; + return TRUE; + } + } + + return FALSE; + +} + +HRESULT SetupGroupList::FindGroupById(UINT groupId, SetupGroup **group) +{ + if (NULL == group) return E_POINTER; + + size_t index = list.size(); + while(index--) + { + if (list[index]->GetId() == groupId) + { + *group = list[index]; + (*group)->AddRef(); + return S_OK; + } + } + return S_FALSE; +} + +size_t SetupGroupList::GetListboxCount() +{ + size_t recordCount = list.size(); + size_t index = recordCount; + while(index--) + { + recordCount += list[index]->GetListboxCount(); + } + return recordCount; +} + +HRESULT SetupGroupList::Save(SetupLog *log) +{ + HRESULT hr(S_OK); + size_t index = list.size(); + while(index--) + { + if (FAILED(list[index]->Save(log))) + hr = E_FAIL; + } + return hr; +} + +HRESULT SetupGroupList::FindListboxItem(size_t listboxId, SetupListboxItem **listboxItem) +{ + if (NULL == listboxItem) return E_POINTER; + + size_t index = 0; + size_t groupCount = list.size(); + + SetupGroup *group; + for (size_t i = 0; i < groupCount; i++) + { + group = list[i]; + if (index == listboxId) + { + *listboxItem = (SetupListboxItem*)group; + return S_OK; + } + index++; + + size_t itemCount; + if (0 != (itemCount = group->GetListboxCount())) + { + if (listboxId < (index + itemCount)) + { + size_t itemIndex = (listboxId - index); + *listboxItem = group->GetListboxItem(itemIndex); + return S_OK; + } + index += itemCount; + } + } + return E_NOTIMPL; +} + +INT SetupGroupList::GetListboxItem(SetupListboxItem *item) +{ + if (NULL == item) return LB_ERR; + size_t index = 0; + size_t groupCount = list.size(); + SetupGroup *group; + SetupListboxItem *groupItem; + + for (size_t i = 0; i < groupCount; i++) + { + group = list[i]; + if (item == group) + return (INT)index; + + index++; + size_t itemCount = group->GetListboxCount(); + for (size_t j = 0; j < itemCount; j++) + { + groupItem = group->GetListboxItem(j); + if (groupItem == item) + return (INT)index; + index++; + } + } + return LB_ERR; +} + +void SetupGroupList::SetPageWnd(HWND hPage) +{ + size_t index = list.size(); + while(index--) + { + list[index]->SetPageWnd(hPage); + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupGroupList.h b/Src/Plugins/Library/ml_online/Setup/setupGroupList.h new file mode 100644 index 00000000..0b4445cb --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupGroupList.h @@ -0,0 +1,52 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPLIST_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPLIST_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupGroup.h" +#include <vector> + +class SetupListboxItem; +class SetupLog; + +class SetupGroupList +{ + +protected: + SetupGroupList(); + ~SetupGroupList(); + +public: + static SetupGroupList *CreateInstance(); + +public: + ULONG AddRef(); + ULONG Release(); + + BOOL AddGroup(SetupGroup *group); + SetupGroup *GetGroup(size_t index) { return list[index]; } + size_t GetGroupCount(); + BOOL FindGroupIndex(SetupGroup *group, size_t *groupIndex); + HRESULT FindGroupById(UINT groupId, SetupGroup **group); + + + BOOL IsModified(); + + HRESULT Save(SetupLog *log); + + size_t GetListboxCount(); + INT GetListboxItem(SetupListboxItem *item); + HRESULT FindListboxItem(size_t listboxId, SetupListboxItem **listboxItem); + + void SetPageWnd(HWND hPage); + + +protected: + ULONG ref; + std::vector<SetupGroup*> list; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPGROUPLIST_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupImage.cpp b/Src/Plugins/Library/ml_online/Setup/setupImage.cpp new file mode 100644 index 00000000..46979043 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupImage.cpp @@ -0,0 +1,282 @@ +#include "./setupImage.h" +#include "../api__ml_online.h" + +#include <shlwapi.h> + +static BOOL SetupImage_CopyImage(HDC hdc, HBITMAP bitmapDst, INT x, INT y, INT cx, INT cy, HBITMAP bitmapSrc, INT srcX, INT srcY) +{ + BOOL resultOk = FALSE; + HDC hdcDst = CreateCompatibleDC(hdc); + HDC hdcSrc = CreateCompatibleDC(hdc); + + if (NULL != hdcDst && NULL != hdcSrc) + { + HBITMAP bitmapDstOrig = (HBITMAP)SelectObject(hdcDst, bitmapDst); + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(hdcSrc, bitmapSrc); + + resultOk = BitBlt(hdcDst, x, y, cx, cy, hdcSrc, srcX, srcY, SRCCOPY); + + SelectObject(hdcDst, bitmapDstOrig); + SelectObject(hdcSrc, bitmapSrcOrig); + } + + if (NULL != hdcDst) DeleteDC(hdcDst); + if (NULL != hdcSrc) DeleteDC(hdcSrc); + + return resultOk; +} + +static BOOL SetupImage_ColorizeImage(BYTE *pPixels, LONG x, LONG y, LONG cx, LONG cy, WORD bpp, LONG dstX, LONG dstY, COLORREF rgbBk, COLORREF rgbFg, BOOL removeAlpha) +{ + LONG pitch; + INT step; + BYTE rFg, gFg, bFg; + LPBYTE srcCursor, srcLine; + LPBYTE dstLine; + + if (bpp < 24) return FALSE; + + step = (bpp>>3); + pitch = cx*step; + while (pitch%4) pitch++; + + rFg = GetRValue(rgbFg); gFg = GetGValue(rgbFg); bFg = GetBValue(rgbFg); + + INT bK = (bFg - GetBValue(rgbBk)); + INT gK = (gFg - GetGValue(rgbBk)); + INT rK = (rFg - GetRValue(rgbBk)); + + srcLine = pPixels + pitch * y + x*step; + dstLine = pPixels + pitch * dstY + dstX*step; + + if (24 == bpp) + { + for (; cy-- != 0; srcLine += pitch, dstLine += pitch ) + { + LONG i; + LPBYTE dstCursor; + for (i = cx, srcCursor = srcLine, dstCursor = dstLine ; i-- != 0; srcCursor += 3, dstCursor +=3) + { + dstCursor[0] = bFg - (bK*(255 - srcCursor[0])>>8); + dstCursor[1] = gFg - (gK*(255 - srcCursor[1])>>8); + dstCursor[2] = rFg - (rK*(255 - srcCursor[2])>>8); + } + } + } + else + { + // nothing for now + return FALSE; + } + + return TRUE; +} + + +SetupImage::SetupImage(HDC hdc, HBITMAP bitmapSource, INT maxColors) + : ref(1), bitmap(NULL), pixels(NULL), + table(NULL), tableSize(0), tableCount(0), insertCursor(0), readCursor(0) +{ + ZeroMemory(&header, sizeof(BITMAPINFOHEADER)); + + BITMAP bm; + if (sizeof(BITMAP) != GetObject(bitmapSource, sizeof(BITMAP), &bm)) + return; + + if (bm.bmHeight < 0) + bm.bmHeight = -bm.bmHeight; + + header.biSize = sizeof(BITMAPINFOHEADER); + header.biCompression = BI_RGB; + header.biBitCount = 24; + header.biPlanes = 1; + header.biWidth = bm.bmWidth; + header.biHeight = -(bm.bmHeight * (maxColors + 1)); + + bitmap = CreateDIBSection(hdc, (LPBITMAPINFO)&header, DIB_RGB_COLORS, (void**)&pixels, NULL, 0); + if (NULL == bitmap) + return; + + if (FALSE == SetupImage_CopyImage(hdc, bitmap, 0, 0, bm.bmWidth, bm.bmHeight, bitmapSource, 0, 0)) + { + DeleteObject(bitmap); + bitmap = NULL; + return; + } + + tableSize = maxColors; + table = (IMAGEINDEX*)calloc(tableSize, sizeof(IMAGEINDEX)); + if (NULL == table) + { + DeleteObject(bitmap); + bitmap = NULL; + return; + } +} + +SetupImage::~SetupImage() +{ + if (NULL != bitmap) + { + DeleteObject(bitmap); + bitmap = NULL; + } + + if (NULL != table) + { + free(table); + table = NULL; + } +} + +SetupImage *SetupImage::CreateInstance(HDC hdc, HBITMAP bitmapSource, INT maxColors) +{ + if (NULL == bitmapSource || maxColors < 1 || maxColors > 120) + return NULL; + + SetupImage *instance = new SetupImage(hdc, bitmapSource, maxColors); + if (NULL == instance) return NULL; + if (NULL == instance->bitmap || NULL == instance->table) + { + instance->Release(); + instance = NULL; + } + return instance; +} + +SetupImage *SetupImage::CreateFromPluginBitmap(HDC hdc, LPCWSTR pszModuleName, LPCWSTR resourceName, INT maxColors) +{ + SetupImage *instance = NULL; + WCHAR szPath[MAX_PATH] = {0}; + + if (0 != GetModuleFileName(WASABI_API_ORIG_HINST, szPath, ARRAYSIZE(szPath))) + { + PathRemoveFileSpec(szPath); + PathAppend(szPath, pszModuleName); + HMODULE hModule = LoadLibraryEx(szPath, NULL, LOAD_LIBRARY_AS_DATAFILE | 0x00000020/*LOAD_LIBRARY_AS_IMAGE_RESOURCE*/); + if (NULL != hModule) + { + HBITMAP bitmapSource = (HBITMAP)LoadImage(hModule, resourceName, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + if (NULL != bitmapSource) + instance = CreateInstance(hdc, bitmapSource, maxColors); + FreeLibrary(hModule); + } + } + return instance; +} + +ULONG SetupImage::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupImage::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +BOOL SetupImage::GetSize(SIZE *pSize) +{ + if (NULL == pSize) return FALSE; + + INT cy = header.biHeight; + if (cy < 0) cy = -cy; + + pSize->cx = header.biWidth; + pSize->cy = cy / (tableSize + 1); + return TRUE; +} + +BOOL SetupImage::DrawImage(HDC hdc, INT x, INT y, INT cx, INT cy, INT srcX, INT srcY, COLORREF rgbBk, COLORREF rgbFg) +{ + BYTE bitmapIndex = 0xFF; + + SIZE imageSize; + if (!GetSize(&imageSize)) + return FALSE; + + for(BYTE i = readCursor; i < tableCount; i++) + { + if (table[i].rgbBk == rgbBk && table[i].rgbFg == rgbFg) + { + bitmapIndex = i; + break; + } + } + + if (0xFF == bitmapIndex) + { + if (readCursor > tableCount) + readCursor = tableCount; + for(BYTE i = 0; i < readCursor; i++) + { + if (table[i].rgbBk == rgbBk && table[i].rgbFg == rgbFg) + { + bitmapIndex = i; + break; + } + } + + if (0xFF == bitmapIndex) + { + if (tableCount < tableSize) + { + insertCursor = tableCount; + tableCount++; + } + else if (++insertCursor == tableCount) + insertCursor = 0; + + INT targetY = (insertCursor + 1) * imageSize.cy; + + if (!SetupImage_ColorizeImage(pixels, 0, 0, imageSize.cx, imageSize.cy, + header.biBitCount, 0, targetY, rgbBk, rgbFg, TRUE)) + { + return FALSE; + } + table[insertCursor].rgbBk = rgbBk; + table[insertCursor].rgbFg = rgbFg; + bitmapIndex = insertCursor; + + } + } + + readCursor = bitmapIndex; + srcY += ((bitmapIndex + 1) * imageSize.cy); + + INT dstY = y; + INT dstCY = cy; + + INT imageHeight = header.biHeight; + if (imageHeight < 0) + { + header.biHeight = -imageHeight; + dstY += (cy - 1); + dstCY = -cy; + } + + BOOL resultOk = StretchDIBits(hdc, x, dstY, cx, dstCY, srcX, srcY, cx, cy, + pixels, (BITMAPINFO*)&header, DIB_RGB_COLORS, SRCCOPY); + + if (imageHeight < 0) + header.biHeight = imageHeight; + + return resultOk; +} + +BOOL SetupImage::ResetCache() +{ + if (NULL != table) + ZeroMemory(&table, sizeof(IMAGEINDEX) * tableSize); + tableCount = 0; + insertCursor = 0; + readCursor = 0; + return TRUE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupImage.h b/Src/Plugins/Library/ml_online/Setup/setupImage.h new file mode 100644 index 00000000..893e2c93 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupImage.h @@ -0,0 +1,50 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPIMAGE_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPIMAGE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +class SetupImage +{ +private: + typedef struct __IMAGEINDEX + { + COLORREF rgbBk; + COLORREF rgbFg; + } IMAGEINDEX; + +protected: + SetupImage(HDC hdc, HBITMAP bitmapSource, INT maxColors); + ~SetupImage(); + +public: + static SetupImage *CreateInstance(HDC hdc, HBITMAP bitmapSource, INT maxColors); + static SetupImage *CreateFromPluginBitmap(HDC hdc, LPCWSTR pszModuleName, LPCWSTR resourceName, INT maxColors); + +public: + ULONG AddRef(); + ULONG Release(); + + BOOL GetSize(SIZE *pSize); + BOOL DrawImage(HDC hdc, INT x, INT y, INT cx, INT cy, INT srcX, INT srcY, COLORREF rgbBk, COLORREF rgbFg); + + BOOL ResetCache(); + +private: + ULONG ref; + HBITMAP bitmap; + BYTE *pixels; + BITMAPINFOHEADER header; + + + IMAGEINDEX *table; + BYTE tableSize; + BYTE tableCount; + BYTE insertCursor; + BYTE readCursor; +}; + +#endif // NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPIMAGE_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupListbox.cpp b/Src/Plugins/Library/ml_online/Setup/setupListbox.cpp new file mode 100644 index 00000000..1035c699 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListbox.cpp @@ -0,0 +1,878 @@ +#include "./setupPage.h" +#include "./setupListbox.h" +#include "./setupGroupList.h" +#include "./setupImage.h" +#include "../common.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include "../../nu/windowsTheme.h" + +#include <vssym32.h> + +//#include <tmschema.h> + +static ATOM SERVICELIST_PROP = 0; + +#define SLF_UNICODE 0x0001 +#define SLF_DRAGMOVE 0x0002 + +typedef BOOL (SetupListboxItem::*ITEMMOUSEPROC)(SetupListbox*, const RECT*, UINT, POINT); + +class Listbox : public SetupListbox +{ + +protected: + Listbox(HWND hListbox, SetupGroupList *groupList); + ~Listbox(); + +public: + static HRESULT AttachToWindow(HWND hwndListbox, SetupGroupList *groupList, SetupListbox **pInstance); + +public: + HWND GetHwnd() { return hwnd; } + HFONT GetFont() { return (HFONT)::SendMessage(hwnd, WM_GETFONT, 0, 0L); } + LRESULT CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + LRESULT CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + + BOOL MeasureItem(INT itemId, UINT *cx, UINT *cy); + BOOL DrawItem(HDC hdc, const RECT *itemRect, INT itemId, UINT itemState, UINT itemAction); + INT_PTR KeyToItem(INT vKey, INT caretPos); + INT_PTR CharToItem(INT vKey, INT caretPos); + + BOOL DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect); + BOOL GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize); + + INT GetCheckboxThemeState(BOOL checked, UINT state); + INT HitTest(POINT pt, RECT *prcItem); + + void SetCapture(SetupListboxItem *item); + SetupListboxItem *GetCapture(); + void ReleaseCapture(); + BOOL InvalidateRect(const RECT *prcInvalidate, BOOL fErase); + BOOL InvalidateItem(INT itemId, BOOL fErase); + void UpdateCount(); + + BOOL DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg); + BOOL GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize); + + INT GetPageCount(); + INT GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut); + INT GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut); + + SetupListboxItem *GetSelection(); + BOOL SetSelection(SetupListboxItem *item); + BOOL GetIndex(SetupListboxItem *item, INT *iItem); + + BOOL DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt); + HMENU GetContextMenu(UINT menuId); + +protected: + friend static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + + void OnDestroy(); + void GetItemRect(INT itemId, RECT *prcItem); + + SetupImage *GetExpandboxImage(HDC hdc, BOOL fExpanded); + + void OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc); + void OnMouseLeave(); + void OnEraseBkGround(HDC hdc); + void OnCaptureChanged(HWND hwndGained); + void NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain); + void OnCommand(INT commandId, INT eventId, HWND hControl); + +protected: + HWND hwnd; + UINT flags; + WNDPROC originalProc; + UXTHEME buttonTheme; + SetupGroupList *groups; + INT mouseoverId; + INT capturedId; + SetupImage *expandedImage; + SetupImage *collapsedImage; +}; + +#define GetList(__hwnd) ((Listbox*)GetPropW((__hwnd), MAKEINTATOM(SERVICELIST_PROP))) + + + + +HRESULT SetupListbox::CreateInstance(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance) +{ + return Listbox::AttachToWindow(hListbox, groupList, pInstance); +} + +SetupListbox *SetupListbox::GetInstance(HWND hListbox) +{ + return GetList(hListbox); +} + +Listbox::Listbox(HWND hListbox, SetupGroupList *groupList) + : hwnd(hListbox), flags(0), originalProc(NULL), buttonTheme(NULL), groups(groupList), + mouseoverId(LB_ERR), capturedId(LB_ERR), expandedImage(NULL), collapsedImage(NULL) +{ + if (IsWindowUnicode(hwnd)) + flags |= SLF_UNICODE; + + buttonTheme = (UxIsAppThemed()) ? UxOpenThemeData(hwnd, L"Button") : NULL; + + groups->AddRef(); + UpdateCount(); + +} + +Listbox::~Listbox() +{ + if (NULL != hwnd) + { + RemoveProp(hwnd, MAKEINTATOM(SERVICELIST_PROP)); + if (NULL != originalProc) + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONGX86)(LONG_PTR)originalProc); + CallPrevProc(WM_DESTROY, 0, 0L); + } + } + + if (NULL != groups) + groups->Release(); + + if (NULL != buttonTheme) + UxCloseThemeData(buttonTheme); + + if (NULL != expandedImage) + expandedImage->Release(); + + if (NULL != collapsedImage) + collapsedImage->Release(); +} + +HRESULT Listbox::AttachToWindow(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance) +{ + if (0 == SERVICELIST_PROP) + { + SERVICELIST_PROP = GlobalAddAtom(TEXT("omSetupListbox")); + if (0 == SERVICELIST_PROP) return E_UNEXPECTED; + } + + + if(NULL == hListbox || !IsWindow(hListbox) || NULL == groupList) + return E_INVALIDARG; + + Listbox *list = new Listbox(hListbox, groupList); + if (NULL == list) + return E_OUTOFMEMORY; + + list->originalProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hListbox, GWLP_WNDPROC, + (LONGX86)(LONG_PTR)Listbox_WindowProc); + + if (NULL == list->originalProc || !SetProp(hListbox, MAKEINTATOM(SERVICELIST_PROP), list)) + { + if (NULL != list->originalProc) + SetWindowLongPtr(hListbox, GWLP_WNDPROC, (LONGX86)(LONG_PTR)list->originalProc); + delete(list); + return E_FAIL; + } + + + if (NULL != pInstance) + *pInstance = list; + + return S_OK; +} + +LRESULT Listbox::CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return (0 != (SLF_UNICODE & flags)) ? + DefWindowProcW(hwnd, uMsg, wParam, lParam) : + DefWindowProcA(hwnd, uMsg, wParam, lParam); +} + +LRESULT Listbox::CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return (0 != (SLF_UNICODE & flags)) ? + CallWindowProcW(originalProc, hwnd, uMsg, wParam, lParam) : + CallWindowProcA(originalProc, hwnd, uMsg, wParam, lParam); +} + + +void Listbox::UpdateCount() +{ + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0L); + + INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L); + + size_t recordCount = (NULL != groups) ? groups->GetListboxCount() : 0; + SendMessage(hwnd, LB_SETCOUNT, (WPARAM)recordCount, 0L); + + SetupListboxItem *item; + UINT cy, maxCY = 0; + for (size_t i = 0; i < recordCount; i++) + { + if (SUCCEEDED(groups->FindListboxItem(i, &item)) && + item->MeasureItem(this, NULL, &cy) && cy > maxCY) + { + maxCY = cy; + } + } + + SendMessage(hwnd, LB_SETITEMHEIGHT, (WPARAM)0, (LPARAM)maxCY); + + if (recordCount > 0) + { + if (iSelected < 0) + iSelected = 0; + + if ((size_t)iSelected >= recordCount) + iSelected = (INT)(recordCount - 1); + + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iSelected, TRUE); + SendMessage(hwnd, LB_SETANCHORINDEX, (WPARAM)iSelected, 0L); + SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iSelected, 0L); + } + + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0L); +} + +BOOL Listbox::MeasureItem(INT itemId, UINT *cx, UINT *cy) +{ + SetupListboxItem *item; + HRESULT hr = groups->FindListboxItem(itemId, &item); + return (SUCCEEDED(hr)) ? item->MeasureItem(this, cx, cy) : FALSE; +} + +BOOL Listbox::DrawItem(HDC hdc, const RECT *prcItem, INT itemId, UINT itemState, UINT itemAction) +{ + SetupListboxItem *item; + HRESULT hr = groups->FindListboxItem(itemId, &item); + if (FAILED(hr)) return FALSE; + + if (0 != (ODS_SELECTED & itemState) && GetFocus() != hwnd) + itemState |= ODS_INACTIVE; + + if (item->IsDisabled()) + itemState |= ODS_DISABLED; + + return item->DrawItem(this, hdc, prcItem, itemState); +} + +INT Listbox::GetPageCount() +{ + RECT clientRect; + if (NULL == hwnd || !GetClientRect(hwnd, &clientRect)) + return 0; + + INT itemHeight = (INT)SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0L); + return (clientRect.bottom - clientRect.top) / itemHeight; +} + +INT Listbox::GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut) +{ + INT iLast = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + if (iLast >= 0) iLast--; + + SetupListboxItem *testItem; + while(iItem++ < iLast) + { + if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem))) + { + if (FALSE == testItem->IsDisabled()) break; + } + } + if (NULL != itemOut) + { + *itemOut = (iItem <= iLast) ? testItem : NULL; + } + return (iItem <= iLast) ? iItem : LB_ERR; +} + +INT Listbox::GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut) +{ + SetupListboxItem *testItem; + while(iItem-- > 0) + { + if (SUCCEEDED(groups->FindListboxItem(iItem, &testItem))) + { + if (FALSE == testItem->IsDisabled()) break; + } + } + + if (NULL != itemOut) + { + *itemOut = (iItem >= 0) ? testItem : NULL; + } + return (iItem >= 0) ? iItem : LB_ERR; +} + +SetupListboxItem *Listbox::GetSelection() +{ + INT iSelected = (INT)SendMessage(hwnd, LB_GETCURSEL, 0, 0L); + if (LB_ERR == iSelected) + return NULL; + + SetupListboxItem *item; + return (SUCCEEDED(groups->FindListboxItem(iSelected, &item))) ? item : NULL; +} + +BOOL Listbox::SetSelection(SetupListboxItem *item) +{ + INT iItem = LB_ERR; + if (NULL != item) + { + iItem = groups->GetListboxItem(item); + if (LB_ERR == iItem) + return FALSE; + } + + BOOL resultOk = (LB_ERR != SendMessage(hwnd, LB_SETCURSEL, (WPARAM)iItem, 0L)); + if (LB_ERR == iItem) resultOk = TRUE; + + if (LB_ERR != iItem) + { + HWND hParent = GetParent(hwnd); + if (NULL != hParent) + SendMessage(hParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), LBN_SELCHANGE), (LPARAM)hwnd); + } + return resultOk; +} + +BOOL Listbox::GetIndex(SetupListboxItem *item, INT *iItem) +{ + if (NULL == iItem) + return FALSE; + + *iItem = (NULL != item && NULL != groups) ? groups->GetListboxItem(item) : LB_ERR; + return (LB_ERR != *iItem); +} + +INT_PTR Listbox::KeyToItem(INT vKey, INT iCaret) +{ + SetupListboxItem *item; + HRESULT hr = groups->FindListboxItem(iCaret, &item); + if (FAILED(hr)) return -1; + + RECT itemRect; + GetItemRect(iCaret, &itemRect); + INT_PTR result = item->KeyToItem(this, &itemRect, vKey); + if (-1 != result) return result; + + INT iTarget, iCount; + + switch(vKey) + { + case VK_UP: + case VK_LEFT: + iTarget = GetPrevEnabledItem(iCaret, NULL); + if (LB_ERR != iTarget) return iTarget; + + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L); + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + return -2; + + case VK_DOWN: + case VK_RIGHT: + iTarget = GetNextEnabledItem(iCaret, NULL); + if (LB_ERR != iTarget) return iTarget; + + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)iCaret, 0L); + return -2; + + case VK_HOME: + if (iCaret > 0) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L); + iTarget = GetNextEnabledItem(-1, NULL); + if (iTarget >= iCaret) iTarget = LB_ERR; + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + + case VK_PRIOR: + if (iCaret > 0) + { + INT iTop = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L); + if (iTop == iCaret) + { + INT iPage = iCaret - GetPageCount() + 1; + iTop = (iPage <= 0) ? 0 : (iPage - 1); + } + + iTarget = GetPrevEnabledItem(iTop + 1, NULL); + + if (LB_ERR == iTarget) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)0, 0L); + iTarget = GetNextEnabledItem(iTop, NULL); + if (iTarget > iCaret) iTarget = LB_ERR; + } + + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + + case VK_END: + iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + if (iCount > 0 && iCaret != (iCount - 1)) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L); + iTarget = GetPrevEnabledItem(iCount, NULL); + if (iTarget <= iCaret) iTarget = LB_ERR; + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + + case VK_NEXT: + iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + if (iCount > 0 && iCaret != (iCount - 1)) + { + INT iPage = GetPageCount(); + INT iBottom = (INT)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0L) + iPage - 1; + if (iBottom == iCaret) + { + iBottom += iPage; + if (iBottom >= iCount) iBottom = iCount -1; + } + iTarget = GetNextEnabledItem(iBottom - 1, NULL); + if (LB_ERR == iTarget) + { + SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)(iCount - 1), 0L); + iTarget = GetPrevEnabledItem(iBottom, NULL); + if (iTarget < iCaret) iTarget = LB_ERR; + } + + if (LB_ERR != iTarget) return iTarget; + SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM)iCaret, FALSE); + } + return -2; + } + + return result; +} + +INT_PTR Listbox::CharToItem(INT vKey, INT caretPos) +{ + return -2; + //SetupListboxItem *item; + //HRESULT hr = groups->FindListboxItem(caretPos, &item); + //return (SUCCEEDED(hr)) ? item->CharToItem(this, vKey) : -1; +} + +INT Listbox::GetCheckboxThemeState(BOOL checked, UINT state) +{ + if (FALSE != checked) + { + if (0 != (ODS_DISABLED & state)) return CBS_CHECKEDDISABLED; + if (0 != (ODS_HOTLIGHT & state)) return CBS_CHECKEDHOT; + if (0 != (ODS_SELECTED & state)) return CBS_CHECKEDPRESSED; + return CBS_CHECKEDNORMAL; + } + + if (0 != (ODS_DISABLED & state)) return CBS_UNCHECKEDDISABLED; + if (0 != (ODS_HOTLIGHT & state)) return CBS_UNCHECKEDHOT; + if (0 != (ODS_SELECTED & state)) return CBS_UNCHECKEDPRESSED; + return CBS_UNCHECKEDNORMAL; +} + +BOOL Listbox::DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect) +{ + if (NULL != buttonTheme) + { + INT stateId = GetCheckboxThemeState(checked, state); + if (SUCCEEDED(UxDrawThemeBackground(buttonTheme, hdc, BP_CHECKBOX, stateId, pRect, pClipRect))) + return TRUE; + } + + UINT stateId = DFCS_BUTTONCHECK; + if (FALSE != checked) stateId |= DFCS_CHECKED; + if (0 != (ODS_DISABLED & state)) stateId |= DFCS_INACTIVE; + if (0 != (ODS_HOTLIGHT & state)) stateId |= DFCS_HOT; + if (0 != (ODS_SELECTED & state)) stateId |= DFCS_PUSHED; + + return DrawFrameControl(hdc, (LPRECT)pRect,DFC_BUTTON, stateId); +} + +BOOL Listbox::GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize) +{ + if (NULL != buttonTheme) + { + HDC hdcMine = NULL; + + if (NULL == hdc) + { + hdcMine = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + hdc = hdcMine; + } + + INT stateId = GetCheckboxThemeState(checked, state); + HRESULT hr = UxGetThemePartSize(buttonTheme, hdc, BP_CHECKBOX, + stateId, NULL, TS_DRAW, pSize); + + if (NULL != hdcMine) + ReleaseDC(hwnd, hdcMine); + if (SUCCEEDED(hr)) return TRUE; + } + pSize->cx = 13; + pSize->cy = 13; + return TRUE; +} + +void Listbox::OnDestroy() +{ + delete(this); +} + + +INT Listbox::HitTest(POINT pt, RECT *prcItem) +{ + RECT itemRect; + INT itemId = (INT)SendMessage(hwnd, LB_ITEMFROMPOINT, 0, MAKELONG(pt.x, pt.y)); + + if (LB_ERR == itemId || + LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect) || + FALSE == PtInRect(&itemRect, pt)) + { + return LB_ERR; + } + + if (NULL != prcItem) + CopyRect(prcItem, &itemRect); + + return itemId; +} + +void Listbox::GetItemRect(INT itemId, RECT *prcItem) +{ + if (LB_ERR == ::SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)prcItem)) + SetRectEmpty(prcItem); +} + +BOOL Listbox::DoDragAndDrop(UINT mouseEvent, UINT mouseFlags, POINT pt) +{ + if (WM_MOUSEMOVE == mouseEvent && + 0 != ((MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) & mouseFlags)) + { + flags |= SLF_DRAGMOVE; + } + else + { + flags &= ~SLF_DRAGMOVE; + } + return (0 != (SLF_DRAGMOVE & flags)); +} + +void Listbox::OnMouseEvent(UINT mouseEvent, UINT mouseFlags, POINTS pts, BOOL fDefaultHandler, ITEMMOUSEPROC proc) +{ + POINT pt; + POINTSTOPOINT(pt, pts); + SetupListboxItem *item; + RECT itemRect; + + if (LB_ERR != capturedId) + { + if (SUCCEEDED(groups->FindListboxItem(capturedId, &item))) + { + GetItemRect(capturedId, &itemRect); + if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt))) + { + CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts)); + } + return; + } + capturedId = LB_ERR; + } + + if (DoDragAndDrop(mouseEvent, mouseFlags, pt)) + return; + + INT itemId = HitTest(pt, &itemRect); + if (mouseoverId != itemId) + { + if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item))) + { + RECT leaveRect; + GetItemRect(mouseoverId, &leaveRect); + item->MouseLeave(this, &leaveRect); + } + mouseoverId = itemId; + + TRACKMOUSEEVENT tm; + tm.cbSize = sizeof(TRACKMOUSEEVENT); + tm.hwndTrack = hwnd; + tm.dwFlags = TME_LEAVE; + if (LB_ERR == mouseoverId) + tm.dwFlags |= TME_CANCEL; + TrackMouseEvent(&tm); + } + + if (LB_ERR != mouseoverId) + { + if (SUCCEEDED(groups->FindListboxItem(mouseoverId, &item))) + { + BOOL callListbox = FALSE; + if (FALSE != item->IsDisabled()) + { + switch(mouseEvent) + { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case 0x020C /*WM_XBUTTONUP*/: + callListbox = TRUE; + break; + } + } + else + { + if (FALSE == ((item->*proc)(this, &itemRect, mouseFlags, pt))) + { + callListbox = TRUE; + } + } + + if (FALSE != callListbox) + { + CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts)); + } + return; + } + } + + if (FALSE != fDefaultHandler) + { + CallPrevProc(mouseEvent, (WPARAM)mouseFlags, *((LPARAM*)&pts)); + } +} + +void Listbox::OnMouseLeave() +{ + if (LB_ERR != mouseoverId) + { + SetupListboxItem *item; + INT itemId = mouseoverId; + mouseoverId = LB_ERR; + if (SUCCEEDED(groups->FindListboxItem(itemId, &item))) + { + RECT itemRect; + GetItemRect(itemId, &itemRect); + if (item->MouseLeave(this, &itemRect)) + return; + } + } + CallPrevProc(WM_MOUSELEAVE, 0, 0L); +} + +void Listbox::SetCapture(SetupListboxItem *item) +{ + INT prevCapturedId = capturedId; + capturedId = (NULL != item) ? groups->GetListboxItem(item) : LB_ERR; + + NotifyReleaseCapture(prevCapturedId, item); + + if (LB_ERR != capturedId && ::GetCapture() != hwnd) + ::SetCapture(hwnd); +} + +SetupListboxItem *Listbox::GetCapture() +{ + SetupListboxItem *capturedItem; + if (LB_ERR == capturedId || FAILED(groups->FindListboxItem(capturedId, &capturedItem))) + capturedItem = NULL; + + return capturedItem; +} + +void Listbox::ReleaseCapture() +{ + if (LB_ERR != capturedId) + { + INT prevCapturedId = capturedId; + capturedId = LB_ERR; + + NotifyReleaseCapture(prevCapturedId, NULL); + if (::GetCapture() == hwnd) + ::ReleaseCapture(); + } +} + +void Listbox::NotifyReleaseCapture(INT itemId, SetupListboxItem *itemGain) +{ + if (LB_ERR == itemId) + return; + + SetupListboxItem *item; + if (SUCCEEDED(groups->FindListboxItem(itemId, &item))) + { + RECT itemRect; + GetItemRect(itemId, &itemRect); + item->CaptureChanged(this, &itemRect, itemGain); + } +} + +void Listbox::OnCaptureChanged(HWND hwndGained) +{ + if (hwnd != hwndGained && LB_ERR != capturedId) + { + INT prevCapturedId = capturedId; + capturedId = LB_ERR; + NotifyReleaseCapture(prevCapturedId, NULL); + } +} + +BOOL Listbox::InvalidateRect(const RECT *prcInvalidate, BOOL fErase) +{ + return ::InvalidateRect(hwnd, prcInvalidate, fErase); +} + +BOOL Listbox::InvalidateItem(INT itemId, BOOL fErase) +{ + if (itemId < 0) return FALSE; + + RECT itemRect; + if (LB_ERR == SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)itemId, (LPARAM)&itemRect)) + return FALSE; + + return ::InvalidateRect(hwnd, &itemRect, fErase); +} + +void Listbox::OnEraseBkGround(HDC hdc) +{ + INT iCount = (INT)SendMessage(hwnd, LB_GETCOUNT, 0, 0L); + RECT clientRect, itemRect; + + GetClientRect(hwnd, &clientRect); + if (iCount > 0 && + LB_ERR != SendMessage(hwnd, LB_GETITEMRECT, (WPARAM)(iCount - 1), (LPARAM)&itemRect)) + { + clientRect.top = itemRect.top; + } + + if (clientRect.top < clientRect.bottom) + { + HBRUSH hb = NULL; + HWND hParent = GetParent(hwnd); + if (NULL != hParent) + { + hb = (HBRUSH)SendMessage(hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc, (LPARAM)hwnd); + } + if (NULL == hb) + { + hb = GetSysColorBrush(COLOR_WINDOW); + } + FillRect(hdc, &clientRect, hb); + } +} + +void Listbox::OnCommand(INT commandId, INT eventId, HWND hControl) +{ + if (NULL == hControl) + { + SetupListboxItem *item = GetSelection(); + if (NULL != item) + { + item->Command(this, commandId, eventId); + } + + } +} +SetupImage *Listbox::GetExpandboxImage(HDC hdc, BOOL fExpanded) +{ + if (fExpanded) + { + if (NULL == expandedImage) + expandedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(137), 3); + return expandedImage; + } + + if (NULL == collapsedImage) + collapsedImage = SetupImage::CreateFromPluginBitmap(hdc, L"gen_ml.dll", MAKEINTRESOURCE(135), 3); + return collapsedImage; +} + +BOOL Listbox::DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg) +{ + SetupImage *image = GetExpandboxImage(hdc, fExpanded); + return (NULL != image) ? + image->DrawImage(hdc, pRect->left, pRect->top, + pRect->right - pRect->left, pRect->bottom- pRect->top, + 0, 0, rgbBk, rgbFg) + : FALSE; +} + +BOOL Listbox::GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize) +{ + SetupImage *image = GetExpandboxImage(hdc, fExpanded); + return (NULL != image) ? image->GetSize(pSize) : FALSE; +} + +HMENU Listbox::GetContextMenu(UINT menuId) +{ + HMENU baseMenu = WASABI_API_LOADMENUW(IDR_SETUPMENU); + if (NULL == baseMenu) + return NULL; + + switch(menuId) + { + case menuGroupContext: + return GetSubMenu(baseMenu, 0); + } + return NULL; +} + +LRESULT Listbox::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_DESTROY: + OnDestroy(); + return 0; + case WM_MOUSEMOVE: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::MouseMove); + return 0; + case WM_LBUTTONDOWN: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDown); + return 0; + case WM_LBUTTONUP: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::LButtonUp); + return 0; + case WM_LBUTTONDBLCLK: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::LButtonDblClk); + return 0; + case WM_RBUTTONDOWN: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), FALSE, &SetupListboxItem::RButtonDown); + return 0; + case WM_RBUTTONUP: + OnMouseEvent(uMsg, (UINT)wParam, MAKEPOINTS(lParam), TRUE, &SetupListboxItem::RButtonUp); + return 0; + case WM_MOUSELEAVE: + OnMouseLeave(); + return 0; + case WM_CAPTURECHANGED: + OnCaptureChanged((HWND)lParam); + break; + case WM_ERASEBKGND: + OnEraseBkGround((HDC)wParam); + return TRUE; + case WM_COMMAND: + OnCommand(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); + return 0; + } + + return CallPrevProc(uMsg, wParam, lParam); +} + +static LRESULT WINAPI Listbox_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + Listbox *list = GetList(hwnd); + if (NULL != list) + return list->WindowProc(uMsg, wParam, lParam); + + return (IsWindowUnicode(hwnd)) ? + DefWindowProcW(hwnd, uMsg, wParam, lParam) : + DefWindowProcA(hwnd, uMsg, wParam, lParam); + +} diff --git a/Src/Plugins/Library/ml_online/Setup/setupListbox.h b/Src/Plugins/Library/ml_online/Setup/setupListbox.h new file mode 100644 index 00000000..0fceffc3 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListbox.h @@ -0,0 +1,84 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <windows.h> + +class SetupGroupList; +class SetupListboxItem; + +class __declspec(novtable) SetupListbox +{ +public: + typedef enum + { + menuGroupContext = 0, + } contextMenu; + +public: + static HRESULT CreateInstance(HWND hListbox, SetupGroupList *groupList, SetupListbox **pInstance); + static SetupListbox *GetInstance(HWND hListbox); + +public: + virtual HWND GetHwnd() = 0; + virtual HFONT GetFont() = 0; + virtual LRESULT CallDefaultProc(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0; + virtual LRESULT CallPrevProc(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0; + + virtual BOOL MeasureItem(INT itemId, UINT *cx, UINT *cy) = 0; + virtual BOOL DrawItem(HDC hdc, const RECT *prcItem, INT itemId, UINT itemState, UINT itemAction) = 0; + virtual INT_PTR KeyToItem(INT vKey, INT caretPos) = 0; + virtual INT_PTR CharToItem(INT vKey, INT caretPos) = 0; + + virtual BOOL DrawCheckbox(HDC hdc, BOOL checked, UINT state, const RECT *pRect, const RECT *pClipRect) = 0; + virtual BOOL GetCheckboxMetrics(HDC hdc, BOOL checked, UINT state, SIZE *pSize) = 0; + virtual void SetCapture(SetupListboxItem *item) = 0; + virtual SetupListboxItem *GetCapture() = 0; + virtual void ReleaseCapture() = 0; + + virtual BOOL InvalidateRect(const RECT *prcInvalidate, BOOL fErase) = 0; + virtual BOOL InvalidateItem(INT iItem, BOOL fErase) = 0; + virtual void UpdateCount() = 0; + + + virtual BOOL DrawExpandbox(HDC hdc, BOOL fExpanded, const RECT *pRect, COLORREF rgbBk, COLORREF rgbFg) = 0; + virtual BOOL GetExpandboxMetrics(HDC hdc, BOOL fExpanded, SIZE *pSize) = 0; + + virtual INT GetPageCount() = 0; + virtual INT GetNextEnabledItem(INT iItem, SetupListboxItem **itemOut) = 0; + virtual INT GetPrevEnabledItem(INT iItem, SetupListboxItem **itemOut) = 0; + virtual SetupListboxItem *GetSelection() = 0; + virtual BOOL SetSelection(SetupListboxItem *item) = 0; + virtual BOOL GetIndex(SetupListboxItem *item, INT *iItem) = 0; + + virtual HMENU GetContextMenu(UINT menuId) = 0; + + +}; + +class __declspec(novtable) SetupListboxItem +{ + +public: + virtual BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) = 0; + virtual BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) = 0; + virtual INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) = 0; + virtual BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem) = 0; + virtual BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) = 0; + virtual void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) = 0; + virtual BOOL IsDisabled() = 0; + virtual void Command(SetupListbox *instance, INT commandId, INT eventId) = 0; + + virtual HWND CreateDetailsView(HWND hParent) = 0; + virtual BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) = 0; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.cpp b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.cpp new file mode 100644 index 00000000..0a24b61e --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.cpp @@ -0,0 +1,228 @@ +#include "./setupListboxLabel.h" +#include "../api__ml_online.h" +#include "../common.h" + +#include <shlwapi.h> +#include <strsafe.h> + +#define LABEL_MARGINCX 0 +#define LABEL_MARGINCY 1 + +#define TEXT_OFFSET_LEFT 2 +#define TEXT_OFFSET_BOTTOM 2 +#define TEXT_ALIGN (TA_CENTER | TA_BOTTOM) + +SetupListboxLabel::SetupListboxLabel(LPCWSTR pszName) + : ref(1), name(NULL) +{ + SetName(pszName); +} + +SetupListboxLabel::~SetupListboxLabel() +{ + SetName(NULL); +} + +SetupListboxLabel *SetupListboxLabel::CreateInstance(LPCWSTR pszName) +{ + return new SetupListboxLabel(pszName); +} + +ULONG SetupListboxLabel::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupListboxLabel::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + return r; +} + +HRESULT SetupListboxLabel::GetName(LPWSTR pszBuffer, INT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + + if (NULL != name && IS_INTRESOURCE(name)) + { + WASABI_API_LNGSTRINGW_BUF((INT)(INT_PTR)name, pszBuffer, cchBufferMax); + return (L'\0' != *pszBuffer) ? S_OK : E_FAIL; + } + return StringCchCopyExW(pszBuffer, cchBufferMax, name, NULL, NULL, STRSAFE_IGNORE_NULLS); +} +HRESULT SetupListboxLabel::SetName(LPCWSTR pszName) +{ + if (NULL != name && !IS_INTRESOURCE(name)) + Plugin_FreeString(name); + + if (IS_INTRESOURCE(pszName)) + { + name = (LPWSTR)pszName; + } + else + { + name = Plugin_CopyString(pszName); + } + + return S_OK; +} + +BOOL SetupListboxLabel::IsNameNull() +{ + return (NULL == name); +} + +void SetupListboxLabel::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut) +{ + COLORREF rgbBk, rgbText; + + rgbBk = GetSysColor(COLOR_WINDOW); + rgbText = GetSysColor( (0 == (ODS_DISABLED & state)) ? COLOR_GRAYTEXT : COLOR_GRAYTEXT); + + if (NULL != rgbBkOut) *rgbBkOut = rgbBk; + if (NULL != rgbTextOut) *rgbTextOut = rgbText; +} + +HBRUSH SetupListboxLabel::GetBrush(HDC hdc, UINT state) +{ + return GetSysColorBrush(COLOR_WINDOW); +} + +BOOL SetupListboxLabel::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) +{ + HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return FALSE; + + HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont()); + + if (NULL != cy) + { + *cy = 0; + TEXTMETRIC tm; + if (GetTextMetrics(hdc, &tm)) + *cy = tm.tmHeight + tm.tmExternalLeading + LABEL_MARGINCY*2; + } + + if (NULL != cx) + { + *cx = 0; + WCHAR szBuffer[128] = {0}; + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + INT cchBuffer = lstrlenW(szBuffer); + SIZE textSize; + if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize)) + { + *cx = textSize.cx + LABEL_MARGINCX*2; + } + } + } + + SelectObject(hdc, originalFont); + ReleaseDC(instance->GetHwnd(), hdc); + return TRUE; +} + +BOOL SetupListboxLabel::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) +{ + LONG paintLeft = prc->left + LABEL_MARGINCX; + + COLORREF rgbBk, rgbText; + GetColors(hdc, state, &rgbBk, &rgbText); + + COLORREF origBk = SetBkColor(hdc, rgbBk); + COLORREF origText = SetTextColor(hdc, rgbText); + UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN); + + HRGN backRgn, rgn; + backRgn = CreateRectRgnIndirect(prc); + rgn = CreateRectRgn(0,0,0,0); + + RECT partRect; + WCHAR szBuffer[128] = {0}; + INT cchBuffer = 0; + + if (SUCCEEDED(GetName(szBuffer, ARRAYSIZE(szBuffer)))) + cchBuffer = lstrlenW(szBuffer); + + SetRect(&partRect, paintLeft, prc->top, prc->right - LABEL_MARGINCX, prc->bottom); + if (ExtTextOut(hdc, partRect.left + (partRect.right - partRect.left)/2, partRect.bottom - TEXT_OFFSET_BOTTOM, + ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL)) + { + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + if (NULL != backRgn) + { + FillRgn(hdc, backRgn, GetBrush(hdc, state)); + DeleteObject(backRgn); + } + if (NULL != rgn) + DeleteObject(rgn); + + + if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state)) + DrawFocusRect(hdc, prc); + + if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign); + if (origBk != rgbBk) SetBkColor(hdc, origBk); + if (origText != rgbText) SetTextColor(hdc, origText); + return TRUE; +} + +INT_PTR SetupListboxLabel::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) +{ + return -1; +} +BOOL SetupListboxLabel::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::MouseLeave(SetupListbox *instance, const RECT *prcItem) +{ + return FALSE; +} +BOOL SetupListboxLabel::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +BOOL SetupListboxLabel::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} +void SetupListboxLabel::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) +{ +} + +BOOL SetupListboxLabel::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + WCHAR szName[128] = {0}; + if (FAILED(GetName(szName, ARRAYSIZE(szName)))) + return FALSE; + + if (NULL == pszBuffer || + FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"lbl_empty_%s", szName))) + { + return FALSE; + } + return TRUE; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.h b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.h new file mode 100644 index 00000000..b1b474e4 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupListboxLabel.h @@ -0,0 +1,57 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_LABEL_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_LABEL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupListbox.h" + + +class SetupListboxLabel: public SetupListboxItem +{ + +protected: + SetupListboxLabel(LPCWSTR pszName); + ~SetupListboxLabel(); + +public: + static SetupListboxLabel *CreateInstance(LPCWSTR pszNamee); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT GetName(LPWSTR pszBuffer, INT cchBufferMax); + HRESULT SetName(LPCWSTR pszName); + BOOL IsNameNull(); + + void GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut); + HBRUSH GetBrush(HDC hdc, UINT state); + + + /* SetupListboxItem */ + BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy); + BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state); + INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey); + BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem); + BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured); + BOOL IsDisabled() { return TRUE; } + void Command(SetupListbox *instance, INT commandId, INT eventId) {} + HWND CreateDetailsView(HWND hParent) { return NULL; } + BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + + +protected: + ULONG ref; + LPWSTR name; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLISTBOX_LABEL_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupLog.cpp b/Src/Plugins/Library/ml_online/Setup/setupLog.cpp new file mode 100644 index 00000000..a53c469f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupLog.cpp @@ -0,0 +1,395 @@ +#include "./setupLog.h" +#include "../common.h" +#include "../api__ml_online.h" +#include "../config.h" + +#include "../../nu/trace.h" + +#include <ifc_omservice.h> +#include <ifc_omwebstorage.h> +#include <ifc_omstorageasync.h> + +#include <shlwapi.h> +#include <strsafe.h> + +#define SETUPLOG_SEPARATOR ',' +#define SETUPLOG_SECTION "Setup" +#define SETUPLOG_KEY_SUBSCRIBED "subscribed" +#define SETUPLOG_KEY_UNSUBSCRIBED "unsubscribed" + +struct LOGPARSERPARAM +{ + LOGPARSERPARAM() : instance(NULL), operation(0) {} + + SetupLog *instance; + UINT operation; +}; + +static size_t SetupLog_GetMaxServiceIdCount(SetupLog::ServiceMap *serviceMap) +{ + SetupLog::ServiceMap::iterator it; + + size_t c1 = 0, c2 = 0; + for (it = serviceMap->begin(); it != serviceMap->end(); it++) + { + switch(it->second) + { + case SetupLog::opServiceAdded: + c1++; + break; + case SetupLog::opServiceRemoved: + c2++; + break; + } + } + return (c1 > c2) ? c1 : c2; +} + +static HRESULT SetupLog_FormatServiceId(SetupLog::ServiceMap *serviceMap, INT operation, LPSTR pszBuffer, size_t cchBufferMax) +{ + if (NULL == pszBuffer) + return E_INVALIDARG; + + *pszBuffer = '\0'; + + if (NULL == serviceMap) + return S_OK; + + HRESULT hr = S_OK; + size_t remaining = cchBufferMax; + LPSTR cursor = pszBuffer; + SetupLog::ServiceMap::iterator it; + + const char format[] = { SETUPLOG_SEPARATOR, '%', 'u', '\0'}; + + for (it = serviceMap->begin(); it != serviceMap->end() && SUCCEEDED(hr); it++) + { + if (it->second == operation) + { + hr = StringCchPrintfExA(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + ((cursor == pszBuffer) ? (format + 1) : format), it->first); + } + } + return hr; +} + +static LPCSTR SetupLog_GetOperationKey(UINT operation) +{ + switch(operation) + { + case SetupLog::opServiceAdded: return SETUPLOG_KEY_SUBSCRIBED; + case SetupLog::opServiceRemoved: return SETUPLOG_KEY_UNSUBSCRIBED; + } + return NULL; +} + +static LPCWSTR SetupLog_GetOperationAction(UINT operation) +{ + switch(operation) + { + case SetupLog::opServiceAdded: return L"add"; + case SetupLog::opServiceRemoved: return L"remove"; + } + return NULL; +} + +static BOOL SetupLog_WriteOperationLog(UINT operation, LPCSTR pszValue) +{ + LPCSTR pszKey = SetupLog_GetOperationKey(operation); + if (NULL == pszKey) return FALSE; + return Config_WriteStr(SETUPLOG_SECTION, pszKey, pszValue); +} + +static HRESULT SetupLog_ReadOperationLog(UINT operation, LPSTR pszBuffer, UINT cchBufferMax, UINT *cchReaded) +{ + LPCSTR pszKey = SetupLog_GetOperationKey(operation); + if (NULL == pszKey) return E_INVALIDARG; + + DWORD readed = Config_ReadStr(SETUPLOG_SECTION, pszKey, NULL, pszBuffer, cchBufferMax); + + if (NULL != cchReaded) + { + *cchReaded = readed; + } + + return S_OK; +} + +SetupLog::SetupLog() : ref(1) +{ +} + +SetupLog::~SetupLog() +{ + +} + +SetupLog *SetupLog::Open() +{ + SetupLog *instance = new SetupLog(); + if (NULL == instance) return NULL; + + INT cchBuffer = 32000; + LPSTR buffer = Plugin_MallocAnsiString(cchBuffer); + if (NULL == buffer) + { + instance->Release(); + return NULL; + } + + UINT cchReaded = 0; + const UINT szOperations[] = { opServiceAdded, + opServiceRemoved, }; + + UINT serviceId; + for (INT i = 0; i < ARRAYSIZE(szOperations); i++) + { + if (SUCCEEDED(SetupLog_ReadOperationLog(szOperations[i], buffer, cchBuffer, &cchReaded)) && cchReaded > 0) + { + LPSTR cursor = buffer; + LPSTR block = cursor; + + for(;;) + { + if (SETUPLOG_SEPARATOR == *cursor || '\0' == *cursor) + { + while (' ' == *block && block < cursor) block++; + + if (block < cursor && + FALSE != StrToIntExA(block, STIF_SUPPORT_HEX, (INT*)&serviceId) && + 0 != serviceId) + { + instance->LogServiceById(serviceId, szOperations[i]); + } + + if ('\0' == *cursor) + break; + + cursor++; + block = cursor; + } + else + { + cursor++; + } + } + } + } + + Plugin_FreeAnsiString(buffer); + return instance; +} + +ULONG SetupLog::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupLog::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +BOOL SetupLog::IsOperationSupported(UINT operation) +{ + switch(operation) + { + case SetupLog::opServiceAdded: + case SetupLog::opServiceRemoved: + return TRUE; + } + return FALSE; +} + +HRESULT SetupLog::LogServiceById(UINT serviceUid, UINT operation) +{ + if (0 == serviceUid || FALSE == IsOperationSupported(operation)) + return E_INVALIDARG; + + serviceMap[serviceUid] = operation; + return S_OK; +} + +HRESULT SetupLog::LogService(ifc_omservice *service, UINT operation) +{ + if (NULL == service || !IsOperationSupported(operation)) + return E_INVALIDARG; + + return LogServiceById(service->GetId(), operation); +} + +HRESULT SetupLog::Save() +{ + LPSTR buffer = NULL; + size_t cchBuffer = SetupLog_GetMaxServiceIdCount(&serviceMap) * 11; + + if (0 != cchBuffer) + { + cchBuffer += 1; + buffer = Plugin_MallocAnsiString(cchBuffer); + if (NULL == buffer) + return E_OUTOFMEMORY; + } + + const UINT szOperations[] = { opServiceAdded, + opServiceRemoved, }; + + for (INT i = 0; i < ARRAYSIZE(szOperations); i++) + { + LPCSTR value = (NULL != buffer && + SUCCEEDED(SetupLog_FormatServiceId(&serviceMap, szOperations[i], buffer, cchBuffer)) && + '\0' != *buffer) ? buffer : NULL; + SetupLog_WriteOperationLog(szOperations[i], value); + } + + if (NULL != buffer) + Plugin_FreeAnsiString(buffer); + + return S_OK; +} + +HRESULT SetupLog::Erase() +{ + HRESULT hr = S_OK; + if (FALSE == Config_WriteStr(SETUPLOG_SECTION, SETUPLOG_KEY_SUBSCRIBED, NULL)) + hr = E_FAIL; + if (FALSE == Config_WriteStr(SETUPLOG_SECTION, SETUPLOG_KEY_UNSUBSCRIBED, NULL)) + hr = E_FAIL; + + return hr; +} + +struct LOGSENDJOBPARAM +{ + LOGSENDJOBPARAM() : totalJobs(0), storage(NULL), completeEvent(NULL) {} + + ULONG totalJobs; + CRITICAL_SECTION lock; + ifc_omstorage *storage; + HANDLE completeEvent; +}; + +static void CALLBACK SetupLog_SendCompleted(ifc_omstorageasync *async) +{ + if (NULL != async) + { + LOGSENDJOBPARAM *param = NULL; + if (SUCCEEDED(async->GetData((void**)¶m)) && NULL != param) + { + EnterCriticalSection(¶m->lock); + + if (NULL != param->storage) + { + param->storage->EndLoad(async, NULL); + param->storage->Release(); + } + + LONG r = InterlockedDecrement((LONG*)¶m->totalJobs); + if (0 == r) + { + if (NULL != param->completeEvent) + SetEvent(param->completeEvent); + + LeaveCriticalSection(¶m->lock); + DeleteCriticalSection(¶m->lock); + free(param); + param = NULL; + } + else + { + LeaveCriticalSection(¶m->lock); + } + } + } +} + +HRESULT SetupLog::Send(HANDLE completeEvent) +{ + size_t cchAlloc = serviceMap.size(); + if (0 == cchAlloc) + { + if (NULL != completeEvent) SetEvent(completeEvent); + return S_OK; + } + + UINT *buffer = (UINT*)calloc(cchAlloc, sizeof(UINT)); + LOGSENDJOBPARAM *param = (LOGSENDJOBPARAM*)calloc(1, sizeof(LOGSENDJOBPARAM)); + + if (NULL == buffer || NULL == param) + { + if (NULL != buffer) { free(buffer); buffer = NULL; } + if (NULL != param) { free(param); param = NULL; } + if (NULL != completeEvent) { SetEvent(completeEvent); completeEvent = NULL; } + return E_OUTOFMEMORY; + } + + ifc_omstorage *storage = NULL; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && storage != NULL) + { + const UINT szOperations[] = { opServiceAdded, + opServiceRemoved, }; + param->totalJobs = 0; + param->completeEvent = completeEvent; + param->storage = storage; + + InitializeCriticalSection(¶m->lock); + EnterCriticalSection(¶m->lock); + + for (INT i = 0; i < ARRAYSIZE(szOperations); i++) + { + size_t count = 0; + hr = S_OK; + for (SetupLog::ServiceMap::iterator it = serviceMap.begin(); it != serviceMap.end() && SUCCEEDED(hr); it++) + { + if (it->second == szOperations[i]) + { + buffer[count] = it->first; + count++; + } + } + + if (0 != count) + { + LPWSTR url = NULL; + LPCWSTR action = SetupLog_GetOperationAction(szOperations[i]); + if (NULL != action && + SUCCEEDED(Plugin_BuildActionUrl(&url, action, buffer, count))) + { + ifc_omstorageasync *async = NULL;; + if (SUCCEEDED(storage->BeginLoad(url, NULL, SetupLog_SendCompleted, param, &async))) + { + InterlockedIncrement((LONG*)¶m->totalJobs); + storage->AddRef(); + async->Release(); + } + Plugin_FreeString(url); + } + } + } + + if (0 == param->totalJobs) + { + LeaveCriticalSection(¶m->lock); + DeleteCriticalSection(¶m->lock); + hr = E_FAIL; + if (param) { free(param); param = NULL; } + } + else + { + LeaveCriticalSection(¶m->lock); + } + + storage->Release(); + } + + if (buffer) { free(buffer); buffer = NULL; } + return hr; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupLog.h b/Src/Plugins/Library/ml_online/Setup/setupLog.h new file mode 100644 index 00000000..e701046a --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupLog.h @@ -0,0 +1,54 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLOG_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLOG_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <map> + +class ifc_omservice; + +class SetupLog +{ +public: + typedef enum + { + opUnknown = 0, + opServiceAdded = 1, + opServiceRemoved = 2, + }; + +protected: + SetupLog(); + ~SetupLog(); + +public: + static SetupLog *Open(); + static HRESULT Erase(); + +public: + ULONG AddRef(); + ULONG Release(); + + HRESULT LogServiceById(UINT serviceUid, UINT operation); + HRESULT LogService(ifc_omservice *service, UINT operation); + HRESULT Save(); + HRESULT Send(HANDLE completeEvent); + + BOOL IsOperationSupported(UINT operation); + + + +protected: + typedef std::map<UINT, UINT> ServiceMap; + friend static size_t SetupLog_GetMaxServiceIdCount(SetupLog::ServiceMap *serviceMap); + friend static HRESULT SetupLog_FormatServiceId(SetupLog::ServiceMap *serviceMap, INT operation, LPSTR pszBuffer, size_t cchBufferMax); + +protected: + ULONG ref; + ServiceMap serviceMap; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPLOG_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupPage.cpp b/Src/Plugins/Library/ml_online/Setup/setupPage.cpp new file mode 100644 index 00000000..8b2db86d --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupPage.cpp @@ -0,0 +1,648 @@ +#include "./setupPage.h" +#include "./setupListbox.h" +#include "./setupGroupList.h" +#include "./setupGroupFilter.h" +#include "./setupListboxLabel.h" +#include "../common.h" +#include "../config.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include "./setupDetails.h" +#include "./setupLog.h" + +#include "../../winamp/setup/svc_setup.h" + +#include <ifc_omservice.h> +#include <ifc_omfilestorage.h> +#include <ifc_omwebstorage.h> + +#include <windows.h> +#include <strsafe.h> +#include <vector> + +#define FEATURED_SERVICES_URL L"http://services.winamp.com/svc/default" + +#define IDC_DETAILS 10000 + +typedef std::vector<ifc_omservice*> ServiceList; +typedef std::vector<UINT> ServiceIdList; + +HWND SetupPage_CreateWindow(HWND hParent, SetupPage *page); +static INT_PTR SetupPage_ModalLoop(HWND hwnd, HACCEL hAccel, HANDLE hCancel); + +struct AppendServiceToStringData +{ + AppendServiceToStringData() : formatFirst(NULL), formatNext(NULL), cursor(NULL), + remaining(0), inserted(0), result(S_OK) {} + + LPCWSTR formatFirst; + LPCWSTR formatNext; + LPWSTR cursor; + size_t remaining; + size_t inserted; + HRESULT result; +}; + +static BOOL CALLBACK SetupPage_AppendServiceToStringCallback(UINT serviceId, void *data) +{ + AppendServiceToStringData *param = (AppendServiceToStringData*)data; + if (NULL == param) return FALSE; + + param->result = StringCchPrintfEx(param->cursor, param->remaining, ¶m->cursor, ¶m->remaining, + STRSAFE_NULL_ON_FAILURE, + ((0 == param->inserted) ? param->formatFirst : param->formatNext), serviceId); + + if (FAILED(param->result)) + return FALSE; + + param->inserted++; + return TRUE; +} + +static BOOL CALLBACK SetupPage_AppendServiceIdCallback(UINT serviceId, void *data) +{ + ServiceIdList *list = (ServiceIdList*)data; + if (NULL == list) return FALSE; + list->push_back(serviceId); + return TRUE; +} + +static HRESULT SetupPage_GetFeaturedServicesUrl(LPWSTR pszBuffer, UINT cchBufferMax) +{ + LPWSTR cursor = pszBuffer; + size_t remaining = cchBufferMax; + + HRESULT hr = StringCchCopyEx(cursor, remaining, FEATURED_SERVICES_URL, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE); + if (FAILED(hr)) + return hr; + + AppendServiceToStringData param; + param.cursor = cursor; + param.remaining = remaining; + param.formatFirst = L"?svc_ids=%u"; + param.formatNext = L",%u"; + param.inserted = 0; + param.result = S_OK; + + hr = Config_ReadServiceIdList("Setup", "featuredExtra", ',', SetupPage_AppendServiceToStringCallback, ¶m); + if (SUCCEEDED(hr)) + hr = param.result; + + return hr; +} + +SetupPage* SetupPage::CreateInstance() +{ + SetupPage *instance = new SetupPage(); + return instance; +} + +SetupPage::SetupPage() + : ref(1), hwnd(NULL), name(NULL), title(NULL), + groupList(NULL), completeEvent(NULL), + servicesInitialized(FALSE) +{ + WasabiApi_AddRef(); + SetupDetails_Initialize(); +} + +SetupPage::~SetupPage() +{ + if (NULL != name) + { + Plugin_FreeString(name); + name = NULL; + } + + if (NULL != title) + { + Plugin_FreeString(title); + title = NULL; + } + + if (NULL != groupList) + { + groupList->Release(); + groupList = NULL; + } + + if (NULL != completeEvent) + { + CloseHandle(completeEvent); + completeEvent = NULL; + } + + SetupDetails_Uninitialize(); + + if (FALSE != servicesInitialized) + { + if (NULL != OMBROWSERMNGR) + OMBROWSERMNGR->Finish(); + } + + WasabiApi_Release(); +} + +size_t SetupPage::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t SetupPage::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int SetupPage::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + return E_NOTIMPL; +} + +HRESULT SetupPage::GetName(bool bShort, const wchar_t **pszName) +{ + InitializeServices(); + + if (false == bShort) + { + if (NULL == title) + { + WCHAR szBuffer[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_SETUPPAGE_TITLE, szBuffer, ARRAYSIZE(szBuffer)); + title = Plugin_CopyString(szBuffer); + } + *pszName = title; + } + else + { + if (NULL == name) + { + WCHAR szBuffer[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_ONLINE_SERVICES, szBuffer, ARRAYSIZE(szBuffer)); + name = Plugin_CopyString(szBuffer); + } + *pszName = name; + } + return S_OK; +} + +HRESULT SetupPage::Save(HWND hwndText) +{ + if (NULL == groupList) + return S_OK; + + SetupLog *log = SetupLog::Open(); + HRESULT hr = groupList->Save(log); + + if (NULL != log) + { + log->Save(); + log->Release(); + } + + return hr; +} + +HRESULT SetupPage::Revert(void) +{ + HRESULT hr(S_OK); + + if (NULL != groupList) + { + groupList->Release(); + groupList = NULL; + } + return hr; +} + +HRESULT SetupPage::IsDirty(void) +{ + return (NULL != groupList && groupList->IsModified()) ? S_OK : S_FALSE; +} + +HRESULT SetupPage::Validate(void) +{ + return S_OK; +} + +HRESULT SetupPage::InitializeServices() +{ + if (FALSE != servicesInitialized) + return S_FALSE; + + HWND hWinamp = NULL; + svc_setup *setupSvc = QueryWasabiInterface(svc_setup, UID_SVC_SETUP); + if (NULL == setupSvc) return E_UNEXPECTED; + HRESULT hr = setupSvc->GetWinampWnd(&hWinamp); + ReleaseWasabiInterface(UID_SVC_SETUP, setupSvc); + + if (SUCCEEDED(hr)) + { + hr = WasabiApi_LoadDefaults(); + if (SUCCEEDED(hr)) + { + if (NULL != OMBROWSERMNGR && + NULL != OMSERVICEMNGR && + NULL != OMUTILITY) + { + hr = OMBROWSERMNGR->Initialize(NULL, hWinamp); + } + else + hr = E_UNEXPECTED; + + if (SUCCEEDED(hr)) + servicesInitialized = TRUE; + } + } + + return hr; +} + +HRESULT SetupPage::CreateView(HWND hParent, HWND *phwnd) +{ + if (NULL == phwnd) + return E_INVALIDARG; + + if (FAILED(InitializeServices())) + { + *phwnd = NULL; + return E_FAIL; + } + + *phwnd = SetupPage_CreateWindow(hParent, this); + return (NULL == phwnd) ? E_FAIL : S_OK; +} + + +BOOL SetupPage::UpdateListAsync(INT groupId) +{ + if (NULL == hwnd) + return FALSE; + + return PostMessage(hwnd, SPM_UPDATELIST, (WPARAM)groupId, NULL); +} + +BOOL SetupPage::AttachWindow(HWND hAttach) +{ + hwnd = hAttach; + + if (NULL == completeEvent) + completeEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + + if (NULL == groupList) + { + groupList = SetupGroupList::CreateInstance(); + if (NULL != groupList) + { + WCHAR szBuffer[4096] = {0}; + SetupPage_GetFeaturedServicesUrl(szBuffer, ARRAYSIZE(szBuffer)); + + SetupGroup *group = SetupGroup::CreateInstance(ID_FEATUREDGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED), + szBuffer, &SUID_OmStorageUrl, &FUID_SetupFeaturedGroupFilter, + SetupGroup::styleSortAlphabetically | SetupGroup::styleDefaultSubscribed | SetupGroup::styleSaveAll); + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATUREDLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED_DESC)); + groupList->AddGroup(group); + group->RequestReload(); + group->Release(); + } + + group = SetupGroup::CreateInstance(ID_KNOWNGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN), + L"*.ini", &SUID_OmStorageIni, &FUID_SetupKnownGroupFilter, + SetupGroup::styleSortAlphabetically); + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWNLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN_DESC)); + group->RequestReload(); + groupList->AddGroup(group); + group->Release(); + } + } + } + + if (NULL != groupList) + groupList->SetPageWnd(hwnd); + + HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST); + if (NULL != hList) + { + SetupListbox *listbox; + if (SUCCEEDED(SetupListbox::CreateInstance(hList, groupList, &listbox))) + { + } + ListboxSelectionChanged(); + } + + return TRUE; +} + +void SetupPage::DetachWindow() +{ + hwnd = NULL; + if (NULL != groupList) + { + groupList->SetPageWnd(NULL); + } +} + + +HRESULT SetupPage_AppendUnselectedServices(LPCSTR pszSection, LPCSTR pszKey, SetupGroup *group) +{ + size_t index = group->GetRecordCount(); + size_t filterIndex, filterSize; + + ServiceIdList list; + Config_ReadServiceIdList(pszSection, pszKey, ',', SetupPage_AppendServiceIdCallback, &list); + filterSize = list.size(); + + while(index--) + { + SetupRecord *record = group->GetRecord(index); + if (NULL == record || FALSE != record->IsSelected()) continue; + + ifc_omservice *service = record->GetService(); + if (NULL == service) continue; + + UINT serviceId = service->GetId(); + for(filterIndex = 0; filterIndex < filterSize; filterIndex++) + { + if (list[filterIndex] == serviceId) + break; + } + + if (filterIndex == filterSize) + list.push_back(serviceId); + } + + if (0 != list.size()) + { + size_t bufferAlloc = (list.size() * 11) * sizeof(CHAR); + LPSTR buffer = Plugin_MallocAnsiString(bufferAlloc); + if (NULL != buffer) + { + filterSize = list.size(); + LPSTR cursor = buffer; + size_t remaining = bufferAlloc; + for(index = 0; index < filterSize; index++) + { + if (FAILED(StringCchPrintfExA(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + ((0 == index) ? "%u" : ",%u"), list[index]))) + { + break; + } + } + Config_WriteStr(pszSection, pszKey, buffer); + Plugin_FreeAnsiString(buffer); + } + } + else + Config_WriteStr(pszSection, pszKey, NULL); + + return S_OK; +} + +HRESULT SetupPage::Execute(HWND hwndText) +{ + SetupGroup *group = NULL; + SetupLog *log = SetupLog::Open(); + WCHAR szBuffer[128] = {0}; + + if (FAILED(InitializeServices())) + return E_FAIL; + + if (NULL == groupList) + { + groupList = SetupGroupList::CreateInstance(); + if (NULL == groupList) return E_UNEXPECTED; + } + + if (S_OK != groupList->FindGroupById(ID_FEATUREDGROUP, &group) && group != NULL) + { + WCHAR szBuffer[4096] = {0}; + SetupPage_GetFeaturedServicesUrl(szBuffer, ARRAYSIZE(szBuffer)); + + group = SetupGroup::CreateInstance(ID_FEATUREDGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED), + szBuffer, &SUID_OmStorageUrl, &FUID_SetupFeaturedGroupFilter, + SetupGroup::styleDefaultSubscribed | SetupGroup::styleSaveAll); + + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATUREDLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED_DESC)); + groupList->AddGroup(group); + group->RequestReload(); + } + } + + if (NULL == completeEvent) + completeEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (NULL != group) + { + if (SUCCEEDED(group->SignalLoadCompleted(completeEvent))) + { + WASABI_API_LNGSTRINGW_BUF(IDS_DOWNLOADSERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + SetupPage_ModalLoop(hwndText, NULL, completeEvent); + } + + WASABI_API_LNGSTRINGW_BUF(IDS_SAVESERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + group->Save(log); + SetupPage_AppendUnselectedServices("Setup", "featuredHistory", group); + group->Release(); + group = NULL; + } + + // ensure that promotions are subscribed + if (S_OK != groupList->FindGroupById(ID_KNOWNGROUP, &group) && group != NULL) + { + group = SetupGroup::CreateInstance(ID_KNOWNGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN), + L"*.ini", &SUID_OmStorageIni, &FUID_SetupKnownGroupFilter, + SetupGroup::styleSortAlphabetically); + if (NULL != group) + { + group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWNLONG)); + group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN_DESC)); + group->RequestReload(); + groupList->AddGroup(group); + } + } + + if (NULL != group) + { + WASABI_API_LNGSTRINGW_BUF(IDS_SAVESERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + + ResetEvent(completeEvent); + if (SUCCEEDED(group->SignalLoadCompleted(completeEvent))) + SetupPage_ModalLoop(hwndText, NULL, completeEvent); + + group->Save(log); + group->Release(); + group = NULL; + } + + if (NULL != log) + { + WASABI_API_LNGSTRINGW_BUF(IDS_REGISTERINGSERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer)); + SetWindowText(hwndText, szBuffer); + ResetEvent(completeEvent); + log->Send(completeEvent); + SetupPage_ModalLoop(hwndText, NULL, completeEvent); + log->Release(); + } + + SetupLog::Erase(); + Config_WriteStr("Setup", "featuredExtra", NULL); // delete promo offer + return S_OK; +} + +HRESULT SetupPage::Cancel(HWND hwndText) +{ + if (NULL != completeEvent) + SetEvent(completeEvent); + return S_OK; +} + +HRESULT SetupPage::IsCancelSupported(void) +{ + return S_OK; +} +void SetupPage::ListboxSelectionChanged() +{ + if (NULL == hwnd) return; + HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST); + if (NULL == hList) return; + + SetupListboxItem *item = NULL; + INT iSelection = (INT)SendMessage(hList, LB_GETCURSEL, 0, 0L); + if (LB_ERR == iSelection || + FAILED(groupList->FindListboxItem(iSelection, &item))) + { + item = NULL; + } + + HWND hDiscard = GetDlgItem(hwnd, IDC_DETAILS); + if (NULL != hDiscard) + { + WCHAR szPanel[64] = {0}, szItem[64] = {0}; + if (FALSE != SetupDetails_GetUniqueName(hDiscard, szPanel, ARRAYSIZE(szPanel)) && + FALSE != item->GetUniqueName(szItem, ARRAYSIZE(szItem)) && + CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, szPanel, - 1, szItem, -1)) + { + return; + } + } + + HWND hDetails = (NULL != item) ? item->CreateDetailsView(hwnd) : NULL; + if (NULL != hDiscard) + { + SetWindowLongPtr(hDiscard, GWL_STYLE, GetWindowLongPtr(hDiscard, GWL_STYLE) & ~WS_VISIBLE); + } + + if (NULL != hDetails) + { + HWND hPlaceholder = GetDlgItem(hwnd, IDC_PLACEHOLDER); + if (NULL != hPlaceholder) + { + RECT windowRect; + if (GetWindowRect(hPlaceholder, &windowRect)) + { + MapWindowPoints(HWND_DESKTOP,hwnd, (POINT*)&windowRect,2); + SetWindowPos(hDetails, NULL, windowRect.left, windowRect.top, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } + SetWindowLongPtr(hDetails, GWLP_ID, IDC_DETAILS); + ShowWindow(hDetails, SW_SHOWNA); + RedrawWindow(hDetails, NULL, NULL, RDW_ERASENOW |RDW_UPDATENOW | RDW_ALLCHILDREN); + } + } + + if (NULL != hDiscard) + { + DestroyWindow(hDiscard); + } +} + +static INT_PTR SetupPage_ModalLoop(HWND hwnd, HACCEL hAccel, HANDLE hCancel) +{ + MSG msg = {0}; + HWND hParent = NULL; + while (NULL != (hParent = GetAncestor(hwnd, GA_PARENT))) + { + hwnd = hParent; + } + + if (NULL == hwnd) + return 0; + + for (;;) + { + DWORD status = MsgWaitForMultipleObjectsEx(1, &hCancel, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + if (WAIT_OBJECT_0 == status) + { + return 0; + } + else if ((WAIT_OBJECT_0 + 1)== status) + { + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + //if (!CallMsgFilter(&msg, MSGF_DIALOGBOX)) + { + if (msg.message == WM_QUIT) + { + PostQuitMessage((INT)msg.wParam); + return msg.wParam; + } + + if (!TranslateAcceleratorW(hwnd, hAccel, &msg) && + !IsDialogMessageW(hwnd, &msg)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + } + } + } + return 0; +} + +#define CBCLASS SetupPage +START_MULTIPATCH; + START_PATCH(MPIID_SETUPPAGE) + M_CB(MPIID_SETUPPAGE, ifc_setuppage, ADDREF, AddRef); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, RELEASE, Release); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, QUERYINTERFACE, QueryInterface); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_GET_NAME, GetName); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_CREATEVIEW, CreateView); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_SAVE, Save); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_REVERT, Revert); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_ISDIRTY, IsDirty); + M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_VALIDATE, Validate); + + NEXT_PATCH(MPIID_SETUPJOB) + M_CB(MPIID_SETUPJOB, ifc_setupjob, ADDREF, AddRef); + M_CB(MPIID_SETUPJOB, ifc_setupjob, RELEASE, Release); + M_CB(MPIID_SETUPJOB, ifc_setupjob, QUERYINTERFACE, QueryInterface); + M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_EXECUTE, Execute); + M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_CANCEL, Cancel); + M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_ISCANCELSUPPORTED, IsCancelSupported); + + END_PATCH +END_MULTIPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupPage.h b/Src/Plugins/Library/ml_online/Setup/setupPage.h new file mode 100644 index 00000000..ea45357f --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupPage.h @@ -0,0 +1,85 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPPAGE_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPPAGE_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <bfc/multipatch.h> + +#include "../../winamp/setup/ifc_setuppage.h" +#include "../../winamp/setup/ifc_setupjob.h" + +#include "./setupGroupList.h" + +class SetupListboxLabel; + +#define ID_KNOWNGROUP 0 +#define ID_FEATUREDGROUP 1 + +#define MPIID_SETUPPAGE 10 +#define MPIID_SETUPJOB 20 + +#define SPM_FIRST (WM_APP + 2) +#define SPM_UPDATELIST (SPM_FIRST + 0) + +class SetupPage : public MultiPatch<MPIID_SETUPPAGE, ifc_setuppage>, + public MultiPatch<MPIID_SETUPJOB, ifc_setupjob> +{ +protected: + typedef enum + { + flagInitWasabi = 0x00000001, + }; + +protected: + SetupPage(); + virtual ~SetupPage(); + +public: + static SetupPage* CreateInstance(); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_setuppage */ + HRESULT GetName(bool bShort, const wchar_t **pszName); + HRESULT Save(HWND hText); + HRESULT CreateView(HWND hParent, HWND *phwnd); + HRESULT Revert(void); + HRESULT IsDirty(void); + HRESULT Validate(void); + + /* ifc_setupjob */ + HRESULT Execute(HWND hwndText); + HRESULT Cancel(HWND hwndText); + HRESULT IsCancelSupported(void); + +public: + BOOL AttachWindow(HWND hAttach); + void DetachWindow(); + + void ListboxSelectionChanged(); + BOOL UpdateListAsync(INT groupId); + +protected: + HRESULT InitializeServices(); + +private: + size_t ref; + HWND hwnd; + LPWSTR name; + LPWSTR title; + SetupGroupList *groupList; + HANDLE completeEvent; + BOOL servicesInitialized; + +protected: + RECVS_MULTIPATCH; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPPAGE_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupPageWnd.cpp b/Src/Plugins/Library/ml_online/Setup/setupPageWnd.cpp new file mode 100644 index 00000000..338df688 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupPageWnd.cpp @@ -0,0 +1,145 @@ +#include "./setupPage.h" +#include "./setupListbox.h" +#include "../common.h" +#include "../resource.h" +#include "../api__ml_online.h" + +static ATOM SETUPPAGE_PROP = 0; + +#define GetPage(__hwnd) ((SetupPage*)GetPropW((__hwnd), MAKEINTATOM(SETUPPAGE_PROP))) + +static INT_PTR WINAPI SetupPage_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + + +HWND SetupPage_CreateWindow(HWND hParent, SetupPage *page) +{ + return WASABI_API_CREATEDIALOGPARAMW(IDD_SETUPPAGE, hParent, SetupPage_DialogProc, (LPARAM)page); +} + +static INT_PTR SetupPage_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam) +{ + if (0 == SETUPPAGE_PROP) + { + SETUPPAGE_PROP = GlobalAddAtom(L"omSetupPageProp"); + if (0 == SETUPPAGE_PROP) return FALSE; + } + + SetupPage *page = (SetupPage*)lParam; + if (NULL != page && page->AttachWindow(hwnd)) + { + SetProp(hwnd, MAKEINTATOM(SETUPPAGE_PROP), page); + } + + return FALSE; +} + +static void SetupPage_OnDestroy(HWND hwnd) +{ + SetupPage *page = GetPage(hwnd); + if (NULL != page) + { + page->DetachWindow(); + } + RemoveProp(hwnd, MAKEINTATOM(SETUPPAGE_PROP)); +} + +static void SetupPage_OnCommand(HWND hwnd, INT controlId, INT eventId, HWND hControl) +{ + SetupPage *page; + switch(controlId) + { + case IDC_SERVICELIST: + switch(eventId) + { + case LBN_SELCHANGE: + page = GetPage(hwnd); + if (NULL != page) + page->ListboxSelectionChanged(); + break; + } + break; + } +} + +static BOOL SetupPage_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT *pmis) +{ + SetupListbox *instance; + switch(pmis->CtlID) + { + case IDC_SERVICELIST: + instance = SetupListbox::GetInstance(GetDlgItem(hwnd, pmis->CtlID)); + if (NULL != instance) + { + return instance->MeasureItem(pmis->itemID, &pmis->itemWidth, &pmis->itemHeight); + } + break; + } + return FALSE; +} + +static BOOL SetupPage_OnDrawItem(HWND hwnd, DRAWITEMSTRUCT *pdis) +{ + SetupListbox *instance; + switch(pdis->CtlID) + { + case IDC_SERVICELIST: + instance = SetupListbox::GetInstance(pdis->hwndItem); + if (NULL != instance) + { + return instance->DrawItem(pdis->hDC, &pdis->rcItem, pdis->itemID, pdis->itemState, pdis->itemAction); + } + break; + } + return FALSE; +} + +static INT_PTR SetupPage_OnCharToItem(HWND hwnd, INT vKey, INT caretPos, HWND hList) +{ + + if (IDC_SERVICELIST == GetDlgCtrlID(hList)) + { + SetupListbox *instance = SetupListbox::GetInstance(hList); + if (NULL != instance) + return instance->CharToItem(vKey, caretPos); + } + return -1; +} + +static INT_PTR SetupPage_OnKeyToItem(HWND hwnd, INT vKey, INT caretPos, HWND hList) +{ + if (IDC_SERVICELIST == GetDlgCtrlID(hList)) + { + SetupListbox *instance = SetupListbox::GetInstance(hList); + if (NULL != instance) + return instance->KeyToItem(vKey, caretPos); + } + return -1; +} +static void SetupPage_OnUpdateList(HWND hwnd, INT groupId) +{ + HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST); + if (NULL != hList) + { + SetupListbox *listbox = SetupListbox::GetInstance(hList); + if (NULL != listbox) + { + listbox->UpdateCount(); + } + } +} +static INT_PTR WINAPI SetupPage_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return SetupPage_OnInitDialog(hwnd, (HWND)wParam, lParam); + case WM_DESTROY: SetupPage_OnDestroy(hwnd); break; + case WM_COMMAND: SetupPage_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break; + case WM_MEASUREITEM: return SetupPage_OnMeasureItem(hwnd, (MEASUREITEMSTRUCT*)lParam); + case WM_DRAWITEM: return SetupPage_OnDrawItem(hwnd, (DRAWITEMSTRUCT*)lParam); + case WM_CHARTOITEM: return SetupPage_OnCharToItem(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); + case WM_VKEYTOITEM: return SetupPage_OnKeyToItem(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); + case SPM_UPDATELIST: SetupPage_OnUpdateList(hwnd, (INT)wParam); return TRUE; + } + return 0; +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupRecord.cpp b/Src/Plugins/Library/ml_online/Setup/setupRecord.cpp new file mode 100644 index 00000000..995ed222 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupRecord.cpp @@ -0,0 +1,567 @@ +#include "./main.h" +#include "../api__ml_online.h" +#include "./setupRecord.h" +#include "./setupDetails.h" +#include "./setupLog.h" +#include "../resource.h" + +#include "./serviceHelper.h" +#include "./serviceHost.h" + +#include <ifc_omservice.h> +#include <ifc_omwebstorage.h> +#include <ifc_omserviceenum.h> +#include <ifc_omservicecopier.h> + +#include <wininet.h> +#include <strsafe.h> + +#define RECORD_MARGINCX 6 +#define RECORD_MARGINCY 2 +#define CHECKBOX_MARGIN_RIGHT 2 + +#define TEXT_OFFSET_LEFT 3 +#define TEXT_OFFSET_BOTTOM RECORD_MARGINCY +#define TEXT_ALIGN (TA_LEFT | TA_BOTTOM) + +SetupRecord::SetupRecord(ifc_omservice *serviceToUse) + : ref(1), service(serviceToUse), flags(0), async(NULL) +{ + if (NULL != service) + { + if (S_OK == ServiceHelper_IsSubscribed(service)) + flags |= recordSelected; + service->AddRef(); + } + + InitializeCriticalSection(&lock); +} + +SetupRecord::~SetupRecord() +{ + EnterCriticalSection(&lock); + + if (NULL != async) + { + ifc_omstorage *storage = NULL; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && storage != NULL) + { + storage->RequestAbort(async, TRUE); + } + + async->Release(); + async = NULL; + } + + if (NULL != service) + service->Release(); + + LeaveCriticalSection(&lock); + DeleteCriticalSection(&lock); +} + +SetupRecord *SetupRecord::CreateInstance(ifc_omservice *serviceToUse) +{ + if (NULL == serviceToUse) return NULL; + return new SetupRecord(serviceToUse); +} + +ULONG SetupRecord::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +ULONG SetupRecord::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +HRESULT SetupRecord::GetServiceName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == service) return E_UNEXPECTED; + return service->GetName(pszBuffer, cchBufferMax); +} + +HRESULT SetupRecord::GetDisplayName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + HRESULT hr = GetServiceName(pszBuffer, cchBufferMax); + if (SUCCEEDED(hr) && L'\0' == *pszBuffer) + { + WASABI_API_LNGSTRINGW_BUF(IDS_DEFAULT_SERVICENAME, pszBuffer, cchBufferMax); + DownloadDetails(); + } + return hr; +} + +HRESULT SetupRecord::DownloadDetails() +{ + HRESULT hr; + EnterCriticalSection(&lock); + if (NULL == async && 0 == (recordDownloaded & flags)) + { + WCHAR szUrl[INTERNET_MAX_URL_LENGTH] = {0}; + hr = ServiceHelper_GetDetailsUrl(szUrl, ARRAYSIZE(szUrl), service, FALSE); + if (SUCCEEDED(hr)) + { + ifc_omstorage *storage = NULL; + hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && storage != NULL) + { + ServiceHost *serviceHost = NULL; + if (FAILED(ServiceHost::GetCachedInstance(&serviceHost))) + serviceHost = NULL; + + hr = storage->BeginLoad(szUrl, serviceHost, SetupRecord_ServiceDownloadedCallback, this, &async); + storage->Release(); + + if (NULL != serviceHost) + serviceHost->Release(); + } + } + } + else + { + hr = S_FALSE; + } + LeaveCriticalSection(&lock); + return hr; +} + +HRESULT SetupRecord::Save(SetupLog *log) +{ + if (NULL == service) return E_POINTER; + + HRESULT hr = ServiceHelper_Subscribe(service, IsSelected(), SHF_SAVE); + if (S_OK == hr) + { + if (NULL != log) + { + INT operation = (IsSelected()) ? SetupLog::opServiceAdded : SetupLog::opServiceRemoved; + log->LogService(service, operation); + } + + } + + return hr; +} + +BOOL SetupRecord::IsModified() +{ + if (NULL == service) + return FALSE; + + if (S_OK == ServiceHelper_IsSubscribed(service) != (FALSE != IsSelected())) + return TRUE; + if (S_OK == ServiceHelper_IsModified(service)) + return TRUE; + + return FALSE; +} + +BOOL SetupRecord::IsSelected() +{ + return (0 != (recordSelected & flags)); +} + +void SetupRecord::SetSelected(BOOL fSelected) +{ + if ((FALSE == fSelected) == !IsSelected()) + return; + + if (FALSE == fSelected) + flags &= ~recordSelected; + else + flags |= recordSelected; +} + +BOOL SetupRecord::AdjustCheckboxRect(SetupListbox *instance, RECT *prcItem) +{ + SIZE checkSize; + if (!instance->GetCheckboxMetrics(NULL, IsSelected(), 0, &checkSize)) + return FALSE; + + prcItem->left += RECORD_MARGINCX; + prcItem->right = prcItem->left + checkSize.cx; + + if (checkSize.cy > (prcItem->bottom - prcItem->top)) + checkSize.cy = (prcItem->bottom - prcItem->top); + prcItem->top += ((prcItem->bottom - prcItem->top) - checkSize.cy) / 2; + prcItem->bottom = prcItem->top + checkSize.cy; + return TRUE; +} + +BOOL SetupRecord::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy) +{ + HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL == hdc) return FALSE; + + HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont()); + + SIZE checkSize; + instance->GetCheckboxMetrics(hdc, IsSelected(), 0, &checkSize); + + if (NULL != cy) + { + *cy = 0; + TEXTMETRIC tm = {0}; + if (GetTextMetrics(hdc, &tm)) + { + *cy = tm.tmHeight + tm.tmExternalLeading; + if (checkSize.cy > (INT)*cy) *cy = checkSize.cy; + *cy += RECORD_MARGINCY*2; + } + } + + if (NULL != cx) + { + *cx = checkSize.cx; + WCHAR szBuffer[128] = {0}; + if (SUCCEEDED(GetDisplayName(szBuffer, ARRAYSIZE(szBuffer)))) + { + INT cchBuffer = lstrlenW(szBuffer); + SIZE textSize; + if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize)) + { + *cx += textSize.cx; + if (0 != checkSize.cx) + *cx += CHECKBOX_MARGIN_RIGHT + RECORD_MARGINCX; + } + } + if (0 != *cx) *cx += RECORD_MARGINCX*2; + } + + SelectObject(hdc, originalFont); + ReleaseDC(instance->GetHwnd(), hdc); + return TRUE; +} + +void SetupRecord::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut) +{ + COLORREF rgbBk, rgbText; + + if (0 != (ODS_DISABLED & state)) + { + rgbBk = GetBkColor(hdc); + rgbText = GetSysColor(COLOR_GRAYTEXT); + } + else if (0 != (ODS_SELECTED & state)) + { + if (0 == (ODS_INACTIVE & state)) + { + rgbBk = GetSysColor(COLOR_HIGHLIGHT); + rgbText = GetSysColor(COLOR_HIGHLIGHTTEXT); + } + else + { + rgbBk = GetSysColor(COLOR_3DFACE); + rgbText = GetTextColor(hdc); + } + } + else + { + rgbBk = GetBkColor(hdc); + rgbText = GetTextColor(hdc); + } + + if (NULL != rgbBkOut) *rgbBkOut = rgbBk; + if (NULL != rgbTextOut) *rgbTextOut = rgbText; +} + +BOOL SetupRecord::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state) +{ + LONG paintLeft = prc->left + RECORD_MARGINCX; + RECT partRect; + + UINT checkState = state & ~ODS_SELECTED; + if (0 == (checkboxPressed & flags)) + { + if (0 != (checkboxHighlighted & flags)) + checkState |= ODS_HOTLIGHT; + } + else + { + checkState |= ((0 != (checkboxHighlighted & flags)) ? ODS_SELECTED : ODS_HOTLIGHT); + } + + HRGN backRgn, rgn; + backRgn = CreateRectRgnIndirect(prc); + rgn = CreateRectRgn(0,0,0,0); + + SetRectEmpty(&partRect); + instance->GetCheckboxMetrics(hdc, IsSelected(), checkState, (((SIZE*)&partRect) + 1)); + + INT space = (prc->bottom - prc->top) - (partRect.bottom- partRect.top); + INT offsetY = space / 2 + space%2; + if (offsetY < 0) offsetY = 0; + + OffsetRect(&partRect, paintLeft, prc->top + offsetY); + if (instance->DrawCheckbox(hdc, IsSelected(), checkState, &partRect, prc)) + { + paintLeft = partRect.right + CHECKBOX_MARGIN_RIGHT; + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + + } + + COLORREF rgbBk, rgbText; + GetColors(hdc, state, &rgbBk, &rgbText); + + COLORREF origBk = SetBkColor(hdc, rgbBk); + COLORREF origText = SetTextColor(hdc, rgbText); + UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN); + + WCHAR szBuffer[128] = {0}; + INT cchBuffer = 0; + if (SUCCEEDED(GetDisplayName(szBuffer, ARRAYSIZE(szBuffer)))) + cchBuffer = lstrlenW(szBuffer); + + SetRect(&partRect, paintLeft, prc->top, prc->right, prc->bottom); + if (ExtTextOut(hdc, partRect.left + TEXT_OFFSET_LEFT, partRect.bottom - TEXT_OFFSET_BOTTOM, + ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL)) + { + if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom)) + CombineRgn(backRgn, backRgn, rgn, RGN_DIFF); + } + + if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state)) + DrawFocusRect(hdc, &partRect); + + if (NULL != backRgn) + { + PaintRgn(hdc, backRgn); + DeleteObject(backRgn); + } + if (NULL != rgn) + DeleteObject(rgn); + + if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign); + if (origBk != rgbBk) SetBkColor(hdc, origBk); + if (origText != rgbText) SetTextColor(hdc, origText); + + return TRUE; +} + +INT_PTR SetupRecord::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey) +{ + switch(vKey) + { + case VK_SPACE: + InvertCheckbox(instance, prcItem); + return -2; + } + return -1; +} + +BOOL SetupRecord::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + RECT checkboxRect; + BOOL fInvalidate = FALSE; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + + if (prcItem->top <= pt.y && pt.y < prcItem->bottom && + checkboxRect.left <= pt.x && pt.x < checkboxRect.right) + { + if (0 == (checkboxHighlighted & flags)) + { + flags |= checkboxHighlighted; + fInvalidate = TRUE; + } + } + else + { + if (0 != (checkboxHighlighted & flags)) + { + flags &= ~checkboxHighlighted; + fInvalidate = TRUE; + } + } + + if (FALSE != fInvalidate) + instance->InvalidateRect(&checkboxRect, FALSE); + + return FALSE; +} + +BOOL SetupRecord::MouseLeave(SetupListbox *instance, const RECT *prcItem) +{ + if (0 != (checkboxHighlighted & flags)) + { + flags &= ~checkboxHighlighted; + RECT checkboxRect; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + instance->InvalidateRect(&checkboxRect, FALSE); + } + return FALSE; +} + +BOOL SetupRecord::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + RECT checkboxRect; + BOOL handled = FALSE; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + + if (prcItem->top <= pt.y && pt.y < prcItem->bottom && + prcItem->left <= pt.x && pt.x < (checkboxRect.right + CHECKBOX_MARGIN_RIGHT)) + { + handled = TRUE; + if (checkboxRect.left <= pt.x && pt.x < checkboxRect.right) + { + flags |= (checkboxHighlighted | checkboxPressed); + instance->SetCapture(this); + instance->InvalidateRect(&checkboxRect, FALSE); + } + } + return handled; +} + +BOOL SetupRecord::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + RECT checkboxRect; + BOOL handled = FALSE; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + + if (0 != (checkboxPressed & flags)) + { + flags &= ~checkboxPressed; + if (this == instance->GetCapture()) + instance->ReleaseCapture(); + + if (prcItem->top <= pt.y && pt.y < prcItem->bottom && + checkboxRect.left <= pt.x && pt.x < checkboxRect.right) + { + SetSelected(!IsSelected()); + handled = TRUE; + } + instance->InvalidateRect(&checkboxRect, FALSE); + } + return handled; +} + +BOOL SetupRecord::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + InvertCheckbox(instance, prcItem); + return TRUE; +} + +BOOL SetupRecord::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} + +BOOL SetupRecord::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt) +{ + return FALSE; +} + +void SetupRecord::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured) +{ +} + +void SetupRecord::InvertCheckbox(SetupListbox *instance, const RECT *prcItem) +{ + SetSelected(!IsSelected()); + + if (NULL != instance && NULL != prcItem) + { + RECT checkboxRect; + CopyRect(&checkboxRect, prcItem); + AdjustCheckboxRect(instance, &checkboxRect); + instance->InvalidateRect(&checkboxRect, FALSE); + } +} + +HWND SetupRecord::CreateDetailsView(HWND hParent) +{ + DownloadDetails(); + + WCHAR szName[64] = {0}; + if (FALSE == GetUniqueName(szName, ARRAYSIZE(szName))) + szName[0] = L'\0'; + + return SetupDetails_CreateServiceView(hParent, szName, service); +} + +BOOL SetupRecord::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer || + FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"record_svc_%u", service->GetId()))) + { + return FALSE; + } + return TRUE; +} + +void SetupRecord::OnDownloadCompleted() +{ + ifc_omstorage *storage = NULL; + HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage); + if (SUCCEEDED(hr) && service != NULL) + { + ifc_omserviceenum *serviceEnum = NULL; + hr = storage->EndLoad(async, &serviceEnum); + if (SUCCEEDED(hr) && serviceEnum != NULL) + { + EnterCriticalSection(&lock); + + ifc_omservice *result = NULL; + while(S_OK == serviceEnum->Next(1, &result, NULL)) + { + if (result) + { + if (result->GetId() == service->GetId()) + { + ifc_omservicecopier *copier; + if (SUCCEEDED(result->QueryInterface(IFC_OmServiceCopier, (void**)&copier))) + { + copier->CopyTo(service, NULL); + copier->Release(); + } + result->Release(); + flags |= recordDownloaded; + break; + } + else + { + result->Release(); + } + } + result = NULL; + } + + LeaveCriticalSection(&lock); + + serviceEnum->Release(); + } + + storage->Release(); + } + + EnterCriticalSection(&lock); + + async->Release(); + async = NULL; + + LeaveCriticalSection(&lock); +} + +void CALLBACK SetupRecord_ServiceDownloadedCallback(ifc_omstorageasync *result) +{ + if (NULL == result) return; + SetupRecord *record = NULL; + if (SUCCEEDED(result->GetData((void**)&record)) && NULL != record) + { + record->OnDownloadCompleted(); + } +}
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupRecord.h b/Src/Plugins/Library/ml_online/Setup/setupRecord.h new file mode 100644 index 00000000..b6573e1a --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupRecord.h @@ -0,0 +1,84 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPRECORD_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPRECORD_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include "./setupListbox.h" + +class ifc_omservice; +class ifc_omstorageasync; +class SetupLog; + +class SetupRecord : public SetupListboxItem + +{ +protected: + typedef enum + { + recordSelected = 0x0001, + recordDownloaded = 0x0002, + checkboxHighlighted = 0x0100, + checkboxPressed = 0x0200, + } RecordFlags; + +protected: + SetupRecord(ifc_omservice *serviceToUse); + ~SetupRecord(); + +public: + static SetupRecord *CreateInstance(ifc_omservice *serviceToUse); + +public: + ULONG AddRef(); + ULONG Release(); + + ifc_omservice *GetService() { return service; } + + BOOL IsModified(); + BOOL IsSelected(); + void SetSelected(BOOL fSelected); + + HRESULT GetServiceName(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT GetDisplayName(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT Save(SetupLog *log); + HRESULT DownloadDetails(); + + /* SetupListboxItem */ + BOOL MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy); + BOOL DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state); + INT_PTR KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey); + BOOL MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL MouseLeave(SetupListbox *instance, const RECT *prcItem); + BOOL LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + BOOL RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt); + void CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured); + BOOL IsDisabled() { return FALSE; } + void Command(SetupListbox *instance, INT commandId, INT eventId) {} + HWND CreateDetailsView(HWND hParent); + BOOL GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + + +protected: + BOOL AdjustCheckboxRect(SetupListbox *instance, RECT *prcItem); + void GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut); + void InvertCheckbox(SetupListbox *instance, const RECT *prcItem); + void OnDownloadCompleted(); + +private: + friend static void CALLBACK SetupRecord_ServiceDownloadedCallback(ifc_omstorageasync *result); + +protected: + ULONG ref; + ifc_omservice *service; + ifc_omstorageasync *async; + CRITICAL_SECTION lock; + UINT flags; +}; + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUPRECORD_HEADER
\ No newline at end of file diff --git a/Src/Plugins/Library/ml_online/Setup/setupServicePanel.cpp b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.cpp new file mode 100644 index 00000000..eb7c2737 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.cpp @@ -0,0 +1,797 @@ +#include "../common.h" +#include "./setupServicePanel.h" +#include "./setupDetails.h" +#include "./setupPage.h" +#include "../resource.h" +#include "../api__ml_online.h" + +#include <ifc_omservice.h> +#include <ifc_omservicedetails.h> +#include <ifc_omcachemanager.h> +#include <ifc_omcachegroup.h> +#include <ifc_omcacherecord.h> +#include <ifc_imageloader.h> +#include <ifc_omgraphics.h> +#include <ifc_omserviceeventmngr.h> +#include <ifc_omserviceeditor.h> + +#include <shlwapi.h> +#include <strsafe.h> + +#define GetPanel(__hwnd) ((ServicePanel*)GetPropW((__hwnd), MAKEINTATOM(DETAILS_PROP))) + +#define GET_IDETAILS(__service, __details)\ + (NULL != (service) && SUCCEEDED((service)->QueryInterface(IFC_OmServiceDetails, (void**)&(__details)))) + + +ServicePanel::ServicePanel(LPCWSTR pszName, ifc_omservice *service) + : ref(1), name(NULL), service(NULL), hwnd(NULL), fontTitle(NULL), fontMeta(NULL), thumbnailCache(NULL) +{ + name = Plugin_CopyString(pszName); + this->service = service; + if (NULL != service) + service->AddRef(); +} + +ServicePanel::~ServicePanel() +{ + Plugin_FreeString(name); + + if (NULL != service) + service->Release(); + + if (NULL != fontTitle) + DeleteObject(fontTitle); + + if (NULL != fontMeta) + DeleteObject(fontMeta); + + if (NULL != thumbnailCache) + thumbnailCache->Release(); +} + +HWND ServicePanel::CreateInstance(HWND hParent, LPCWSTR pszName, ifc_omservice *service, ServicePanel **instance) +{ + ServicePanel *panel = new ServicePanel(pszName, service); + if (NULL == panel) + { + if (NULL != instance) *instance = NULL; + return NULL; + } + + HWND hwnd = WASABI_API_CREATEDIALOGPARAMW(IDD_SETUP_SERVICEDETAILS, hParent, ServicePanel_DialogProc, (LPARAM)panel); + + if (NULL != instance) + { + if (NULL != hwnd) + { + *instance = panel; + panel->AddRef(); + } + else + *instance = NULL; + } + + panel->Release(); + return hwnd; +} + +size_t ServicePanel::AddRef() +{ + return InterlockedIncrement((LONG*)&ref); +} + +size_t ServicePanel::Release() +{ + if (0 == ref) + return ref; + + LONG r = InterlockedDecrement((LONG*)&ref); + if (0 == r) + delete(this); + + return r; +} + +int ServicePanel::QueryInterface(GUID interface_guid, void **object) +{ + if (NULL == object) return E_POINTER; + + if (IsEqualIID(interface_guid, IFC_OmServiceEvent)) + *object = static_cast<ifc_omserviceevent*>(this); + else + { + *object = NULL; + return E_NOINTERFACE; + } + + if (NULL == *object) + return E_UNEXPECTED; + + AddRef(); + return S_OK; +} + +static void CALLBACK ThreadCallback_ServiceChange(Dispatchable *instance, ULONG_PTR param1, ULONG_PTR param2) +{ + ifc_omserviceevent *panel = (ifc_omserviceevent*)instance; + ifc_omservice *service = (ifc_omservice*)param1; + if (NULL != service) + { + if (NULL != panel) + panel->ServiceChange(service, (UINT)param2); + service->Release(); + } +} +void ServicePanel::ServiceChange(ifc_omservice *service, unsigned int modifiedFlags) +{ + + DWORD currentTID = GetCurrentThreadId(); + DWORD windowTID = GetWindowThreadProcessId(hwnd, NULL); + if (NULL != windowTID && currentTID != windowTID) + { + if(NULL != OMUTILITY) + { + service->AddRef(); + if (FAILED(OMUTILITY->PostMainThreadCallback2(ThreadCallback_ServiceChange, (ifc_omserviceevent*)this, (ULONG_PTR)service, (ULONG_PTR)modifiedFlags))) + service->Release(); + } + return; + } + + + if ( 0 != (ifc_omserviceeditor::modifiedName & modifiedFlags)) + { + UpdateName(); + HWND hPage = GetParent(hwnd); + if (NULL != hPage) + PostMessage(hPage, SPM_UPDATELIST, (WPARAM)service->GetId(), NULL); + } + + if ( 0 != (ifc_omserviceeditor::modifiedDescription & modifiedFlags)) + UpdateDescription(); + + if ( 0 != (ifc_omserviceeditor::modifiedThumbnail& modifiedFlags)) + UpdateThumbnail(); + + if ( 0 != ((ifc_omserviceeditor::modifiedAuthorFirst | + ifc_omserviceeditor::modifiedAuthorLast | + ifc_omserviceeditor::modifiedUpdated | + ifc_omserviceeditor::modifiedPublished) & modifiedFlags)) + { + UpdateMeta(); + } + +} + +HRESULT ServicePanel::LoadLocalThumbnail(LPCWSTR pszPath) +{ + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL == hThumbnail) return E_UNEXPECTED; + + SendMessage(hThumbnail, WM_SETREDRAW, FALSE, 0L); + + HBITMAP hBitmap = NULL; + + BITMAPINFOHEADER header; + void *pixelData; + + ifc_omimageloader *imageLoader; + if (SUCCEEDED(OMUTILITY->QueryImageLoader(NULL, pszPath, FALSE, &imageLoader))) + { + imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData); + imageLoader->Release(); + } + + if (NULL == hBitmap && + SUCCEEDED(OMUTILITY->QueryImageLoader(WASABI_API_ORIG_HINST, MAKEINTRESOURCE(IDR_SERVICE64X64_IMAGE), FALSE, &imageLoader))) + { + imageLoader->LoadBitmapEx(&hBitmap, &header, &pixelData); + imageLoader->Release(); + } + + HBITMAP hTest = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); + if (NULL != hTest) + DeleteObject(hTest); + + if (NULL != hBitmap) + { + hTest = (HBITMAP)SendMessage(hThumbnail, STM_GETIMAGE, IMAGE_BITMAP, 0L); + if (hTest != hBitmap) + { // this is XP and up image copy was created and alpha channel will be handled properly + DeleteObject(hBitmap); + } + else + { // fix alpha channel + if (32 == header.biBitCount) + { + HDC hdcFixed = CreateCompatibleDC(NULL); + if (NULL != hdcFixed) + { + BITMAPINFOHEADER headerFixed; + CopyMemory(&headerFixed, &header, sizeof(BITMAPINFOHEADER)); + BYTE *pixelsFixed; + INT cx = header.biWidth; + INT cy = abs(header.biHeight); + HBITMAP bitmapFixed = CreateDIBSection(NULL, (LPBITMAPINFO)&headerFixed, DIB_RGB_COLORS, (void**)&pixelsFixed, NULL, 0); + + if (NULL != bitmapFixed) + { + HBITMAP bitmapOrig = (HBITMAP)SelectObject(hdcFixed, bitmapFixed); + HBRUSH hb = (HBRUSH)SendMessage(hwnd, WM_CTLCOLORDLG, (WPARAM)hdcFixed, (LPARAM)hwnd); + if (NULL == hb) + hb = GetSysColorBrush(COLOR_3DFACE); + RECT rect; + SetRect(&rect, 0, 0, cx, cy); + FillRect(hdcFixed, &rect, hb); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + HDC hdcSrc = CreateCompatibleDC(NULL); + if (NULL != hdcSrc) + { + HBITMAP bitmapSrcOrig = (HBITMAP)SelectObject(hdcSrc, hBitmap); + BLENDFUNCTION bf; + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 0xFF; + bf.AlphaFormat = AC_SRC_ALPHA; + + RECT blendRect; + SetRect(&blendRect, 0, 0, cx, cy); + + graphics->Premultiply((BYTE*)pixelData, cx, cy); + graphics->AlphaBlend(hdcFixed, &blendRect, hdcSrc, &blendRect, bf); + + SelectObject(hdcSrc, bitmapSrcOrig); + DeleteDC(hdcSrc); + } + graphics->Release(); + } + + SelectObject(hdcFixed, bitmapOrig); + SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bitmapFixed); + DeleteObject(hBitmap); + + } + DeleteDC(hdcFixed); + } + } + } + } + + RECT clientRect; + if (GetClientRect(hThumbnail, &clientRect)) + { + INT cx = clientRect.right - clientRect.left; + INT cy = clientRect.bottom - clientRect.top; + if (64 != cx || 64 != cy) + { + SetWindowPos(hThumbnail, NULL, 0, 0, 64, 64, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + SendMessage(hThumbnail, WM_SETREDRAW, TRUE, 0L); + + if (0 != ShowWindow(hThumbnail, (NULL != hBitmap) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hThumbnail, NULL, TRUE); + + return S_OK; +} + +static void CALLBACK ThreadCallback_PathChanged(Dispatchable *instance, ULONG_PTR param1, ULONG_PTR param2) +{ + ifc_omcachecallback *panel = (ifc_omcachecallback*)instance; + ifc_omcacherecord *record = (ifc_omcacherecord*)param1; + if (NULL != record) + { + if (NULL != panel) + panel->PathChanged(record); + record->Release(); + } +} + +void ServicePanel::PathChanged(ifc_omcacherecord *record) +{ + if (NULL == hwnd || FALSE == IsWindow(hwnd)) + return; + + DWORD currentTID = GetCurrentThreadId(); + DWORD windowTID = GetWindowThreadProcessId(hwnd, NULL); + if (NULL != windowTID && currentTID != windowTID) + { + if(NULL != OMUTILITY) + { + record->AddRef(); + if (FAILED(OMUTILITY->PostMainThreadCallback2(ThreadCallback_PathChanged, (ifc_omcachecallback*)this, (ULONG_PTR)record, 0L))) + record->Release(); + } + return; + } + + WCHAR szPath[2048] = {0}; + if (FAILED(record->GetPath(szPath, ARRAYSIZE(szPath)))) + szPath[0] = L'\0'; + + LoadLocalThumbnail(szPath); +} + +void ServicePanel::Attach(HWND hwnd) +{ + this->hwnd = hwnd; + if (NULL != hwnd && + FALSE != SetProp(hwnd, MAKEINTATOM(DETAILS_PROP), this)) + { + AddRef(); + } +} + +void ServicePanel::Detach() +{ + RemoveProp(hwnd, MAKEINTATOM(DETAILS_PROP)); + + if (NULL != thumbnailCache) + { + thumbnailCache->UnregisterCallback(this); + thumbnailCache->Release(); + thumbnailCache = NULL; + } + + if (NULL != service) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager))) + { + eventManager->UnregisterHandler(this); + eventManager->Release(); + } + } + + Release(); +} + +HFONT ServicePanel::PickTitleFont(LPCWSTR pszTitle, INT cchTitle, INT maxWidth) +{ + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + + LOGFONT lf; + if (0 == GetObject(dialogFont, sizeof(LOGFONT), &lf)) + return NULL; + + HFONT titleFont = NULL; + if (cchTitle > 0) + { + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Arial Bold"); + lf.lfWidth = 0; + lf.lfWeight = FW_DONTCARE; + lf.lfQuality = 5/*ANTIALIASED_QUALITY*/; + + HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS); + if (NULL != hdc) + { + HFONT origFont = (HFONT)GetCurrentObject(hdc, OBJ_FONT); + SIZE textSize; + + INT heightLimit = (lf.lfHeight < 0) ? 1 : -1; + lf.lfHeight += (lf.lfHeight < 0) ? -2 : +2; + do + { + textSize.cx = 0; + if (NULL != titleFont) DeleteObject(titleFont); + titleFont = CreateFontIndirect(&lf); + if (NULL != titleFont) + { + SelectObject(hdc, titleFont); + GetTextExtentPoint32(hdc, pszTitle, cchTitle, &textSize); + } + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + + } while(textSize.cx > maxWidth && lf.lfHeight != heightLimit); + + if (0 == textSize.cx) + { + DeleteObject(titleFont); + titleFont = NULL; + } + + SelectObject(hdc, origFont); + ReleaseDC(hwnd, hdc); + } + } + } + + if (NULL == titleFont && + 0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + titleFont = CreateFontIndirect(&lf); + } + return titleFont; +} + +LPCWSTR ServicePanel::FormatDate(LPCWSTR pszDate, LPWSTR pszBuffer, INT cchBufferMax) +{ + SYSTEMTIME st; + ZeroMemory(&st, sizeof(SYSTEMTIME)); + LPCWSTR cursor; + + cursor = pszDate; + INT index = 0; + + for(;;) + { + + INT iVal; + + if (FALSE == StrToIntEx(cursor, STIF_DEFAULT, &iVal) || iVal < 1) + { + index = 0; + break; + } + + if (0 == index) + { + if (iVal < 2000 || iVal > 2100) + break; + st.wYear = iVal; + index++; + } + else if (1 == index) + { + if (iVal < 1 || iVal > 12) + break; + st.wMonth = iVal; + index++; + } + else if (2 == index) + { + if (iVal < 1 || iVal > 31) + break; + st.wDay = iVal; + index++; + } + else + { + index = 0; + break; + } + + while(L'\0' != *cursor && L'-' != *cursor) cursor++; + if (L'-' == *cursor) cursor++; + if (L'\0' == *cursor) + break; + + } + + if (3 == index && + 0 != GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuffer, cchBufferMax)) + { + return pszBuffer; + } + + return pszDate; +} + + + +HRESULT ServicePanel::GetFullName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) + return E_POINTER; + *pszBuffer = L'\0'; + + if (NULL == service) return E_UNEXPECTED; + + ifc_omservicedetails *details; + HRESULT hr = service->QueryInterface(IFC_OmServiceDetails, (void**)&details); + if (SUCCEEDED(hr)) + { + hr = details->GetAuthorFirst(pszBuffer, cchBufferMax); + if (SUCCEEDED(hr)) + { + UINT cchBuffer = lstrlen(pszBuffer); + LPWSTR cursor = pszBuffer + cchBuffer; + size_t remaining = cchBufferMax - cchBuffer; + + if (cursor != pszBuffer) + { + hr = StringCchCopyEx(cursor, remaining, L" ", &cursor, &remaining, 0); + if (SUCCEEDED(hr)) + { + hr = details->GetAuthorLast(cursor, (UINT)remaining); + if (FAILED(hr) || L'\0' == *cursor) + { + pszBuffer[cchBuffer] = L'\0'; + } + } + } + } + } + return hr; +} +void ServicePanel::UpdateName() +{ + HWND hTitle = GetDlgItem(hwnd, IDC_TITLE); + if (NULL == hTitle) return; + + WCHAR szBuffer[128] = {0}; + if (NULL == service || + FAILED(service->GetName(szBuffer, ARRAYSIZE(szBuffer)))) + { + szBuffer[0] = L'\0'; + } + + INT cchBuffer = lstrlen(szBuffer); + RECT rc; + GetClientRect(hTitle, &rc); + HFONT font = PickTitleFont(szBuffer, cchBuffer, rc.right - rc.left); + if (NULL != font) + { + if (NULL != fontTitle) + DeleteObject(fontTitle); + + fontTitle = font; + SendMessage(hTitle, WM_SETFONT, (WPARAM)fontTitle, 0L); + } + + + SetWindowText(hTitle, szBuffer); + InvalidateRect(hTitle, NULL, TRUE); +} + + +void ServicePanel::UpdateDescription() +{ + HWND hDescription = GetDlgItem(hwnd, IDC_DESCRIPTION); + if (NULL == hDescription) return; + + WCHAR szBuffer[4096] = {0}; + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + details->GetDescription(szBuffer, ARRAYSIZE(szBuffer)); + details->Release(); + } + + SetupDetails_SetDescription(hDescription, szBuffer); +} + +void ServicePanel::UpdateMeta() +{ + HWND hMeta = GetDlgItem(hwnd, IDC_SERVICEMETA); + if (NULL == hMeta) return; + + WCHAR szBuffer[512] = {0}; + ifc_omservicedetails *svcdetails = 0; + if (GET_IDETAILS(service, svcdetails)) + { + WCHAR szValue[256] = {0}, szPrefix[64] = {0}; + HRESULT hr = S_OK; + LPWSTR cursor = szBuffer; + size_t remaining = ARRAYSIZE(szBuffer); + + if (SUCCEEDED(GetFullName(szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_BYAUTHOR, szPrefix, ARRAYSIZE(szPrefix)); + hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, szValue); + } + + if (SUCCEEDED(svcdetails->GetUpdated(szValue, ARRAYSIZE(szValue))) && L'\0' != szValue[0]) + { + if (cursor != szBuffer) + hr = StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE); + + if (SUCCEEDED(hr)) + { + WCHAR szDate[128] = {0}; + WASABI_API_LNGSTRINGW_BUF(IDS_SERVICE_LASTUPDATED, szPrefix, ARRAYSIZE(szPrefix)); + StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, + L"%s%s", szPrefix, FormatDate(szValue, szDate, ARRAYSIZE(szDate))); + } + } + + svcdetails->Release(); + } + + if (NULL == fontMeta) + { + HFONT dialogFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L); + LOGFONT lf; + if (0 != GetObject(dialogFont, sizeof(LOGFONT), &lf)) + { + StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Tahoma"); + lf.lfWidth = 0; + lf.lfHeight += (lf.lfHeight < 0) ? 1 : -1; + lf.lfQuality = ANTIALIASED_QUALITY; + fontMeta = CreateFontIndirect(&lf); + } + + if (NULL != fontMeta) + { + SendMessage(hMeta, WM_SETFONT, (WPARAM)fontMeta, 0L); + } + } + + SetWindowText(hMeta, szBuffer); + if (0 != ShowWindow(hMeta, (L'\0' != szBuffer[0]) ? SW_SHOWNA : SW_HIDE)) + InvalidateRect(hMeta, NULL, TRUE); +} + +void ServicePanel::UpdateThumbnail() +{ + if (NULL != thumbnailCache) + { + thumbnailCache->UnregisterCallback(this); + thumbnailCache->Release(); + thumbnailCache = NULL; + } + LoadLocalThumbnail(NULL); + + ifc_omservicedetails *details = 0; + if (GET_IDETAILS(service, details)) + { + WCHAR szPath[2048] = {0}; + if (SUCCEEDED(details->GetThumbnail(szPath, ARRAYSIZE(szPath))) && L'\0' != szPath[0]) + { + ifc_omcachemanager *cacheManager; + if (SUCCEEDED(OMUTILITY->GetCacheManager(&cacheManager))) + { + ifc_omcachegroup *cacheGroup; + if (SUCCEEDED(cacheManager->Find(L"thumbnails", TRUE, &cacheGroup, NULL))) + { + + if (SUCCEEDED(cacheGroup->Find(szPath, TRUE, &thumbnailCache, FALSE))) + { + thumbnailCache->RegisterCallback(this); + if (SUCCEEDED(thumbnailCache->GetPath(szPath, ARRAYSIZE(szPath)))) + LoadLocalThumbnail(szPath); + } + cacheGroup->Release(); + } + cacheManager->Release(); + } + } + details->Release(); + } +} + + + + +INT_PTR ServicePanel::OnInitDialog(HWND hFocus, LPARAM lParam) +{ + UpdateName(); + UpdateDescription(); + UpdateThumbnail(); + UpdateMeta(); + + if (NULL != service) + { + ifc_omserviceeventmngr *eventManager; + if (SUCCEEDED(service->QueryInterface(IFC_OmServiceEventMngr, (void**)&eventManager))) + { + eventManager->RegisterHandler(this); + eventManager->Release(); + } + } + + return FALSE; +} + +void ServicePanel::OnDestroy() +{ + + HWND hThumbnail = GetDlgItem(hwnd, IDC_THUMBNAIL); + if (NULL != hThumbnail) + { + HBITMAP hBitmap = (HBITMAP)SendMessage(hThumbnail, STM_SETIMAGE, IMAGE_BITMAP, 0L); + if (NULL != hBitmap) + DeleteObject(hBitmap); + } + + Detach(); +} + + +INT_PTR ServicePanel::OnDialogColor(HDC hdc, HWND hControl) +{ + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + return (INT_PTR)SendMessage(hParent, WM_CTLCOLORDLG, (WPARAM)hdc, (LPARAM)hControl); + + return 0; +} + + +INT_PTR ServicePanel::OnStaticColor(HDC hdc, HWND hControl) +{ + INT_PTR result = 0; + HWND hParent = GetAncestor(hwnd, GA_PARENT); + if (NULL != hParent && hParent != hwnd) + result = (INT_PTR)SendMessage(hParent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hControl); + + INT controlId = GetDlgCtrlID(hControl); + switch(controlId) + { + case IDC_SERVICEMETA: + { + COLORREF rgbBk = GetBkColor(hdc); + COLORREF rgbFg = GetTextColor(hdc); + + ifc_omgraphics *graphics; + if (SUCCEEDED(OMUTILITY->GetGraphics(&graphics))) + { + graphics->BlendColor(rgbFg, rgbBk, 180, &rgbFg); + graphics->Release(); + } + + SetTextColor(hdc, rgbFg); + } + break; + } + return result; +} + + +INT_PTR ServicePanel::OnGetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax) +{ + if (NULL == pszBuffer) return FALSE; + return SUCCEEDED(StringCchCopy(pszBuffer, cchBufferMax, (NULL != name) ? name : L"")); +} + +INT_PTR ServicePanel::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: return OnInitDialog((HWND)wParam, lParam); + case WM_DESTROY: OnDestroy(); break; + case WM_CTLCOLORDLG: return OnDialogColor((HDC)wParam, (HWND)lParam); + case WM_CTLCOLORSTATIC: return OnStaticColor((HDC)wParam, (HWND)lParam); + + case NSDM_GETUNIQUENAME: MSGRESULT(hwnd, OnGetUniqueName((LPWSTR)lParam, (UINT)wParam)); + } + return 0; +} + +static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + ServicePanel *panel = GetPanel(hwnd); + if (NULL == panel) + { + if (WM_INITDIALOG == uMsg) + { + panel = (ServicePanel*)lParam; + if (NULL != panel) + panel->Attach(hwnd); + } + + if (NULL == panel) return 0; + } + + return panel->DialogProc(uMsg, wParam, lParam); +} + + + +#define CBCLASS ServicePanel +START_MULTIPATCH; + START_PATCH(MPIID_SERVICEEVENT) + M_CB(MPIID_SERVICEEVENT, ifc_omserviceevent, ADDREF, AddRef); + M_CB(MPIID_SERVICEEVENT, ifc_omserviceevent, RELEASE, Release); + M_CB(MPIID_SERVICEEVENT, ifc_omserviceevent, QUERYINTERFACE, QueryInterface); + M_VCB(MPIID_SERVICEEVENT, ifc_omserviceevent, API_SERVICECHANGE, ServiceChange); + + + NEXT_PATCH(MPIID_CACHECALLBACK) + M_CB(MPIID_CACHECALLBACK, ifc_omcachecallback, ADDREF, AddRef); + M_CB(MPIID_CACHECALLBACK, ifc_omcachecallback, RELEASE, Release); + M_CB(MPIID_CACHECALLBACK, ifc_omcachecallback, QUERYINTERFACE, QueryInterface); + M_VCB(MPIID_CACHECALLBACK, ifc_omcachecallback, API_PATHCHANGED, PathChanged); + + END_PATCH +END_MULTIPATCH; +#undef CBCLASS diff --git a/Src/Plugins/Library/ml_online/Setup/setupServicePanel.h b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.h new file mode 100644 index 00000000..f60adac1 --- /dev/null +++ b/Src/Plugins/Library/ml_online/Setup/setupServicePanel.h @@ -0,0 +1,79 @@ +#ifndef NULLOSFT_ONLINEMEDIA_PLUGIN_SETUP_SERVICE_PANEL_HEADER +#define NULLOSFT_ONLINEMEDIA_PLUGIN_SETUP_SERVICE_PANEL_HEADER + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +#include <wtypes.h> +#include <bfc/multipatch.h> +#include <ifc_omserviceevent.h> +#include <ifc_omcachecallback.h> + +class ifc_omservice; + +#define MPIID_SERVICEEVENT 10 +#define MPIID_CACHECALLBACK 20 + + +class ServicePanel : public MultiPatch<MPIID_SERVICEEVENT, ifc_omserviceevent>, + public MultiPatch<MPIID_CACHECALLBACK, ifc_omcachecallback> +{ +protected: + ServicePanel(LPCWSTR pszName, ifc_omservice *service); + ~ServicePanel(); + +public: + static HWND CreateInstance(HWND hParent, LPCWSTR pszName, ifc_omservice *service, ServicePanel **instance); + +public: + /* Dispatchable */ + size_t AddRef(); + size_t Release(); + int QueryInterface(GUID interface_guid, void **object); + + /* ifc_omserviceevent */ + void ServiceChange(ifc_omservice *service, unsigned int modifiedFlags); + + /* ifc_omcachecallback */ + void PathChanged(ifc_omcacherecord *record); + +protected: + void Attach(HWND hwnd); + void Detach(); + + void UpdateName(); + void UpdateDescription(); + void UpdateMeta(); + void UpdateThumbnail(); + + HFONT PickTitleFont(LPCWSTR pszTitle, INT cchTitle, INT maxWidth); + LPCWSTR FormatDate(LPCWSTR pszDate, LPWSTR pszBuffer, INT cchBufferMax); + HRESULT GetFullName(LPWSTR pszBuffer, UINT cchBufferMax); + + INT_PTR OnInitDialog(HWND hFocus, LPARAM lParam); + void OnDestroy(); + INT_PTR OnDialogColor(HDC hdc, HWND hControl); + INT_PTR OnStaticColor(HDC hdc, HWND hControl); + INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + INT_PTR OnGetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax); + HRESULT LoadLocalThumbnail(LPCWSTR pszPath); + +private: + friend static INT_PTR WINAPI ServicePanel_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +protected: + size_t ref; + HWND hwnd; + LPWSTR name; + ifc_omservice *service; + ifc_omcacherecord *thumbnailCache; + HFONT fontTitle; + HFONT fontMeta; + +private: + RECVS_MULTIPATCH; +}; + + +#endif //NULLOSFT_ONLINEMEDIA_PLUGIN_SETUP_SERVICE_PANEL_HEADER
\ No newline at end of file |