2020-07-24 08:07:43 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Applications Manager
|
|
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
|
|
* PURPOSE: Application view class and other classes used by it
|
2023-02-20 18:30:02 +00:00
|
|
|
* COPYRIGHT: Copyright 2020 He Yang (1160386205@qq.com)
|
|
|
|
* Copyright 2022,2023 Mark Jansen <mark.jansen@reactos.org>
|
2020-07-24 08:07:43 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "rapps.h"
|
|
|
|
#include "appview.h"
|
|
|
|
#include "gui.h"
|
2020-07-29 10:50:57 +00:00
|
|
|
#include <windowsx.h>
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
using namespace Gdiplus;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
HICON g_hDefaultPackageIcon = NULL;
|
|
|
|
static int g_DefaultPackageIconILIdx = I_IMAGENONE;
|
|
|
|
|
2024-03-22 17:20:35 +00:00
|
|
|
// **** Menu helpers ****
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
DeleteMenuEx(
|
|
|
|
_In_ HMENU hMenu,
|
|
|
|
_In_ UINT uPosition,
|
|
|
|
_In_ UINT uFlags)
|
|
|
|
{
|
|
|
|
INT pos;
|
|
|
|
MENUITEMINFOW mii = { sizeof(mii), MIIM_FTYPE, 0 };
|
|
|
|
bool bIsValidItem1, bIsValidItem2;
|
|
|
|
bool bIsSep1, bIsSep2;
|
|
|
|
|
|
|
|
if (uFlags & MF_BYPOSITION)
|
|
|
|
pos = (INT)uPosition;
|
|
|
|
else
|
|
|
|
pos = ::GetMenuPosFromID(hMenu, uPosition);
|
|
|
|
if (pos < 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
bIsValidItem1 = ((pos > 0) && ::GetMenuItemInfoW(hMenu, pos - 1, TRUE, &mii));
|
|
|
|
bIsSep1 = bIsValidItem1 && !!(mii.fType & MFT_SEPARATOR);
|
|
|
|
|
|
|
|
bIsValidItem2 = ::GetMenuItemInfoW(hMenu, pos + 1, TRUE, &mii);
|
|
|
|
bIsSep2 = bIsValidItem2 && !!(mii.fType & MFT_SEPARATOR);
|
|
|
|
|
|
|
|
if (bIsSep1 && !bIsSep2 && !bIsValidItem2)
|
|
|
|
pos = pos - 1; // Delete separator only if pos+1 has no item
|
|
|
|
else if (!bIsSep1 && bIsSep2 && !bIsValidItem1)
|
|
|
|
pos = pos + 1; // Delete separator only if pos-1 has no item
|
|
|
|
else if (bIsSep1 && bIsSep2)
|
|
|
|
pos = pos + 1;
|
|
|
|
else
|
|
|
|
pos = -1;
|
|
|
|
|
|
|
|
// Delete one of the separators if necessary
|
|
|
|
if (pos != -1)
|
|
|
|
::DeleteMenu(hMenu, pos, MF_BYPOSITION);
|
|
|
|
|
|
|
|
// Finally, delete the menu item itself.
|
|
|
|
return ::DeleteMenu(hMenu, uPosition, uFlags);
|
|
|
|
}
|
|
|
|
// **** Menu helpers ****
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
// **** CMainToolbar ****
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CMainToolbar::AddImageToImageList(HIMAGELIST hImageList, UINT ImageIndex)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
HICON hImage;
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
if (!(hImage =
|
|
|
|
(HICON)LoadImageW(hInst, MAKEINTRESOURCE(ImageIndex), IMAGE_ICON, m_iToolbarHeight, m_iToolbarHeight, 0)))
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
return;
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ImageList_AddIcon(hImageList, hImage);
|
|
|
|
DeleteObject(hImage);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HIMAGELIST
|
|
|
|
CMainToolbar::InitImageList()
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
HIMAGELIST hImageList;
|
|
|
|
|
|
|
|
/* Create the toolbar icon image list */
|
2023-02-20 18:30:02 +00:00
|
|
|
hImageList = ImageList_Create(m_iToolbarHeight, m_iToolbarHeight, ILC_MASK | GetSystemColorDepth(), 1, 1);
|
2020-07-29 10:50:57 +00:00
|
|
|
if (!hImageList)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
AddImageToImageList(hImageList, IDI_INSTALL);
|
|
|
|
AddImageToImageList(hImageList, IDI_UNINSTALL);
|
|
|
|
AddImageToImageList(hImageList, IDI_MODIFY);
|
|
|
|
AddImageToImageList(hImageList, IDI_CHECK_ALL);
|
|
|
|
AddImageToImageList(hImageList, IDI_REFRESH);
|
|
|
|
AddImageToImageList(hImageList, IDI_UPDATE_DB);
|
|
|
|
AddImageToImageList(hImageList, IDI_SETTINGS);
|
|
|
|
AddImageToImageList(hImageList, IDI_EXIT);
|
|
|
|
|
|
|
|
return hImageList;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
CMainToolbar::CMainToolbar() : m_iToolbarHeight(24), m_dButtonsWidthMax(0)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CMainToolbar::OnGetDispInfo(LPTOOLTIPTEXT lpttt)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
UINT idButton = (UINT)lpttt->hdr.idFrom;
|
|
|
|
|
|
|
|
switch (idButton)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_EXIT:
|
|
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_EXIT);
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_INSTALL:
|
|
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_INSTALL);
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_UNINSTALL:
|
|
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_MODIFY:
|
|
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_MODIFY);
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_SETTINGS:
|
|
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SETTINGS);
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_REFRESH:
|
|
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_REFRESH);
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_RESETDB:
|
|
|
|
lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE_DB);
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HWND
|
|
|
|
CMainToolbar::Create(HWND hwndParent)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-07-07 23:02:10 +00:00
|
|
|
CStringW szInstallBtn;
|
|
|
|
CStringW szUninstallBtn;
|
|
|
|
CStringW szModifyBtn;
|
|
|
|
CStringW szSelectAllBtn;
|
|
|
|
CStringW szRefreshBtn;
|
|
|
|
CStringW szUpdateDbBtn;
|
|
|
|
|
|
|
|
/* Load tooltip strings */
|
|
|
|
szInstallBtn.LoadStringW(IDS_TOOLTIP_INSTALL);
|
|
|
|
szUninstallBtn.LoadStringW(IDS_TOOLTIP_UNINSTALL);
|
|
|
|
szModifyBtn.LoadStringW(IDS_TOOLTIP_MODIFY);
|
|
|
|
szSelectAllBtn.LoadStringW(IDS_TOOLTIP_SELECT_ALL);
|
|
|
|
szRefreshBtn.LoadStringW(IDS_TOOLTIP_REFRESH);
|
|
|
|
szUpdateDbBtn.LoadStringW(IDS_TOOLTIP_UPDATE_DB);
|
|
|
|
|
2020-07-29 10:50:57 +00:00
|
|
|
/* Create buttons */
|
2023-02-20 18:30:02 +00:00
|
|
|
TBBUTTON Buttons[] = {
|
|
|
|
/* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
|
2023-07-07 23:02:10 +00:00
|
|
|
{0, ID_INSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)szInstallBtn.GetString()},
|
|
|
|
{1, ID_UNINSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)szUninstallBtn.GetString()},
|
|
|
|
{2, ID_MODIFY, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)szModifyBtn.GetString()},
|
|
|
|
{3, ID_CHECK_ALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)szSelectAllBtn.GetString()},
|
2023-02-20 18:30:02 +00:00
|
|
|
{-1, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
|
2023-07-07 23:02:10 +00:00
|
|
|
{4, ID_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)szRefreshBtn.GetString()},
|
|
|
|
{5, ID_RESETDB, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)szUpdateDbBtn.GetString()}};
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
m_hWnd = CreateWindowExW(
|
|
|
|
0, TOOLBARCLASSNAMEW, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_LIST, 0, 0, 0, 0,
|
|
|
|
hwndParent, 0, hInst, NULL);
|
2020-07-29 10:50:57 +00:00
|
|
|
|
|
|
|
if (!m_hWnd)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
SendMessageW(TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
|
|
|
|
SetButtonStructSize();
|
|
|
|
|
|
|
|
/* Set image list */
|
|
|
|
HIMAGELIST hImageList = InitImageList();
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
if (hImageList)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
ImageList_Destroy(SetImageList(hImageList));
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AddButtons(_countof(Buttons), Buttons);
|
|
|
|
|
2024-03-22 20:55:43 +00:00
|
|
|
/* Remember the ideal width to use as a max width of buttons */
|
|
|
|
UpdateMaxButtonsWidth();
|
2020-07-29 10:50:57 +00:00
|
|
|
|
|
|
|
return m_hWnd;
|
|
|
|
}
|
|
|
|
|
2024-03-22 20:58:35 +00:00
|
|
|
void
|
|
|
|
CMainToolbar::ShowButtonCaption(bool bShow)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
DWORD dCurrentExStyle = (DWORD)SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
|
2024-03-22 20:58:35 +00:00
|
|
|
if (bShow)
|
|
|
|
SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle & ~TBSTYLE_EX_MIXEDBUTTONS);
|
|
|
|
else
|
|
|
|
SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle | TBSTYLE_EX_MIXEDBUTTONS);
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
|
2024-03-22 20:55:43 +00:00
|
|
|
void
|
|
|
|
CMainToolbar::UpdateMaxButtonsWidth()
|
|
|
|
{
|
|
|
|
SIZE size;
|
|
|
|
GetIdealSize(FALSE, &size);
|
|
|
|
m_dButtonsWidthMax = size.cx;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
DWORD
|
|
|
|
CMainToolbar::GetMaxButtonsWidth() const
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
return m_dButtonsWidthMax;
|
|
|
|
}
|
|
|
|
// **** CMainToolbar ****
|
|
|
|
|
|
|
|
// **** CSearchBar ****
|
|
|
|
|
|
|
|
CSearchBar::CSearchBar() : m_Width(180), m_Height(22)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CSearchBar::SetText(LPCWSTR lpszText)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM)lpszText);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HWND
|
|
|
|
CSearchBar::Create(HWND hwndParent)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szBuf;
|
|
|
|
m_hWnd = CreateWindowExW(
|
|
|
|
WS_EX_CLIENTEDGE, L"Edit", NULL, WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL, 0, 0, m_Width, m_Height,
|
|
|
|
hwndParent, (HMENU)NULL, hInst, 0);
|
2020-07-29 10:50:57 +00:00
|
|
|
|
|
|
|
SendMessageW(WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
|
|
|
|
szBuf.LoadStringW(IDS_SEARCH_TEXT);
|
|
|
|
SetWindowTextW(szBuf);
|
|
|
|
return m_hWnd;
|
|
|
|
}
|
|
|
|
// **** CSearchBar ****
|
|
|
|
|
|
|
|
// **** CComboBox ****
|
|
|
|
|
|
|
|
CComboBox::CComboBox() : m_Width(80), m_Height(22)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HWND
|
|
|
|
CComboBox::Create(HWND hwndParent)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
m_hWnd = CreateWindowW(
|
|
|
|
WC_COMBOBOX, L"", CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 0, 0, m_Width,
|
|
|
|
m_Height, hwndParent, NULL, 0, NULL);
|
2020-07-29 10:50:57 +00:00
|
|
|
|
|
|
|
SendMessageW(WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
|
2021-09-13 01:33:14 +00:00
|
|
|
|
2020-07-29 10:50:57 +00:00
|
|
|
for (int i = 0; i < (int)_countof(m_TypeStringID); i++)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szBuf;
|
2020-07-29 10:50:57 +00:00
|
|
|
szBuf.LoadStringW(m_TypeStringID[i]);
|
|
|
|
SendMessageW(CB_ADDSTRING, 0, (LPARAM)(LPCWSTR)szBuf);
|
|
|
|
}
|
2021-09-13 01:33:14 +00:00
|
|
|
|
2020-07-29 10:50:57 +00:00
|
|
|
SendMessageW(CB_SETCURSEL, m_DefaultSelectType, 0); // select the first item
|
|
|
|
|
|
|
|
return m_hWnd;
|
|
|
|
}
|
|
|
|
// **** CComboBox ****
|
|
|
|
|
2020-07-24 08:07:43 +00:00
|
|
|
// **** CAppRichEdit ****
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppRichEdit::LoadAndInsertText(UINT uStringID, const CStringW &szText, DWORD TextFlags)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szLoadedText;
|
2020-07-24 08:07:43 +00:00
|
|
|
if (!szText.IsEmpty() && szLoadedText.LoadStringW(uStringID))
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
const DWORD StringFlags = CFE_BOLD;
|
2020-07-24 08:07:43 +00:00
|
|
|
InsertText(szLoadedText, StringFlags);
|
|
|
|
InsertText(szText, TextFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppRichEdit::LoadAndInsertText(UINT uStringID, DWORD StringFlags)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szLoadedText;
|
2020-07-24 08:07:43 +00:00
|
|
|
if (szLoadedText.LoadStringW(uStringID))
|
|
|
|
{
|
|
|
|
InsertText(L"\n", 0);
|
|
|
|
InsertText(szLoadedText, StringFlags);
|
|
|
|
InsertText(L"\n", 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppRichEdit::InsertTextWithString(UINT StringID, const CStringW &Text, DWORD TextFlags)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
if (!Text.IsEmpty())
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
LoadAndInsertText(StringID, Text, TextFlags);
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// **** CAppRichEdit ****
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
int
|
|
|
|
ScrnshotDownloadCallback(pASYNCINET AsyncInet, ASYNC_EVENT Event, WPARAM wParam, LPARAM lParam, VOID *Extension)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
ScrnshotDownloadParam *DownloadParam = (ScrnshotDownloadParam *)Extension;
|
|
|
|
switch (Event)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case ASYNCINET_DATA:
|
|
|
|
DWORD BytesWritten;
|
|
|
|
WriteFile(DownloadParam->hFile, (LPCVOID)wParam, (DWORD)lParam, &BytesWritten, NULL);
|
|
|
|
break;
|
|
|
|
case ASYNCINET_COMPLETE:
|
|
|
|
CloseHandle(DownloadParam->hFile);
|
|
|
|
SendMessage(
|
|
|
|
DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, (WPARAM)ERROR_SUCCESS, (LPARAM)DownloadParam);
|
|
|
|
break;
|
|
|
|
case ASYNCINET_CANCELLED:
|
|
|
|
CloseHandle(DownloadParam->hFile);
|
|
|
|
SendMessage(
|
|
|
|
DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, (WPARAM)ERROR_CANCELLED, (LPARAM)DownloadParam);
|
|
|
|
break;
|
|
|
|
case ASYNCINET_ERROR:
|
|
|
|
CloseHandle(DownloadParam->hFile);
|
|
|
|
SendMessage(DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, wParam, (LPARAM)DownloadParam);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ATLASSERT(FALSE);
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// **** CAppScrnshotPreview ****
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
CAppScrnshotPreview::CAppScrnshotPreview(const CStringW &BasePath) : m_BasePath(BasePath)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
CAppScrnshotPreview::ProcessWindowMessage(
|
|
|
|
HWND hwnd,
|
|
|
|
UINT Msg,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam,
|
|
|
|
LRESULT &theResult,
|
|
|
|
DWORD dwMapId)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
theResult = 0;
|
|
|
|
switch (Msg)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_CREATE:
|
|
|
|
hBrokenImgIcon =
|
|
|
|
(HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_BROKEN_IMAGE), IMAGE_ICON, BrokenImgSize, BrokenImgSize, 0);
|
|
|
|
break;
|
|
|
|
case WM_SIZE:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
if (BrokenImgSize != min(min(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), BROKENIMG_ICON_SIZE))
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
BrokenImgSize = min(min(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), BROKENIMG_ICON_SIZE);
|
|
|
|
|
|
|
|
if (hBrokenImgIcon)
|
|
|
|
{
|
|
|
|
DeleteObject(hBrokenImgIcon);
|
|
|
|
hBrokenImgIcon = (HICON)LoadImage(
|
|
|
|
hInst, MAKEINTRESOURCE(IDI_BROKEN_IMAGE), IMAGE_ICON, BrokenImgSize, BrokenImgSize, 0);
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_RAPPS_DOWNLOAD_COMPLETE:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
ScrnshotDownloadParam *DownloadParam = (ScrnshotDownloadParam *)lParam;
|
|
|
|
AsyncInetRelease(AsyncInet);
|
|
|
|
AsyncInet = NULL;
|
|
|
|
switch (wParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case ERROR_SUCCESS:
|
|
|
|
if (ContentID == DownloadParam->ID)
|
|
|
|
{
|
|
|
|
DisplayFile(DownloadParam->DownloadFileName);
|
|
|
|
// send a message to trigger resizing
|
|
|
|
::SendMessageW(::GetParent(m_hWnd), WM_RAPPS_RESIZE_CHILDREN, 0, 0);
|
|
|
|
InvalidateRect(0, 0);
|
|
|
|
TempImagePath =
|
|
|
|
DownloadParam->DownloadFileName; // record tmp file path in order to delete it when cleanup
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// the picture downloaded is already outdated. delete it.
|
|
|
|
DeleteFileW(DownloadParam->DownloadFileName);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ERROR_CANCELLED:
|
|
|
|
DeleteFileW(DownloadParam->DownloadFileName);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DisplayFailed();
|
|
|
|
// send a message to trigger resizing
|
|
|
|
::SendMessageW(::GetParent(m_hWnd), WM_RAPPS_RESIZE_CHILDREN, 0, 0);
|
|
|
|
InvalidateRect(0, 0);
|
|
|
|
DeleteFileW(DownloadParam->DownloadFileName);
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
delete DownloadParam;
|
2020-07-24 08:07:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_PAINT:
|
|
|
|
{
|
|
|
|
PAINTSTRUCT ps;
|
|
|
|
HDC hdc = BeginPaint(&ps);
|
|
|
|
CRect rect;
|
|
|
|
GetClientRect(&rect);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
PaintOnDC(hdc, rect.Width(), rect.Height(), ps.fErase);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
EndPaint(&ps);
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_PRINTCLIENT:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
if (lParam & PRF_CHECKVISIBLE)
|
|
|
|
{
|
|
|
|
if (!IsWindowVisible())
|
|
|
|
break;
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
CRect rect;
|
|
|
|
GetClientRect(&rect);
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
PaintOnDC((HDC)wParam, rect.Width(), rect.Height(), lParam & PRF_ERASEBKGND);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_ERASEBKGND:
|
|
|
|
{
|
|
|
|
return TRUE; // do not erase to avoid blinking
|
|
|
|
}
|
|
|
|
case WM_TIMER:
|
|
|
|
{
|
|
|
|
switch (wParam)
|
|
|
|
{
|
|
|
|
case TIMER_LOADING_ANIMATION:
|
|
|
|
LoadingAnimationFrame++;
|
|
|
|
LoadingAnimationFrame %= (LOADING_ANIMATION_PERIOD * LOADING_ANIMATION_FPS);
|
|
|
|
HDC hdc = GetDC();
|
|
|
|
CRect rect;
|
|
|
|
GetClientRect(&rect);
|
|
|
|
|
|
|
|
PaintOnDC(hdc, rect.Width(), rect.Height(), TRUE);
|
|
|
|
ReleaseDC(hdc);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
|
|
{
|
|
|
|
PreviousDisplayCleanup();
|
|
|
|
DeleteObject(hBrokenImgIcon);
|
|
|
|
hBrokenImgIcon = NULL;
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppScrnshotPreview::DisplayLoading()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
SetStatus(SCRNSHOT_PREV_LOADING);
|
|
|
|
if (bLoadingTimerOn)
|
|
|
|
{
|
|
|
|
KillTimer(TIMER_LOADING_ANIMATION);
|
|
|
|
}
|
|
|
|
LoadingAnimationFrame = 0;
|
|
|
|
bLoadingTimerOn = TRUE;
|
|
|
|
SetTimer(TIMER_LOADING_ANIMATION, 1000 / LOADING_ANIMATION_FPS, 0);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppScrnshotPreview::DisplayFailed()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
InterlockedIncrement64(&ContentID);
|
|
|
|
SetStatus(SCRNSHOT_PREV_FAILED);
|
|
|
|
PreviousDisplayCleanup();
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CAppScrnshotPreview::DisplayFile(LPCWSTR lpszFileName)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
PreviousDisplayCleanup();
|
|
|
|
SetStatus(SCRNSHOT_PREV_IMAGE);
|
|
|
|
pImage = Bitmap::FromFile(lpszFileName, 0);
|
|
|
|
if (pImage->GetLastStatus() != Ok)
|
|
|
|
{
|
|
|
|
DisplayFailed();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppScrnshotPreview::SetStatus(SCRNSHOT_STATUS Status)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
ScrnshotPrevStauts = Status;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppScrnshotPreview::PaintOnDC(HDC hdc, int width, int height, BOOL bDrawBkgnd)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
// use an off screen dc to avoid blinking
|
|
|
|
HDC hdcMem = CreateCompatibleDC(hdc);
|
|
|
|
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
|
|
|
|
SelectObject(hdcMem, hBitmap);
|
|
|
|
|
|
|
|
if (bDrawBkgnd)
|
|
|
|
{
|
|
|
|
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdcMem, (HGDIOBJ)GetSysColorBrush(COLOR_BTNFACE));
|
|
|
|
PatBlt(hdcMem, 0, 0, width, height, PATCOPY);
|
|
|
|
SelectObject(hdcMem, hOldBrush);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ScrnshotPrevStauts)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case SCRNSHOT_PREV_EMPTY:
|
|
|
|
{
|
|
|
|
}
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case SCRNSHOT_PREV_LOADING:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
Graphics graphics(hdcMem);
|
2023-02-20 18:30:02 +00:00
|
|
|
Color color(255, 0, 0);
|
|
|
|
SolidBrush dotBrush(Color(255, 100, 100, 100));
|
|
|
|
|
|
|
|
graphics.SetSmoothingMode(SmoothingMode::SmoothingModeAntiAlias);
|
|
|
|
|
|
|
|
// Paint three dot
|
|
|
|
float DotWidth = GetLoadingDotWidth(width, height);
|
|
|
|
graphics.FillEllipse(
|
|
|
|
(Brush *)(&dotBrush), (REAL)width / 2.0 - min(width, height) * 2.0 / 16.0 - DotWidth / 2.0,
|
|
|
|
(REAL)height / 2.0 -
|
|
|
|
GetFrameDotShift(LoadingAnimationFrame + LOADING_ANIMATION_FPS / 4, width, height) - DotWidth / 2.0,
|
|
|
|
DotWidth, DotWidth);
|
|
|
|
|
|
|
|
graphics.FillEllipse(
|
|
|
|
(Brush *)(&dotBrush), (REAL)width / 2.0 - DotWidth / 2.0,
|
|
|
|
(REAL)height / 2.0 - GetFrameDotShift(LoadingAnimationFrame, width, height) - DotWidth / 2.0, DotWidth,
|
|
|
|
DotWidth);
|
|
|
|
|
|
|
|
graphics.FillEllipse(
|
|
|
|
(Brush *)(&dotBrush), (REAL)width / 2.0 + min(width, height) * 2.0 / 16.0 - DotWidth / 2.0,
|
|
|
|
(REAL)height / 2.0 -
|
|
|
|
GetFrameDotShift(LoadingAnimationFrame - LOADING_ANIMATION_FPS / 4, width, height) - DotWidth / 2.0,
|
|
|
|
DotWidth, DotWidth);
|
|
|
|
}
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case SCRNSHOT_PREV_IMAGE:
|
|
|
|
{
|
|
|
|
if (pImage)
|
|
|
|
{
|
|
|
|
// always draw entire image inside the window.
|
|
|
|
Graphics graphics(hdcMem);
|
|
|
|
float ZoomRatio =
|
|
|
|
min(((float)width / (float)pImage->GetWidth()), ((float)height / (float)pImage->GetHeight()));
|
|
|
|
float ZoomedImgWidth = ZoomRatio * (float)pImage->GetWidth();
|
|
|
|
float ZoomedImgHeight = ZoomRatio * (float)pImage->GetHeight();
|
|
|
|
|
|
|
|
graphics.DrawImage(
|
|
|
|
pImage, ((float)width - ZoomedImgWidth) / 2.0, ((float)height - ZoomedImgHeight) / 2.0,
|
|
|
|
ZoomedImgWidth, ZoomedImgHeight);
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case SCRNSHOT_PREV_FAILED:
|
|
|
|
{
|
|
|
|
DrawIconEx(
|
|
|
|
hdcMem, (width - BrokenImgSize) / 2, (height - BrokenImgSize) / 2, hBrokenImgIcon, BrokenImgSize,
|
|
|
|
BrokenImgSize, NULL, NULL, DI_NORMAL | DI_COMPAT);
|
|
|
|
}
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// copy the content form off-screen dc to hdc
|
|
|
|
BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
|
|
|
|
DeleteDC(hdcMem);
|
|
|
|
DeleteObject(hBitmap);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
float
|
|
|
|
CAppScrnshotPreview::GetLoadingDotWidth(int width, int height)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
return min(width, height) / 20.0;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
float
|
|
|
|
CAppScrnshotPreview::GetFrameDotShift(int Frame, int width, int height)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
return min(width, height) * (1.0 / 16.0) * (2.0 / (2.0 - sqrt(3.0))) *
|
|
|
|
(max(sin((float)Frame * 2 * PI / (LOADING_ANIMATION_PERIOD * LOADING_ANIMATION_FPS)), sqrt(3.0) / 2.0) -
|
|
|
|
sqrt(3.0) / 2.0);
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
ATL::CWndClassInfo &
|
|
|
|
CAppScrnshotPreview::GetWndClassInfo()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
|
2023-02-20 18:30:02 +00:00
|
|
|
static ATL::CWndClassInfo wc = {
|
|
|
|
{sizeof(WNDCLASSEX), csStyle, StartWindowProc, 0, 0, NULL, 0, LoadCursorW(NULL, IDC_ARROW),
|
|
|
|
(HBRUSH)(COLOR_BTNFACE + 1), 0, L"RAppsScrnshotPreview", NULL},
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
IDC_ARROW,
|
|
|
|
TRUE,
|
|
|
|
0,
|
|
|
|
_T("")};
|
2020-07-24 08:07:43 +00:00
|
|
|
return wc;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HWND
|
|
|
|
CAppScrnshotPreview::Create(HWND hParent)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
RECT r = {0, 0, 0, 0};
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
return CWindowImpl::Create(hParent, r, L"", WS_CHILD | WS_VISIBLE);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppScrnshotPreview::PreviousDisplayCleanup()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
if (bLoadingTimerOn)
|
|
|
|
{
|
|
|
|
KillTimer(TIMER_LOADING_ANIMATION);
|
|
|
|
bLoadingTimerOn = FALSE;
|
|
|
|
}
|
|
|
|
LoadingAnimationFrame = 0;
|
|
|
|
if (pImage)
|
|
|
|
{
|
|
|
|
delete pImage;
|
|
|
|
pImage = NULL;
|
|
|
|
}
|
|
|
|
if (AsyncInet)
|
|
|
|
{
|
|
|
|
AsyncInetCancel(AsyncInet);
|
|
|
|
}
|
|
|
|
if (!TempImagePath.IsEmpty())
|
|
|
|
{
|
|
|
|
DeleteFileW(TempImagePath.GetString());
|
|
|
|
TempImagePath.Empty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppScrnshotPreview::DisplayEmpty()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
InterlockedIncrement64(&ContentID);
|
|
|
|
SetStatus(SCRNSHOT_PREV_EMPTY);
|
|
|
|
PreviousDisplayCleanup();
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CAppScrnshotPreview::DisplayImage(LPCWSTR lpszLocation)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
LONGLONG ID = InterlockedIncrement64(&ContentID);
|
|
|
|
PreviousDisplayCleanup();
|
|
|
|
|
|
|
|
if (PathIsURLW(lpszLocation))
|
|
|
|
{
|
|
|
|
DisplayLoading();
|
|
|
|
|
|
|
|
ScrnshotDownloadParam *DownloadParam = new ScrnshotDownloadParam;
|
2023-02-20 18:30:02 +00:00
|
|
|
if (!DownloadParam)
|
|
|
|
return FALSE;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
DownloadParam->hwndNotify = m_hWnd;
|
|
|
|
DownloadParam->ID = ID;
|
|
|
|
// generate a filename
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW ScrnshotFolder = m_BasePath;
|
2020-07-24 08:07:43 +00:00
|
|
|
PathAppendW(ScrnshotFolder.GetBuffer(MAX_PATH), L"screenshots");
|
|
|
|
ScrnshotFolder.ReleaseBuffer();
|
|
|
|
|
|
|
|
if (!PathIsDirectoryW(ScrnshotFolder.GetString()))
|
|
|
|
{
|
|
|
|
CreateDirectoryW(ScrnshotFolder.GetString(), NULL);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
if (!GetTempFileNameW(
|
|
|
|
ScrnshotFolder.GetString(), L"img", 0, DownloadParam->DownloadFileName.GetBuffer(MAX_PATH)))
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
DownloadParam->DownloadFileName.ReleaseBuffer();
|
|
|
|
delete DownloadParam;
|
|
|
|
DisplayFailed();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
DownloadParam->DownloadFileName.ReleaseBuffer();
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
DownloadParam->hFile = CreateFileW(
|
|
|
|
DownloadParam->DownloadFileName.GetString(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
|
|
|
NULL);
|
2020-07-24 08:07:43 +00:00
|
|
|
if (DownloadParam->hFile == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
delete DownloadParam;
|
|
|
|
DisplayFailed();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
AsyncInet = AsyncInetDownload(
|
|
|
|
0, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, lpszLocation, TRUE, ScrnshotDownloadCallback, DownloadParam);
|
2020-07-24 08:07:43 +00:00
|
|
|
if (!AsyncInet)
|
|
|
|
{
|
|
|
|
CloseHandle(DownloadParam->hFile);
|
|
|
|
DeleteFileW(DownloadParam->DownloadFileName.GetBuffer());
|
|
|
|
delete DownloadParam;
|
|
|
|
DisplayFailed();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return DisplayFile(lpszLocation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
int
|
|
|
|
CAppScrnshotPreview::GetRequestedWidth(int Height) // calculate requested window width by given height
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
switch (ScrnshotPrevStauts)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case SCRNSHOT_PREV_EMPTY:
|
|
|
|
return 0;
|
|
|
|
case SCRNSHOT_PREV_LOADING:
|
|
|
|
return 200;
|
|
|
|
case SCRNSHOT_PREV_IMAGE:
|
|
|
|
if (pImage)
|
|
|
|
{
|
|
|
|
// return the width needed to display image inside the window.
|
|
|
|
// and always keep window w/h ratio inside [ 1/SCRNSHOT_MAX_ASPECT_RAT, SCRNSHOT_MAX_ASPECT_RAT ]
|
|
|
|
return (int)floor(
|
|
|
|
(float)Height *
|
|
|
|
max(min((float)pImage->GetWidth() / (float)pImage->GetHeight(), (float)SCRNSHOT_MAX_ASPECT_RAT),
|
|
|
|
1.0 / (float)SCRNSHOT_MAX_ASPECT_RAT));
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
case SCRNSHOT_PREV_FAILED:
|
|
|
|
return 200;
|
|
|
|
default:
|
|
|
|
return 0;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CAppScrnshotPreview::~CAppScrnshotPreview()
|
|
|
|
{
|
|
|
|
PreviousDisplayCleanup();
|
|
|
|
}
|
|
|
|
// **** CAppScrnshotPreview ****
|
|
|
|
|
|
|
|
// **** CAppInfoDisplay ****
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CAppInfoDisplay::ProcessWindowMessage(
|
|
|
|
HWND hwnd,
|
|
|
|
UINT message,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam,
|
|
|
|
LRESULT &theResult,
|
|
|
|
DWORD dwMapId)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
theResult = 0;
|
|
|
|
switch (message)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_CREATE:
|
|
|
|
{
|
|
|
|
RichEdit = new CAppRichEdit();
|
|
|
|
RichEdit->Create(hwnd);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW Directory;
|
|
|
|
::GetStorageDirectory(Directory);
|
|
|
|
ScrnshotPrev = new CAppScrnshotPreview(Directory);
|
|
|
|
ScrnshotPrev->Create(hwnd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_SIZE:
|
|
|
|
{
|
|
|
|
ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_RAPPS_RESIZE_CHILDREN:
|
|
|
|
{
|
|
|
|
ResizeChildren();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_COMMAND:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
OnCommand(wParam, lParam);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_NOTIFY:
|
|
|
|
{
|
|
|
|
NMHDR *NotifyHeader = (NMHDR *)lParam;
|
|
|
|
if (NotifyHeader->hwndFrom == RichEdit->m_hWnd)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
switch (NotifyHeader->code)
|
|
|
|
{
|
|
|
|
case EN_LINK:
|
|
|
|
OnLink((ENLINK *)lParam);
|
|
|
|
break;
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2024-08-31 20:10:35 +00:00
|
|
|
case WM_SYSCOLORCHANGE:
|
|
|
|
{
|
|
|
|
RichEdit->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
|
|
|
|
break;
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppInfoDisplay::ResizeChildren()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
CRect rect;
|
|
|
|
GetWindowRect(&rect);
|
|
|
|
ResizeChildren(rect.Width(), rect.Height());
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppInfoDisplay::ResizeChildren(int Width, int Height)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
int ScrnshotWidth = ScrnshotPrev->GetRequestedWidth(Height);
|
|
|
|
|
|
|
|
// make sure richedit always have room to display
|
|
|
|
ScrnshotWidth = min(ScrnshotWidth, Width - INFO_DISPLAY_PADDING - RICHEDIT_MIN_WIDTH);
|
|
|
|
|
|
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
HDWP hDwp = BeginDeferWindowPos(2);
|
|
|
|
|
|
|
|
if (hDwp)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
hDwp = ::DeferWindowPos(hDwp, ScrnshotPrev->m_hWnd, NULL, 0, 0, ScrnshotWidth, Height, 0);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
if (hDwp)
|
|
|
|
{
|
|
|
|
// hide the padding if scrnshot window width == 0
|
|
|
|
int RicheditPosX = ScrnshotWidth ? (ScrnshotWidth + INFO_DISPLAY_PADDING) : 0;
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
hDwp = ::DeferWindowPos(hDwp, RichEdit->m_hWnd, NULL, RicheditPosX, 0, Width - RicheditPosX, Height, 0);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
if (hDwp)
|
|
|
|
{
|
|
|
|
EndDeferWindowPos(hDwp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dwError = GetLastError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dwError = GetLastError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dwError = GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if DBG
|
|
|
|
ATLASSERT(dwError == ERROR_SUCCESS);
|
|
|
|
#endif
|
2021-03-11 11:26:45 +00:00
|
|
|
UNREFERENCED_PARAMETER(dwError);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
UpdateWindow();
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppInfoDisplay::OnLink(ENLINK *Link)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
switch (Link->msg)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case WM_RBUTTONUP:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
if (pLink)
|
|
|
|
HeapFree(GetProcessHeap(), 0, pLink);
|
|
|
|
|
|
|
|
pLink = (LPWSTR)HeapAlloc(
|
|
|
|
GetProcessHeap(), 0,
|
|
|
|
(max(Link->chrg.cpMin, Link->chrg.cpMax) - min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) *
|
|
|
|
sizeof(WCHAR));
|
|
|
|
if (!pLink)
|
|
|
|
{
|
|
|
|
/* TODO: Error message */
|
|
|
|
return;
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
|
|
|
|
RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM)pLink);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
ShowPopupMenuEx(m_hWnd, m_hWnd, IDR_LINKMENU, -1);
|
|
|
|
}
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
ATL::CWndClassInfo &
|
|
|
|
CAppInfoDisplay::GetWndClassInfo()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
|
2023-02-20 18:30:02 +00:00
|
|
|
static ATL::CWndClassInfo wc = {/*.m_wc=*/
|
|
|
|
{/*cbSize=*/sizeof(WNDCLASSEX),
|
|
|
|
/*style=*/csStyle,
|
|
|
|
/*lpfnWndProc=*/StartWindowProc,
|
|
|
|
/*cbClsExtra=*/0,
|
|
|
|
/*cbWndExtra=*/0,
|
|
|
|
/*hInstance=*/NULL,
|
|
|
|
/*hIcon=*/NULL,
|
|
|
|
/*hCursor*/ NULL,
|
|
|
|
/*hbrBackground=*/(HBRUSH)(COLOR_BTNFACE + 1),
|
|
|
|
/*lpszMenuName=*/NULL,
|
|
|
|
/*lpszClassName=*/L"RAppsAppInfo",
|
|
|
|
/*hIconSm=*/NULL},
|
|
|
|
/*m_lpszOrigName=*/NULL,
|
|
|
|
/*pWndProc=*/NULL,
|
|
|
|
/*m_lpszCursorID=*/IDC_ARROW,
|
|
|
|
/*m_bSystemCursor*/ TRUE,
|
|
|
|
/*m_atom=*/0,
|
|
|
|
/*m_szAutoName=*/_T("")};
|
2020-07-24 08:07:43 +00:00
|
|
|
return wc;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HWND
|
|
|
|
CAppInfoDisplay::Create(HWND hwndParent)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
RECT r = {0, 0, 0, 0};
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
2023-02-28 00:00:29 +00:00
|
|
|
CAppInfoDisplay::ShowAppInfo(CAppInfo *Info)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW ScrnshotLocation;
|
|
|
|
if (Info->RetrieveScreenshot(ScrnshotLocation))
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
ScrnshotPrev->DisplayImage(ScrnshotLocation);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScrnshotPrev->DisplayEmpty();
|
|
|
|
}
|
|
|
|
ResizeChildren();
|
2023-02-20 18:30:02 +00:00
|
|
|
Info->ShowAppInfo(RichEdit);
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2024-09-16 16:26:09 +00:00
|
|
|
void
|
|
|
|
CAppInfoDisplay::SetWelcomeText(bool bAppwiz)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2024-09-16 16:26:09 +00:00
|
|
|
CStringW szText;
|
|
|
|
|
2020-07-24 08:07:43 +00:00
|
|
|
ScrnshotPrev->DisplayEmpty();
|
|
|
|
ResizeChildren();
|
2024-09-16 16:26:09 +00:00
|
|
|
|
|
|
|
// Display the standard banner in normal mode, or
|
|
|
|
// the specific "Add/Remove Programs" in APPWIZ-mode.
|
|
|
|
if (!bAppwiz)
|
|
|
|
{
|
|
|
|
szText.LoadStringW(IDS_WELCOME_TITLE);
|
|
|
|
RichEdit->SetText(szText, CFE_BOLD);
|
|
|
|
RichEdit->InsertText(L"\n\n", 0);
|
|
|
|
|
|
|
|
szText.LoadStringW(IDS_WELCOME_TEXT);
|
|
|
|
RichEdit->InsertText(szText, 0);
|
|
|
|
|
|
|
|
szText.LoadStringW(IDS_WELCOME_URL);
|
|
|
|
RichEdit->InsertText(szText, CFM_LINK);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
szText.LoadStringW(IDS_APPWIZ_TITLE);
|
|
|
|
RichEdit->SetText(szText, CFE_BOLD);
|
|
|
|
RichEdit->InsertText(L"\n\n", 0);
|
|
|
|
|
|
|
|
szText.LoadStringW(IDS_APPWIZ_TEXT1);
|
|
|
|
RichEdit->InsertText(szText, 0);
|
|
|
|
RichEdit->InsertText(L"\n", 0);
|
|
|
|
|
|
|
|
szText.LoadStringW(IDS_APPWIZ_TEXT2);
|
|
|
|
RichEdit->InsertText(szText, 0);
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppInfoDisplay::OnCommand(WPARAM wParam, LPARAM lParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
WORD wCommand = LOWORD(wParam);
|
|
|
|
|
|
|
|
switch (wCommand)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_OPEN_LINK:
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
|
|
|
|
HeapFree(GetProcessHeap(), 0, pLink);
|
|
|
|
pLink = NULL;
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_COPY_LINK:
|
|
|
|
CopyTextToClipboard(pLink);
|
|
|
|
HeapFree(GetProcessHeap(), 0, pLink);
|
|
|
|
pLink = NULL;
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CAppInfoDisplay::~CAppInfoDisplay()
|
|
|
|
{
|
|
|
|
delete RichEdit;
|
|
|
|
delete ScrnshotPrev;
|
|
|
|
}
|
|
|
|
// **** CAppInfoDisplay ****
|
|
|
|
|
|
|
|
// **** CAppsListView ****
|
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
struct CAsyncLoadIcon {
|
|
|
|
CAsyncLoadIcon *pNext;
|
|
|
|
HWND hAppsList;
|
|
|
|
CAppInfo *AppInfo; // Only used to find the item in the list, do not access on background thread
|
|
|
|
UINT TaskId;
|
|
|
|
bool Parse;
|
|
|
|
WCHAR Location[ANYSIZE_ARRAY];
|
|
|
|
|
|
|
|
void Free() { free(this); }
|
|
|
|
static CAsyncLoadIcon* Queue(HWND hAppsList, CAppInfo &AppInfo, bool Parse);
|
|
|
|
static void StartTasks();
|
|
|
|
} *g_AsyncIconTasks = NULL;
|
|
|
|
static UINT g_AsyncIconTaskId = 0;
|
|
|
|
|
|
|
|
static DWORD CALLBACK
|
|
|
|
AsyncLoadIconProc(LPVOID Param)
|
|
|
|
{
|
|
|
|
for (CAsyncLoadIcon *task = (CAsyncLoadIcon*)Param, *old; task; old->Free())
|
|
|
|
{
|
|
|
|
if (task->TaskId == g_AsyncIconTaskId)
|
|
|
|
{
|
|
|
|
HICON hIcon;
|
|
|
|
if (!task->Parse)
|
|
|
|
hIcon = (HICON)LoadImageW(NULL, task->Location, IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
|
|
|
|
else if (!ExtractIconExW(task->Location, PathParseIconLocationW(task->Location), &hIcon, NULL, 1))
|
|
|
|
hIcon = NULL;
|
|
|
|
|
|
|
|
if (hIcon)
|
|
|
|
{
|
|
|
|
SendMessageW(task->hAppsList, WM_RAPPSLIST_ASYNCICON, (WPARAM)hIcon, (LPARAM)task);
|
|
|
|
DestroyIcon(hIcon);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
old = task;
|
|
|
|
task = task->pNext;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CAsyncLoadIcon*
|
|
|
|
CAsyncLoadIcon::Queue(HWND hAppsList, CAppInfo &AppInfo, bool Parse)
|
|
|
|
{
|
|
|
|
ATLASSERT(GetCurrentThreadId() == GetWindowThreadProcessId(hAppsList, NULL));
|
|
|
|
CStringW szIconPath;
|
|
|
|
if (!AppInfo.RetrieveIcon(szIconPath))
|
|
|
|
return NULL;
|
|
|
|
SIZE_T cbstr = (szIconPath.GetLength() + 1) * sizeof(WCHAR);
|
|
|
|
CAsyncLoadIcon *task = (CAsyncLoadIcon*)malloc(sizeof(CAsyncLoadIcon) + cbstr);
|
|
|
|
if (!task)
|
|
|
|
return NULL;
|
|
|
|
task->hAppsList = hAppsList;
|
|
|
|
task->AppInfo = &AppInfo;
|
|
|
|
task->TaskId = g_AsyncIconTaskId;
|
|
|
|
task->Parse = Parse;
|
|
|
|
CopyMemory(task->Location, szIconPath.GetBuffer(), cbstr);
|
|
|
|
szIconPath.ReleaseBuffer();
|
|
|
|
task->pNext = g_AsyncIconTasks;
|
|
|
|
g_AsyncIconTasks = task;
|
|
|
|
return task;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CAsyncLoadIcon::StartTasks()
|
|
|
|
{
|
|
|
|
CAsyncLoadIcon *tasks = g_AsyncIconTasks;
|
|
|
|
g_AsyncIconTasks = NULL;
|
|
|
|
if (HANDLE hThread = CreateThread(NULL, 0, AsyncLoadIconProc, tasks, 0, NULL))
|
|
|
|
CloseHandle(hThread);
|
|
|
|
else
|
|
|
|
AsyncLoadIconProc(tasks); // Insist so we at least free the tasks
|
|
|
|
}
|
|
|
|
|
2021-06-09 20:56:53 +00:00
|
|
|
CAppsListView::CAppsListView()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2024-06-13 00:20:41 +00:00
|
|
|
m_hImageListView = 0;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2021-06-09 20:56:53 +00:00
|
|
|
CAppsListView::~CAppsListView()
|
|
|
|
{
|
|
|
|
if (m_hImageListView)
|
|
|
|
ImageList_Destroy(m_hImageListView);
|
2024-06-13 00:20:41 +00:00
|
|
|
if (g_hDefaultPackageIcon)
|
|
|
|
DestroyIcon(g_hDefaultPackageIcon);
|
2021-06-09 20:56:53 +00:00
|
|
|
}
|
|
|
|
|
2021-12-30 19:17:32 +00:00
|
|
|
LRESULT
|
|
|
|
CAppsListView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
|
|
{
|
|
|
|
LRESULT lRes = this->DefWindowProc(uMsg, wParam, lParam);
|
|
|
|
if (!m_Watermark.IsEmpty())
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
GetClientRect(&rc);
|
|
|
|
HGDIOBJ oldFont = SelectFont(HDC(wParam), GetStockFont(DEFAULT_GUI_FONT));
|
|
|
|
DrawShadowText(
|
|
|
|
HDC(wParam), m_Watermark.GetString(), m_Watermark.GetLength(), &rc,
|
|
|
|
DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE, GetSysColor(COLOR_GRAYTEXT),
|
|
|
|
GetSysColor(COLOR_GRAYTEXT), 1, 1);
|
|
|
|
SelectFont(HDC(wParam), oldFont);
|
|
|
|
}
|
|
|
|
return lRes;
|
|
|
|
}
|
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
LRESULT
|
|
|
|
CAppsListView::OnAsyncIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
|
|
|
|
{
|
|
|
|
CAsyncLoadIcon *task = (CAsyncLoadIcon*)lParam;
|
|
|
|
bHandled = TRUE;
|
|
|
|
if (task->TaskId == g_AsyncIconTaskId)
|
|
|
|
{
|
|
|
|
LVITEM lvi;
|
|
|
|
LVFINDINFO lvfi;
|
|
|
|
lvfi.flags = LVFI_PARAM;
|
|
|
|
lvfi.lParam = (LPARAM)task->AppInfo;
|
|
|
|
lvi.iItem = ListView_FindItem(m_hWnd, -1, &lvfi);
|
|
|
|
if (lvi.iItem != -1)
|
|
|
|
{
|
|
|
|
lvi.iImage = ImageList_AddIcon(m_hImageListView, (HICON)wParam);
|
|
|
|
if (lvi.iImage != -1)
|
|
|
|
{
|
|
|
|
lvi.mask = LVIF_IMAGE;
|
|
|
|
lvi.iSubItem = 0;
|
|
|
|
ListView_SetItem(m_hWnd, &lvi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppsListView::SetWatermark(const CStringW &Text)
|
2021-12-30 19:17:32 +00:00
|
|
|
{
|
|
|
|
m_Watermark = Text;
|
|
|
|
}
|
|
|
|
|
2024-09-16 20:47:42 +00:00
|
|
|
void
|
|
|
|
CAppsListView::ShowCheckboxes(bool bShow)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2024-09-16 20:47:42 +00:00
|
|
|
SetExtendedListViewStyle((bShow ? LVS_EX_CHECKBOXES : 0) | LVS_EX_FULLROWSELECT);
|
|
|
|
bHasCheckboxes = bShow;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppsListView::ColumnClick(LPNMLISTVIEW pnmv)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
HWND hHeader;
|
|
|
|
HDITEMW hColumn;
|
|
|
|
INT nHeaderID = pnmv->iSubItem;
|
|
|
|
|
|
|
|
if ((GetWindowLongPtr(GWL_STYLE) & ~LVS_NOSORTHEADER) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
hHeader = (HWND)SendMessage(LVM_GETHEADER, 0, 0);
|
|
|
|
ZeroMemory(&hColumn, sizeof(hColumn));
|
|
|
|
|
|
|
|
/* If the sorting column changed, remove the sorting style from the old column */
|
|
|
|
if ((nLastHeaderID != -1) && (nLastHeaderID != nHeaderID))
|
|
|
|
{
|
|
|
|
bIsAscending = TRUE; // also reset sorting method to ascending
|
|
|
|
hColumn.mask = HDI_FORMAT;
|
|
|
|
Header_GetItem(hHeader, nLastHeaderID, &hColumn);
|
|
|
|
hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
|
|
|
|
Header_SetItem(hHeader, nLastHeaderID, &hColumn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the sorting style to the new column */
|
|
|
|
hColumn.mask = HDI_FORMAT;
|
|
|
|
Header_GetItem(hHeader, nHeaderID, &hColumn);
|
|
|
|
|
|
|
|
hColumn.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
|
|
|
|
hColumn.fmt |= (bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
|
|
|
|
Header_SetItem(hHeader, nHeaderID, &hColumn);
|
|
|
|
|
|
|
|
/* Sort the list, using the current values of nHeaderID and bIsAscending */
|
2023-02-20 18:30:02 +00:00
|
|
|
SortContext ctx = {this, nHeaderID};
|
2020-07-24 08:07:43 +00:00
|
|
|
SortItems(s_CompareFunc, &ctx);
|
|
|
|
|
|
|
|
/* Save new values */
|
|
|
|
nLastHeaderID = nHeaderID;
|
|
|
|
bIsAscending = !bIsAscending;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CAppsListView::AddColumn(INT Index, CStringW &Text, INT Width, INT Format)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
LVCOLUMNW Column;
|
|
|
|
|
|
|
|
ZeroMemory(&Column, sizeof(Column));
|
|
|
|
|
|
|
|
Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
|
|
|
|
Column.iSubItem = Index;
|
2023-02-20 18:30:02 +00:00
|
|
|
Column.pszText = const_cast<LPWSTR>(Text.GetString());
|
2020-07-24 08:07:43 +00:00
|
|
|
Column.cx = Width;
|
|
|
|
Column.fmt = Format;
|
|
|
|
|
|
|
|
return SendMessage(LVM_INSERTCOLUMN, Index, (LPARAM)(&Column));
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
void
|
|
|
|
CAppsListView::DeleteColumn(INT Index)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
SendMessage(LVM_DELETECOLUMN, Index, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
INT
|
|
|
|
CAppsListView::AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
LVITEMW Item;
|
|
|
|
|
|
|
|
ZeroMemory(&Item, sizeof(Item));
|
|
|
|
|
|
|
|
Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
|
|
|
|
Item.pszText = const_cast<LPWSTR>(lpText);
|
|
|
|
Item.lParam = lParam;
|
|
|
|
Item.iItem = ItemIndex;
|
|
|
|
Item.iImage = IconIndex;
|
|
|
|
|
|
|
|
if (IconIndex >= 0)
|
|
|
|
{
|
|
|
|
Item.iImage = IconIndex;
|
|
|
|
Item.mask |= LVIF_IMAGE;
|
|
|
|
}
|
|
|
|
return InsertItem(&Item);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HIMAGELIST
|
|
|
|
CAppsListView::GetImageList(int iImageList)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
return (HIMAGELIST)SendMessage(LVM_GETIMAGELIST, iImageList, 0);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
INT CALLBACK
|
|
|
|
CAppsListView::s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
SortContext *ctx = ((SortContext *)lParamSort);
|
|
|
|
return ctx->lvw->CompareFunc(lParam1, lParam2, ctx->iSubItem);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
INT
|
|
|
|
CAppsListView::CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW Item1, Item2;
|
2020-07-24 08:07:43 +00:00
|
|
|
LVFINDINFOW IndexInfo;
|
|
|
|
INT Index;
|
|
|
|
|
|
|
|
IndexInfo.flags = LVFI_PARAM;
|
|
|
|
|
|
|
|
IndexInfo.lParam = lParam1;
|
|
|
|
Index = FindItem(-1, &IndexInfo);
|
|
|
|
GetItemText(Index, iSubItem, Item1.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
|
|
|
|
Item1.ReleaseBuffer();
|
|
|
|
|
|
|
|
IndexInfo.lParam = lParam2;
|
|
|
|
Index = FindItem(-1, &IndexInfo);
|
|
|
|
GetItemText(Index, iSubItem, Item2.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
|
|
|
|
Item2.ReleaseBuffer();
|
|
|
|
|
|
|
|
return bIsAscending ? Item1.Compare(Item2) : Item2.Compare(Item1);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HWND
|
|
|
|
CAppsListView::Create(HWND hwndParent)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
RECT r = {205, 28, 465, 250};
|
|
|
|
DWORD style = WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS |
|
|
|
|
LVS_AUTOARRANGE | LVS_SHAREIMAGELISTS;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE);
|
|
|
|
|
|
|
|
if (hwnd)
|
|
|
|
{
|
2024-09-16 20:47:42 +00:00
|
|
|
ShowCheckboxes(false);
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2021-12-30 19:17:32 +00:00
|
|
|
#pragma push_macro("SubclassWindow")
|
|
|
|
#undef SubclassWindow
|
|
|
|
m_hWnd = NULL;
|
|
|
|
SubclassWindow(hwnd);
|
|
|
|
#pragma pop_macro("SubclassWindow")
|
|
|
|
|
2020-07-24 08:07:43 +00:00
|
|
|
return hwnd;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CAppsListView::GetCheckState(INT item)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
return (BOOL)(GetItemState(item, LVIS_STATEIMAGEMASK) >> 12) - 1;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppsListView::SetCheckState(INT item, BOOL fCheck)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
if (bHasCheckboxes)
|
|
|
|
{
|
|
|
|
SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), LVIS_STATEIMAGEMASK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppsListView::CheckAll()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
if (bHasCheckboxes)
|
|
|
|
{
|
|
|
|
if (CheckedItemCount == ItemCount)
|
|
|
|
{
|
|
|
|
// clear all
|
|
|
|
SetCheckState(-1, FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// check all
|
|
|
|
SetCheckState(-1, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
PVOID
|
|
|
|
CAppsListView::GetFocusedItemData()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
INT item = GetSelectionMark();
|
|
|
|
if (item == -1)
|
|
|
|
{
|
|
|
|
return (PVOID)0;
|
|
|
|
}
|
|
|
|
return (PVOID)GetItemData(item);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CAppsListView::SetDisplayAppType(APPLICATION_VIEW_TYPE AppType)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2024-06-13 00:20:41 +00:00
|
|
|
++g_AsyncIconTaskId; // Stop loading icons that are now invalid
|
2023-02-20 18:30:02 +00:00
|
|
|
if (!DeleteAllItems())
|
|
|
|
return FALSE;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
ApplicationViewType = AppType;
|
2020-07-24 08:07:43 +00:00
|
|
|
bIsAscending = TRUE;
|
|
|
|
ItemCount = 0;
|
|
|
|
CheckedItemCount = 0;
|
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
ListView_Scroll(m_hWnd, 0, 0x7fff * -1); // FIXME: a bug in Wine ComCtl32 where VScroll is not reset after deleting items
|
|
|
|
|
2020-07-24 08:07:43 +00:00
|
|
|
// delete old columns
|
|
|
|
while (ColumnCount)
|
|
|
|
{
|
|
|
|
DeleteColumn(--ColumnCount);
|
|
|
|
}
|
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
if (!g_hDefaultPackageIcon)
|
|
|
|
{
|
|
|
|
ImageList_Destroy(m_hImageListView);
|
|
|
|
UINT IconSize = GetSystemMetrics(SM_CXICON);
|
|
|
|
UINT ilc = GetSystemColorDepth() | ILC_MASK;
|
|
|
|
m_hImageListView = ImageList_Create(IconSize, IconSize, ilc, 0, 1);
|
|
|
|
SetImageList(m_hImageListView, LVSIL_SMALL);
|
|
|
|
SetImageList(m_hImageListView, LVSIL_NORMAL);
|
|
|
|
g_hDefaultPackageIcon = (HICON)LoadImageW(hInst, MAKEINTRESOURCEW(IDI_MAIN),
|
|
|
|
IMAGE_ICON, IconSize, IconSize, LR_SHARED);
|
|
|
|
}
|
2020-07-29 10:50:57 +00:00
|
|
|
ImageList_RemoveAll(m_hImageListView);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
g_DefaultPackageIconILIdx = ImageList_AddIcon(m_hImageListView, g_hDefaultPackageIcon);
|
|
|
|
if (g_DefaultPackageIconILIdx == -1)
|
|
|
|
g_DefaultPackageIconILIdx = I_IMAGENONE;
|
|
|
|
|
2020-07-24 08:07:43 +00:00
|
|
|
// add new columns
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szText;
|
2020-07-29 10:50:57 +00:00
|
|
|
switch (AppType)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case AppViewTypeInstalledApps:
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
/* Add columns to ListView */
|
|
|
|
szText.LoadStringW(IDS_APP_NAME);
|
2024-09-16 16:38:33 +00:00
|
|
|
AddColumn(ColumnCount++, szText, 368, LVCFMT_LEFT);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
szText.LoadStringW(IDS_APP_INST_VERSION);
|
|
|
|
AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-09-16 16:38:33 +00:00
|
|
|
#if 0 // This column is not currently useful for installed apps.
|
2023-02-20 18:30:02 +00:00
|
|
|
szText.LoadStringW(IDS_APP_DESCRIPTION);
|
|
|
|
AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
|
2024-09-16 16:38:33 +00:00
|
|
|
#endif
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-09-16 20:47:42 +00:00
|
|
|
// Disable checkboxes
|
|
|
|
ShowCheckboxes(false);
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case AppViewTypeAvailableApps:
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
/* Add columns to ListView */
|
|
|
|
szText.LoadStringW(IDS_APP_NAME);
|
|
|
|
AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
szText.LoadStringW(IDS_APP_INST_VERSION);
|
|
|
|
AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
szText.LoadStringW(IDS_APP_DESCRIPTION);
|
|
|
|
AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-09-16 20:47:42 +00:00
|
|
|
// Enable checkboxes
|
|
|
|
ShowCheckboxes(true);
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
default:
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CAppsListView::SetViewMode(DWORD ViewMode)
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
return SendMessage(LVM_SETVIEW, (WPARAM)ViewMode, 0) == 1;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
2023-02-28 00:00:29 +00:00
|
|
|
CAppsListView::AddApplication(CAppInfo *AppInfo, BOOL InitialCheckState)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2024-06-13 00:20:41 +00:00
|
|
|
if (!AppInfo)
|
[RAPPS] Display custom applications icons for installed applications CORE-17257 (#3144)
* [RAPPS] Display custom applications icons for installed applications
- Implement `RetrieveIcon` helper function in `CInstalledApplicationInfo` class, which retrueves the current app's icon from registry, same as it done for `CAvailableApplicationInfo`.
- Use it for loading the icon in `CAppsListView::AddInstalledApplication` function, via `ExtractIconW`. Load default Rapps icon only when the app has no its custom icon.
- Retrieve `DisplayIcon` value from registry in `CInstalledApps::Enum` function, same as other registry values (like app name, description, etc).Store it in `szDisplayIcon` string, which is used in `CInstalledApplicationInfo::RetrieveIcon` for retrieving the data of that value.
- Increase `LISTVIEW_ICON_SIZE` macro from 24 to 32, so 32x32 icon size is now used instead of 24x24. This makes displayed icons more accurate, since most of apps contain 32x32 icon, so they look a bit distorted with 24x24 size.
2020-09-20 17:19:59 +00:00
|
|
|
{
|
2024-06-13 00:20:41 +00:00
|
|
|
CAsyncLoadIcon::StartTasks();
|
|
|
|
return TRUE;
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-06-13 00:20:41 +00:00
|
|
|
int IconIndex = g_DefaultPackageIconILIdx;
|
|
|
|
if (ApplicationViewType == AppViewTypeInstalledApps)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
int Index = AddItem(ItemCount, IconIndex, AppInfo->szDisplayName, (LPARAM)AppInfo);
|
2024-06-13 00:20:41 +00:00
|
|
|
if (Index == -1)
|
|
|
|
return FALSE;
|
|
|
|
CAsyncLoadIcon::Queue(m_hWnd, *AppInfo, true);
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
SetItemText(Index, 1, AppInfo->szDisplayVersion.IsEmpty() ? L"---" : AppInfo->szDisplayVersion);
|
|
|
|
SetItemText(Index, 2, AppInfo->szComments.IsEmpty() ? L"---" : AppInfo->szComments);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
ItemCount++;
|
|
|
|
return TRUE;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
else if (ApplicationViewType == AppViewTypeAvailableApps)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
int Index = AddItem(ItemCount, IconIndex, AppInfo->szDisplayName, (LPARAM)AppInfo);
|
2024-06-13 00:20:41 +00:00
|
|
|
if (Index == -1)
|
|
|
|
return FALSE;
|
|
|
|
CAsyncLoadIcon::Queue(m_hWnd, *AppInfo, false);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
if (InitialCheckState)
|
|
|
|
{
|
|
|
|
SetCheckState(Index, TRUE);
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
SetItemText(Index, 1, AppInfo->szDisplayVersion);
|
|
|
|
SetItemText(Index, 2, AppInfo->szComments);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
ItemCount++;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// this function is called when parent window receiving an notification about checkstate changing
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CAppsListView::ItemCheckStateNotify(int iItem, BOOL bCheck)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
if (bCheck)
|
|
|
|
{
|
|
|
|
CheckedItemCount++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CheckedItemCount--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// **** CAppsListView ****
|
|
|
|
|
|
|
|
// **** CApplicationView ****
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::ProcessWindowMessage(
|
|
|
|
HWND hwnd,
|
|
|
|
UINT message,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam,
|
|
|
|
LRESULT &theResult,
|
|
|
|
DWORD dwMapId)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
theResult = 0;
|
|
|
|
switch (message)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_CREATE:
|
|
|
|
{
|
|
|
|
BOOL bSuccess = TRUE;
|
|
|
|
m_Panel = new CUiPanel();
|
|
|
|
m_Panel->m_VerticalAlignment = UiAlign_Stretch;
|
|
|
|
m_Panel->m_HorizontalAlignment = UiAlign_Stretch;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
bSuccess &= CreateToolbar();
|
|
|
|
bSuccess &= CreateSearchBar();
|
|
|
|
bSuccess &= CreateComboBox();
|
|
|
|
bSuccess &= CreateHSplitter();
|
|
|
|
bSuccess &= CreateListView();
|
|
|
|
bSuccess &= CreateAppInfoDisplay();
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-03-22 17:20:35 +00:00
|
|
|
/* APPWIZ-mode: Remove the unneeded menu items and toolbar buttons */
|
|
|
|
if (m_MainWindow->m_bAppwizMode)
|
|
|
|
{
|
|
|
|
HMENU hMenu;
|
|
|
|
|
|
|
|
/* Delete the "Settings" item in the "File" sub-menu */
|
|
|
|
hMenu = ::GetSubMenu(m_MainWindow->GetMenu(), 0);
|
|
|
|
DeleteMenuEx(hMenu, ID_SETTINGS, MF_BYCOMMAND);
|
|
|
|
|
|
|
|
/* Remove the menu items: ID_INSTALL, ID_RESETDB */
|
|
|
|
hMenu = GetMenu();
|
|
|
|
DeleteMenuEx(hMenu, ID_INSTALL, MF_BYCOMMAND);
|
|
|
|
DeleteMenuEx(hMenu, ID_RESETDB, MF_BYCOMMAND);
|
|
|
|
|
|
|
|
/* Remove the toolbar buttons:
|
|
|
|
* ID_INSTALL, ID_CHECK_ALL, ID_RESETDB
|
|
|
|
* We only keep:
|
|
|
|
* ID_UNINSTALL, ID_MODIFY, ID_REFRESH */
|
|
|
|
TBBUTTONINFO info = { sizeof(info), 0 };
|
|
|
|
int index;
|
|
|
|
|
|
|
|
index = m_Toolbar->GetButtonInfo(ID_INSTALL, &info);
|
|
|
|
if (index >= 0) m_Toolbar->DeleteButton(index);
|
|
|
|
|
|
|
|
index = m_Toolbar->GetButtonInfo(ID_CHECK_ALL, &info);
|
|
|
|
if (index >= 0) m_Toolbar->DeleteButton(index);
|
|
|
|
|
|
|
|
index = m_Toolbar->GetButtonInfo(ID_RESETDB, &info);
|
|
|
|
if (index >= 0) m_Toolbar->DeleteButton(index);
|
2024-03-22 20:55:43 +00:00
|
|
|
|
|
|
|
/* Update the ideal width to use as a max width of buttons */
|
|
|
|
m_Toolbar->UpdateMaxButtonsWidth();
|
2024-03-22 17:20:35 +00:00
|
|
|
}
|
|
|
|
|
2024-03-22 20:55:43 +00:00
|
|
|
/* Resize the toolbar */
|
2023-02-20 18:30:02 +00:00
|
|
|
m_Toolbar->AutoSize();
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
RECT rTop;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
|
|
|
|
m_HSplitter->m_Margin.top = rTop.bottom - rTop.top;
|
|
|
|
if (!bSuccess)
|
|
|
|
{
|
|
|
|
return -1; // creation failure
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_NOTIFY:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
LPNMHDR pNotifyHeader = (LPNMHDR)lParam;
|
|
|
|
if (pNotifyHeader->hwndFrom == m_ListView->GetWindow())
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
switch (pNotifyHeader->code)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case LVN_ITEMCHANGED:
|
|
|
|
{
|
|
|
|
LPNMLISTVIEW pnic = (LPNMLISTVIEW)lParam;
|
|
|
|
|
|
|
|
/* Check if this is a valid item
|
|
|
|
* (technically, it can be also an unselect) */
|
|
|
|
INT ItemIndex = pnic->iItem;
|
|
|
|
if (ItemIndex == -1 || ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the focus has been moved to another item */
|
|
|
|
if ((pnic->uChanged & LVIF_STATE) && (pnic->uNewState & LVIS_FOCUSED) &&
|
|
|
|
!(pnic->uOldState & LVIS_FOCUSED))
|
|
|
|
{
|
|
|
|
ItemGetFocus((LPVOID)pnic->lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the item is checked/unchecked */
|
|
|
|
if (pnic->uChanged & LVIF_STATE)
|
|
|
|
{
|
|
|
|
int iOldState = STATEIMAGETOINDEX(pnic->uOldState);
|
|
|
|
int iNewState = STATEIMAGETOINDEX(pnic->uNewState);
|
|
|
|
|
|
|
|
if (iOldState == STATEIMAGE_UNCHECKED && iNewState == STATEIMAGE_CHECKED)
|
|
|
|
{
|
|
|
|
// this item is just checked
|
|
|
|
m_ListView->ItemCheckStateNotify(pnic->iItem, TRUE);
|
|
|
|
ItemCheckStateChanged(TRUE, (LPVOID)pnic->lParam);
|
|
|
|
}
|
|
|
|
else if (iOldState == STATEIMAGE_CHECKED && iNewState == STATEIMAGE_UNCHECKED)
|
|
|
|
{
|
|
|
|
// this item is just unchecked
|
|
|
|
m_ListView->ItemCheckStateNotify(pnic->iItem, FALSE);
|
|
|
|
ItemCheckStateChanged(FALSE, (LPVOID)pnic->lParam);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
break;
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case LVN_COLUMNCLICK:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
|
|
|
|
|
|
|
|
m_ListView->ColumnClick(pnmv);
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NM_DBLCLK:
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
LPNMITEMACTIVATE Item = (LPNMITEMACTIVATE)lParam;
|
|
|
|
if (Item->iItem != -1)
|
|
|
|
{
|
|
|
|
/* this won't do anything if the program is already installed */
|
|
|
|
|
|
|
|
if (ApplicationViewType == AppViewTypeAvailableApps)
|
|
|
|
{
|
|
|
|
m_MainWindow->InstallApplication(
|
2023-02-28 00:00:29 +00:00
|
|
|
(CAppInfo *)m_ListView->GetItemData(Item->iItem));
|
2023-02-20 18:30:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
else if (pNotifyHeader->hwndFrom == m_Toolbar->GetWindow())
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
switch (pNotifyHeader->code)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case TTN_GETDISPINFO:
|
|
|
|
m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT)lParam);
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_SYSCOLORCHANGE:
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
/* Forward WM_SYSCOLORCHANGE to common controls */
|
|
|
|
m_ListView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
|
2024-08-31 20:10:35 +00:00
|
|
|
m_AppsInfo->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
|
2023-02-20 18:30:02 +00:00
|
|
|
m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
|
|
|
|
m_ComboBox->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_SIZE:
|
|
|
|
{
|
|
|
|
OnSize(hwnd, wParam, lParam);
|
|
|
|
break;
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case WM_COMMAND:
|
|
|
|
{
|
|
|
|
OnCommand(wParam, lParam);
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
break;
|
2024-08-31 16:30:45 +00:00
|
|
|
|
|
|
|
case WM_CONTEXTMENU:
|
|
|
|
{
|
|
|
|
bool kbd = -1 == (int)(INT_PTR)lParam;
|
|
|
|
if ((HWND)wParam == m_ListView->m_hWnd)
|
|
|
|
{
|
|
|
|
int item = m_ListView->GetNextItem(-1, LVNI_FOCUSED | LVNI_SELECTED);
|
|
|
|
if (item != -1)
|
|
|
|
{
|
|
|
|
POINT *ppt = NULL, pt;
|
|
|
|
if (kbd)
|
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
ListView_GetItemRect((HWND)wParam, item, &r, LVIR_LABEL);
|
|
|
|
pt.x = r.left + (r.right - r.left) / 2;
|
|
|
|
pt.y = r.top + (r.bottom - r.top) / 2;
|
|
|
|
::ClientToScreen((HWND)wParam, ppt = &pt);
|
|
|
|
}
|
|
|
|
ShowPopupMenuEx(m_hWnd, m_hWnd, 0, ID_INSTALL, ppt);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::CreateToolbar()
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
m_Toolbar = new CMainToolbar();
|
|
|
|
m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
|
|
|
|
m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
|
|
|
|
m_Panel->Children().Append(m_Toolbar);
|
|
|
|
|
|
|
|
return m_Toolbar->Create(m_hWnd) != NULL;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::CreateSearchBar()
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
m_SearchBar = new CUiWindow<CSearchBar>();
|
|
|
|
m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
|
|
|
|
m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
|
|
|
|
m_SearchBar->m_Margin.top = 4;
|
|
|
|
m_SearchBar->m_Margin.right = TOOLBAR_PADDING;
|
|
|
|
|
|
|
|
return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::CreateComboBox()
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
|
|
|
m_ComboBox = new CUiWindow<CComboBox>();
|
|
|
|
m_ComboBox->m_VerticalAlignment = UiAlign_LeftTop;
|
|
|
|
m_ComboBox->m_HorizontalAlignment = UiAlign_RightBtm;
|
|
|
|
m_ComboBox->m_Margin.top = 4;
|
|
|
|
|
|
|
|
return m_ComboBox->Create(m_Toolbar->m_hWnd) != NULL;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::CreateHSplitter()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
m_HSplitter = new CUiSplitPanel();
|
|
|
|
m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
|
|
|
|
m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
|
|
|
|
m_HSplitter->m_DynamicFirst = TRUE;
|
|
|
|
m_HSplitter->m_Horizontal = TRUE;
|
2023-02-20 18:30:02 +00:00
|
|
|
m_HSplitter->m_Pos = INT_MAX; // set INT_MAX to use lowest possible position (m_MinSecond)
|
2020-07-24 08:07:43 +00:00
|
|
|
m_HSplitter->m_MinFirst = 10;
|
|
|
|
m_HSplitter->m_MinSecond = 140;
|
|
|
|
m_Panel->Children().Append(m_HSplitter);
|
|
|
|
|
|
|
|
return m_HSplitter->Create(m_hWnd) != NULL;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::CreateListView()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
m_ListView = new CAppsListView();
|
|
|
|
m_ListView->m_VerticalAlignment = UiAlign_Stretch;
|
|
|
|
m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
|
|
|
|
m_HSplitter->First().Append(m_ListView);
|
|
|
|
|
|
|
|
return m_ListView->Create(m_hWnd) != NULL;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::CreateAppInfoDisplay()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
m_AppsInfo = new CAppInfoDisplay();
|
|
|
|
m_AppsInfo->m_VerticalAlignment = UiAlign_Stretch;
|
|
|
|
m_AppsInfo->m_HorizontalAlignment = UiAlign_Stretch;
|
|
|
|
m_HSplitter->Second().Append(m_AppsInfo);
|
|
|
|
|
|
|
|
return m_AppsInfo->Create(m_hWnd) != NULL;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
void
|
|
|
|
CApplicationView::SetRedraw(BOOL bRedraw)
|
2021-09-30 18:19:21 +00:00
|
|
|
{
|
|
|
|
CWindow::SetRedraw(bRedraw);
|
|
|
|
m_ListView->SetRedraw(bRedraw);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
void
|
|
|
|
CApplicationView::SetFocusOnSearchBar()
|
2021-12-07 17:36:49 +00:00
|
|
|
{
|
|
|
|
m_SearchBar->SetFocus();
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CApplicationView::OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
if (wParam == SIZE_MINIMIZED)
|
|
|
|
return;
|
|
|
|
|
2024-03-22 20:55:43 +00:00
|
|
|
/* Resize the toolbar */
|
2020-07-29 10:50:57 +00:00
|
|
|
m_Toolbar->AutoSize();
|
|
|
|
|
|
|
|
/* Automatically hide captions */
|
|
|
|
DWORD dToolbarTreshold = m_Toolbar->GetMaxButtonsWidth();
|
|
|
|
DWORD dSearchbarMargin = (LOWORD(lParam) - m_SearchBar->m_Width - m_ComboBox->m_Width - TOOLBAR_PADDING * 2);
|
|
|
|
|
|
|
|
if (dSearchbarMargin > dToolbarTreshold)
|
|
|
|
{
|
2024-03-22 20:58:35 +00:00
|
|
|
m_Toolbar->ShowButtonCaption(true);
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
else if (dSearchbarMargin < dToolbarTreshold)
|
|
|
|
{
|
2024-03-22 20:58:35 +00:00
|
|
|
m_Toolbar->ShowButtonCaption(false);
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
|
2020-07-24 08:07:43 +00:00
|
|
|
HDWP hdwp = NULL;
|
|
|
|
INT count = m_Panel->CountSizableChildren();
|
|
|
|
|
|
|
|
hdwp = BeginDeferWindowPos(count);
|
|
|
|
if (hdwp)
|
|
|
|
{
|
|
|
|
hdwp = m_Panel->OnParentSize(r, hdwp);
|
|
|
|
if (hdwp)
|
|
|
|
{
|
|
|
|
EndDeferWindowPos(hdwp);
|
|
|
|
}
|
|
|
|
}
|
2020-07-29 10:50:57 +00:00
|
|
|
|
|
|
|
count = m_SearchBar->CountSizableChildren();
|
|
|
|
hdwp = BeginDeferWindowPos(count);
|
|
|
|
if (hdwp)
|
|
|
|
{
|
|
|
|
hdwp = m_SearchBar->OnParentSize(r, hdwp);
|
|
|
|
if (hdwp)
|
|
|
|
{
|
|
|
|
EndDeferWindowPos(hdwp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ComboBox->m_Margin.right = m_SearchBar->m_Width + m_SearchBar->m_Margin.right + TOOLBAR_PADDING;
|
|
|
|
count = m_ComboBox->CountSizableChildren();
|
|
|
|
hdwp = BeginDeferWindowPos(count);
|
|
|
|
if (hdwp)
|
|
|
|
{
|
|
|
|
hdwp = m_ComboBox->OnParentSize(r, hdwp);
|
|
|
|
if (hdwp)
|
|
|
|
{
|
|
|
|
EndDeferWindowPos(hdwp);
|
|
|
|
}
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CApplicationView::OnCommand(WPARAM wParam, LPARAM lParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2020-07-29 10:50:57 +00:00
|
|
|
if (lParam)
|
|
|
|
{
|
|
|
|
if ((HWND)lParam == m_SearchBar->GetWindow())
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szBuf;
|
2020-07-29 10:50:57 +00:00
|
|
|
switch (HIWORD(wParam))
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case EN_SETFOCUS:
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szWndText;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
|
|
|
szBuf.LoadStringW(IDS_SEARCH_TEXT);
|
2023-02-20 18:30:02 +00:00
|
|
|
m_SearchBar->GetWindowTextW(szWndText);
|
|
|
|
if (szBuf == szWndText)
|
|
|
|
{
|
|
|
|
m_SearchBar->SetWindowTextW(L"");
|
|
|
|
}
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case EN_KILLFOCUS:
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
m_SearchBar->GetWindowTextW(szBuf);
|
|
|
|
if (szBuf.IsEmpty())
|
|
|
|
{
|
|
|
|
szBuf.LoadStringW(IDS_SEARCH_TEXT);
|
|
|
|
m_SearchBar->SetWindowTextW(szBuf.GetString());
|
|
|
|
}
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EN_CHANGE:
|
2020-07-29 10:50:57 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
CStringW szWndText;
|
|
|
|
|
|
|
|
szBuf.LoadStringW(IDS_SEARCH_TEXT);
|
|
|
|
m_SearchBar->GetWindowTextW(szWndText);
|
|
|
|
if (szBuf == szWndText)
|
|
|
|
{
|
|
|
|
szWndText = L"";
|
|
|
|
m_MainWindow->SearchTextChanged(szWndText);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_MainWindow->SearchTextChanged(szWndText);
|
|
|
|
}
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
|
2020-08-03 13:54:01 +00:00
|
|
|
return;
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
else if ((HWND)lParam == m_ComboBox->GetWindow())
|
|
|
|
{
|
|
|
|
int NotifyCode = HIWORD(wParam);
|
|
|
|
switch (NotifyCode)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case CBN_SELCHANGE:
|
|
|
|
int CurrSelection = m_ComboBox->SendMessageW(CB_GETCURSEL);
|
2020-07-29 10:50:57 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
int ViewModeList[] = {LV_VIEW_DETAILS, LV_VIEW_LIST, LV_VIEW_TILE};
|
|
|
|
ATLASSERT(CurrSelection < (int)_countof(ViewModeList));
|
|
|
|
if (!m_ListView->SetViewMode(ViewModeList[CurrSelection]))
|
|
|
|
{
|
|
|
|
MessageBoxW(L"View mode invalid or unimplemented");
|
|
|
|
}
|
|
|
|
break;
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
2020-08-03 13:54:01 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ((HWND)lParam == m_Toolbar->GetWindow())
|
|
|
|
{
|
|
|
|
// the message is sent from Toolbar. fall down to continue process
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
2020-07-29 10:50:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2020-08-03 13:54:01 +00:00
|
|
|
// the LOWORD of wParam contains a Menu or Control ID
|
|
|
|
WORD wCommand = LOWORD(wParam);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2020-08-03 13:54:01 +00:00
|
|
|
switch (wCommand)
|
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case ID_INSTALL:
|
|
|
|
case ID_UNINSTALL:
|
|
|
|
case ID_MODIFY:
|
|
|
|
case ID_REGREMOVE:
|
|
|
|
case ID_REFRESH:
|
|
|
|
case ID_RESETDB:
|
|
|
|
case ID_CHECK_ALL:
|
|
|
|
m_MainWindow->SendMessageW(WM_COMMAND, wCommand, 0);
|
|
|
|
break;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
CApplicationView::CApplicationView(CMainWindow *MainWindow) : m_MainWindow(MainWindow)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CApplicationView::~CApplicationView()
|
|
|
|
{
|
2020-07-29 10:50:57 +00:00
|
|
|
delete m_Toolbar;
|
|
|
|
delete m_SearchBar;
|
2020-07-24 08:07:43 +00:00
|
|
|
delete m_ListView;
|
|
|
|
delete m_AppsInfo;
|
|
|
|
delete m_HSplitter;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
ATL::CWndClassInfo &
|
|
|
|
CApplicationView::GetWndClassInfo()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
|
2023-02-20 18:30:02 +00:00
|
|
|
static ATL::CWndClassInfo wc = {
|
|
|
|
{sizeof(WNDCLASSEX), csStyle, StartWindowProc, 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_BTNFACE + 1), NULL,
|
|
|
|
L"RAppsApplicationView", NULL},
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
IDC_ARROW,
|
|
|
|
TRUE,
|
|
|
|
0,
|
|
|
|
_T("")};
|
2020-07-24 08:07:43 +00:00
|
|
|
return wc;
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
HWND
|
|
|
|
CApplicationView::Create(HWND hwndParent)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
RECT r = {0, 0, 0, 0};
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-03-22 12:06:52 +00:00
|
|
|
// Pick the "Programs" sub-menu for building the context menu.
|
|
|
|
HMENU hMenu = ::GetSubMenu(m_MainWindow->GetMenu(), 1);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2024-03-22 12:06:52 +00:00
|
|
|
return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, hMenu);
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
|
|
|
CApplicationView::SetDisplayAppType(APPLICATION_VIEW_TYPE AppType)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2020-07-29 10:50:57 +00:00
|
|
|
if (!m_ListView->SetDisplayAppType(AppType))
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2020-07-29 10:50:57 +00:00
|
|
|
ApplicationViewType = AppType;
|
2024-09-16 16:26:09 +00:00
|
|
|
m_AppsInfo->SetWelcomeText(m_MainWindow->m_bAppwizMode);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
|
|
|
HMENU hMenu = ::GetMenu(m_hWnd);
|
2020-07-29 10:50:57 +00:00
|
|
|
switch (AppType)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
case AppViewTypeInstalledApps:
|
2024-03-22 17:20:35 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
EnableMenuItem(hMenu, ID_INSTALL, MF_GRAYED);
|
|
|
|
EnableMenuItem(hMenu, ID_UNINSTALL, MF_ENABLED);
|
|
|
|
EnableMenuItem(hMenu, ID_MODIFY, MF_ENABLED);
|
2024-03-22 17:20:35 +00:00
|
|
|
EnableMenuItem(hMenu, ID_REGREMOVE, MF_ENABLED);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
|
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
|
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
|
2024-03-22 17:20:35 +00:00
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_CHECK_ALL, FALSE);
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2024-03-22 17:20:35 +00:00
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
case AppViewTypeAvailableApps:
|
2024-03-22 17:20:35 +00:00
|
|
|
{
|
|
|
|
// We shouldn't get there in APPWIZ-mode.
|
|
|
|
ATLASSERT(!m_MainWindow->m_bAppwizMode);
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
EnableMenuItem(hMenu, ID_INSTALL, MF_ENABLED);
|
|
|
|
EnableMenuItem(hMenu, ID_UNINSTALL, MF_GRAYED);
|
|
|
|
EnableMenuItem(hMenu, ID_MODIFY, MF_GRAYED);
|
2024-03-22 17:20:35 +00:00
|
|
|
EnableMenuItem(hMenu, ID_REGREMOVE, MF_GRAYED);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
|
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
|
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
|
2024-03-22 17:20:35 +00:00
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_CHECK_ALL, TRUE);
|
2023-02-20 18:30:02 +00:00
|
|
|
break;
|
2024-03-22 17:20:35 +00:00
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
2023-02-20 18:30:02 +00:00
|
|
|
return TRUE;
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL
|
2023-02-28 00:00:29 +00:00
|
|
|
CApplicationView::AddApplication(CAppInfo *AppInfo, BOOL InitialCheckState)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
return m_ListView->AddApplication(AppInfo, InitialCheckState);
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CApplicationView::SetWatermark(const CStringW &Text)
|
2021-12-30 19:17:32 +00:00
|
|
|
{
|
|
|
|
m_ListView->SetWatermark(Text);
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
void
|
|
|
|
CApplicationView::CheckAll()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
m_ListView->CheckAll();
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
PVOID
|
|
|
|
CApplicationView::GetFocusedItemData()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
return m_ListView->GetFocusedItemData();
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
int
|
|
|
|
CApplicationView::GetItemCount()
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
return m_ListView->GetItemCount();
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CApplicationView::AppendTabOrderWindow(int Direction, ATL::CSimpleArray<HWND> &TabOrderList)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2020-07-29 10:50:57 +00:00
|
|
|
m_Toolbar->AppendTabOrderWindow(Direction, TabOrderList);
|
|
|
|
m_ComboBox->AppendTabOrderWindow(Direction, TabOrderList);
|
|
|
|
m_SearchBar->AppendTabOrderWindow(Direction, TabOrderList);
|
2020-07-24 08:07:43 +00:00
|
|
|
m_ListView->AppendTabOrderWindow(Direction, TabOrderList);
|
|
|
|
m_AppsInfo->AppendTabOrderWindow(Direction, TabOrderList);
|
|
|
|
}
|
|
|
|
|
2024-08-22 21:21:59 +00:00
|
|
|
VOID
|
|
|
|
CApplicationView::GetRestoreListSelectionData(RESTORELISTSELECTION &Restore)
|
|
|
|
{
|
|
|
|
LVITEMW &Item = Restore.Item;
|
|
|
|
Item.mask = LVIF_TEXT|LVIF_STATE;
|
|
|
|
Item.iItem = -1, Item.iSubItem = 0;
|
|
|
|
Item.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
|
|
|
|
Item.pszText = Restore.Name, Item.cchTextMax = _countof(Restore.Name);
|
|
|
|
|
|
|
|
HWND hList = m_ListView ? m_ListView->m_hWnd : NULL;
|
|
|
|
if (hList)
|
|
|
|
{
|
|
|
|
Item.iItem = ListView_GetNextItem(hList, -1, LVNI_FOCUSED);
|
|
|
|
ListView_GetItem(hList, &Item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
CApplicationView::RestoreListSelection(const RESTORELISTSELECTION &Restore)
|
|
|
|
{
|
|
|
|
const LVITEMW &Item = Restore.Item;
|
|
|
|
int index = Item.iItem;
|
|
|
|
if (index != -1) // Was there a selected item?
|
|
|
|
{
|
|
|
|
LVFINDINFOW fi;
|
|
|
|
fi.flags = LVFI_STRING;
|
|
|
|
fi.psz = Item.pszText;
|
|
|
|
index = ListView_FindItem(m_ListView->m_hWnd, -1, &fi);
|
|
|
|
}
|
|
|
|
if (index != -1) // Is it still in the list?
|
|
|
|
{
|
|
|
|
ListView_SetItemState(m_ListView->m_hWnd, index, Item.state, Item.stateMask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-24 08:07:43 +00:00
|
|
|
// this function is called when a item of listview get focus.
|
|
|
|
// CallbackParam is the param passed to listview when adding the item (the one getting focus now).
|
2023-02-20 18:30:02 +00:00
|
|
|
VOID
|
|
|
|
CApplicationView::ItemGetFocus(LPVOID CallbackParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-20 18:30:02 +00:00
|
|
|
if (CallbackParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
2023-02-28 00:00:29 +00:00
|
|
|
CAppInfo *Info = static_cast<CAppInfo *>(CallbackParam);
|
2023-02-20 18:30:02 +00:00
|
|
|
m_AppsInfo->ShowAppInfo(Info);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
if (ApplicationViewType == AppViewTypeInstalledApps)
|
|
|
|
{
|
|
|
|
HMENU hMenu = ::GetMenu(m_hWnd);
|
2020-07-24 08:07:43 +00:00
|
|
|
|
2023-02-20 18:30:02 +00:00
|
|
|
BOOL CanModify = Info->CanModify();
|
|
|
|
|
|
|
|
EnableMenuItem(hMenu, ID_MODIFY, CanModify ? MF_ENABLED : MF_GRAYED);
|
|
|
|
m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, CanModify);
|
|
|
|
}
|
2020-07-24 08:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// this function is called when a item of listview is checked/unchecked
|
2023-02-20 18:30:02 +00:00
|
|
|
// CallbackParam is the param passed to listview when adding the item (the one getting changed now).
|
|
|
|
VOID
|
|
|
|
CApplicationView::ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam)
|
2020-07-24 08:07:43 +00:00
|
|
|
{
|
|
|
|
m_MainWindow->ItemCheckStateChanged(bChecked, CallbackParam);
|
|
|
|
}
|
|
|
|
// **** CApplicationView ****
|