mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[RAPPS] Screenshot preview and other trivial fixes (#2894)
* add one more layer of window * using Path* API to operate path * always use rappmgr.cab as file name when downloading db. ignore the URL * add snapshot preview window * show a broken-image icon when failed to load image * add a padding between image and content, and make sure always some space is reserved for richedit * hide the padding if snapshot window does not have a width * some work to avoid blinking when window resizing * add WM_PRINTCLIENT handling
This commit is contained in:
parent
eacaf65459
commit
fbf119fde1
11 changed files with 574 additions and 69 deletions
|
@ -39,7 +39,7 @@ add_rc_deps(rapps.rc ${rapps_rc_deps})
|
|||
add_executable(rapps ${SOURCE} rapps.rc)
|
||||
set_module_type(rapps win32gui UNICODE)
|
||||
target_link_libraries(rapps uuid wine)
|
||||
add_importlibs(rapps advapi32 comctl32 gdi32 wininet user32 shell32 shlwapi ole32 setupapi msvcrt kernel32 ntdll)
|
||||
add_importlibs(rapps advapi32 comctl32 gdi32 wininet user32 shell32 shlwapi ole32 setupapi gdiplus msvcrt kernel32 ntdll)
|
||||
add_pch(rapps include/rapps.h SOURCE)
|
||||
add_dependencies(rapps rappsmsg)
|
||||
add_message_headers(ANSI rappsmsg.mc)
|
||||
|
|
|
@ -18,23 +18,23 @@
|
|||
#include <atlstr.h>
|
||||
|
||||
// CAvailableApplicationInfo
|
||||
CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam)
|
||||
CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam, AvailableStrings& AvlbStrings)
|
||||
: m_IsSelected(FALSE), m_LicenseType(LICENSE_NONE), m_SizeBytes(0), m_sFileName(sFileNameParam),
|
||||
m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE)
|
||||
{
|
||||
RetrieveGeneralInfo();
|
||||
RetrieveGeneralInfo(AvlbStrings);
|
||||
}
|
||||
|
||||
VOID CAvailableApplicationInfo::RefreshAppInfo()
|
||||
VOID CAvailableApplicationInfo::RefreshAppInfo(AvailableStrings& AvlbStrings)
|
||||
{
|
||||
if (m_szUrlDownload.IsEmpty())
|
||||
{
|
||||
RetrieveGeneralInfo();
|
||||
RetrieveGeneralInfo(AvlbStrings);
|
||||
}
|
||||
}
|
||||
|
||||
// Lazily load general info from the file
|
||||
VOID CAvailableApplicationInfo::RetrieveGeneralInfo()
|
||||
VOID CAvailableApplicationInfo::RetrieveGeneralInfo(AvailableStrings& AvlbStrings)
|
||||
{
|
||||
m_Parser = new CConfigParser(m_sFileName);
|
||||
|
||||
|
@ -52,10 +52,31 @@ VOID CAvailableApplicationInfo::RetrieveGeneralInfo()
|
|||
GetString(L"License", m_szLicense);
|
||||
GetString(L"Description", m_szDesc);
|
||||
GetString(L"URLSite", m_szUrlSite);
|
||||
GetString(L"CDPath", m_szCDPath);
|
||||
GetString(L"Language", m_szRegName);
|
||||
GetString(L"SHA1", m_szSHA1);
|
||||
|
||||
static_assert(MAX_SNAPSHOT_NUM < 10000, "MAX_SNAPSHOT_NUM is too big");
|
||||
for (int i = 0; i < MAX_SNAPSHOT_NUM; i++)
|
||||
{
|
||||
WCHAR SnapshotField[sizeof("Snapshot") + 4];
|
||||
wsprintfW(SnapshotField, L"Snapshot%d", i + 1);
|
||||
ATL::CStringW SnapshotFileName;
|
||||
if (!GetString(SnapshotField, SnapshotFileName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Add URL Support
|
||||
|
||||
// TODO: Does the filename contain anything stuff like "\\" ".." ":" "<" ">" ?
|
||||
// these stuff may lead to security issues
|
||||
|
||||
ATL::CStringW SnapshotName = AvlbStrings.szAppsPath;
|
||||
PathAppendW(SnapshotName.GetBuffer(MAX_PATH), L"snapshots");
|
||||
PathAppendW(SnapshotName.GetBuffer(), SnapshotFileName.GetString());
|
||||
SnapshotName.ReleaseBuffer();
|
||||
m_szSnapshotFilename.Add(SnapshotName);
|
||||
}
|
||||
|
||||
RetrieveSize();
|
||||
RetrieveLicenseType();
|
||||
RetrieveLanguages();
|
||||
|
@ -209,6 +230,16 @@ BOOL CAvailableApplicationInfo::HasUpdate() const
|
|||
return (m_szInstalledVersion.Compare(m_szVersion) < 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
BOOL CAvailableApplicationInfo::RetrieveSnapshot(UINT Index,ATL::CStringW& SnapshotFileName) const
|
||||
{
|
||||
if (Index >= (UINT)m_szSnapshotFilename.GetSize())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
SnapshotFileName = m_szSnapshotFilename[Index];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID CAvailableApplicationInfo::SetLastWriteTime(FILETIME* ftTime)
|
||||
{
|
||||
RtlCopyMemory(&m_ftCacheStamp, ftTime, sizeof(FILETIME));
|
||||
|
@ -231,11 +262,19 @@ AvailableStrings::AvailableStrings()
|
|||
//FIXME: maybe provide a fallback?
|
||||
if (GetStorageDirectory(szPath))
|
||||
{
|
||||
szAppsPath = szPath + L"\\rapps\\";
|
||||
szAppsPath = szPath;
|
||||
PathAppendW(szAppsPath.GetBuffer(MAX_PATH), L"rapps");
|
||||
szAppsPath.ReleaseBuffer();
|
||||
|
||||
szCabName = L"rappmgr.cab";
|
||||
szCabDir = szPath;
|
||||
szCabPath = (szCabDir + L"\\") + szCabName;
|
||||
szSearchPath = szAppsPath + L"*.txt";
|
||||
szCabPath = szCabDir;
|
||||
PathAppendW(szCabPath.GetBuffer(MAX_PATH), szCabName);
|
||||
szCabPath.ReleaseBuffer();
|
||||
|
||||
szSearchPath = szAppsPath;
|
||||
PathAppendW(szSearchPath.GetBuffer(MAX_PATH), L"*.txt");
|
||||
szSearchPath.ReleaseBuffer();
|
||||
}
|
||||
}
|
||||
// AvailableStrings
|
||||
|
@ -273,7 +312,9 @@ VOID CAvailableApps::DeleteCurrentAppsDB()
|
|||
ATL::CStringW szTmp;
|
||||
do
|
||||
{
|
||||
szTmp = m_Strings.szAppsPath + FindFileData.cFileName;
|
||||
szTmp = m_Strings.szAppsPath;
|
||||
PathAppendW(szTmp.GetBuffer(MAX_PATH), FindFileData.cFileName);
|
||||
szTmp.ReleaseBuffer();
|
||||
DeleteFileW(szTmp.GetString());
|
||||
} while (FindNextFileW(hFind, &FindFileData) != 0);
|
||||
FindClose(hFind);
|
||||
|
@ -369,7 +410,7 @@ BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param)
|
|||
}
|
||||
|
||||
// create a new entry
|
||||
Info = new CAvailableApplicationInfo(FindFileData.cFileName);
|
||||
Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
|
||||
|
||||
// set a timestamp for the next time
|
||||
Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
|
||||
|
@ -380,7 +421,7 @@ skip_if_cached:
|
|||
|| EnumType == ENUM_ALL_AVAILABLE
|
||||
|| (EnumType == ENUM_CAT_SELECTED && Info->m_IsSelected))
|
||||
{
|
||||
Info->RefreshAppInfo();
|
||||
Info->RefreshAppInfo(m_Strings);
|
||||
|
||||
if (lpEnumProc)
|
||||
lpEnumProc(Info, m_Strings.szAppsPath.GetString(), param);
|
||||
|
|
|
@ -17,15 +17,48 @@
|
|||
|
||||
#include <atlbase.h>
|
||||
#include <atlcom.h>
|
||||
#include <atltypes.h>
|
||||
#include <atlwin.h>
|
||||
#include <wininet.h>
|
||||
#include <shellutils.h>
|
||||
#include <rosctrls.h>
|
||||
#include <gdiplus.h>
|
||||
#include <math.h>
|
||||
|
||||
using namespace Gdiplus;
|
||||
|
||||
#define SEARCH_TIMER_ID 'SR'
|
||||
#define LISTVIEW_ICON_SIZE 24
|
||||
#define TREEVIEW_ICON_SIZE 24
|
||||
|
||||
// default broken-image icon size
|
||||
#define BROKENIMG_ICON_SIZE 96
|
||||
|
||||
// the boundary of w/h ratio of snapshot preview window
|
||||
#define SNPSHT_MAX_ASPECT_RAT 2.5
|
||||
|
||||
// padding between snapshot preview and richedit (in pixel)
|
||||
#define INFO_DISPLAY_PADDING 10
|
||||
|
||||
// minimum width of richedit
|
||||
#define RICHEDIT_MIN_WIDTH 160
|
||||
|
||||
enum SNPSHT_STATUS
|
||||
{
|
||||
SNPSHTPREV_EMPTY, // show nothing
|
||||
SNPSHTPREV_LOADING, // image is loading (most likely downloading)
|
||||
SNPSHTPREV_FILE, // display image from a file
|
||||
SNPSHTPREV_FAILED // image can not be shown (download failure or wrong image)
|
||||
};
|
||||
|
||||
#define TIMER_LOADING_ANIMATION 1 // Timer ID
|
||||
|
||||
#define LOADING_ANIMATION_PERIOD 3 // Animation cycling period (in seconds)
|
||||
#define LOADING_ANIMATION_FPS 18 // Animation Frame Per Second
|
||||
|
||||
|
||||
#define PI 3.1415927
|
||||
|
||||
INT GetSystemColorDepth()
|
||||
{
|
||||
DEVMODEW pDevMode;
|
||||
|
@ -257,6 +290,322 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CAppSnapshotPreview :
|
||||
public CWindowImpl<CAppSnapshotPreview>
|
||||
{
|
||||
private:
|
||||
|
||||
SNPSHT_STATUS SnpshtPrevStauts = SNPSHTPREV_EMPTY;
|
||||
Image* pImage = NULL;
|
||||
HICON hBrokenImgIcon = NULL;
|
||||
BOOL bLoadingTimerOn = FALSE;
|
||||
int LoadingAnimationFrame = 0;
|
||||
int BrokenImgSize = BROKENIMG_ICON_SIZE;
|
||||
|
||||
BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
|
||||
{
|
||||
theResult = 0;
|
||||
switch (Msg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
hBrokenImgIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_BROKEN_IMAGE), IMAGE_ICON, BrokenImgSize, BrokenImgSize, 0);
|
||||
break;
|
||||
case WM_SIZE:
|
||||
{
|
||||
if (BrokenImgSize != min(min(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)), BROKENIMG_ICON_SIZE))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(&ps);
|
||||
CRect rect;
|
||||
GetClientRect(&rect);
|
||||
|
||||
PaintOnDC(hdc,
|
||||
rect.Width(),
|
||||
rect.Height(),
|
||||
ps.fErase);
|
||||
|
||||
EndPaint(&ps);
|
||||
break;
|
||||
}
|
||||
case WM_PRINTCLIENT:
|
||||
{
|
||||
if (lParam & PRF_CHECKVISIBLE)
|
||||
{
|
||||
if (!IsWindowVisible()) break;
|
||||
}
|
||||
CRect rect;
|
||||
GetClientRect(&rect);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID SetStatus(SNPSHT_STATUS Status)
|
||||
{
|
||||
SnpshtPrevStauts = Status;
|
||||
}
|
||||
|
||||
VOID PaintOnDC(HDC hdc, int width, int height, BOOL bDrawBkgnd)
|
||||
{
|
||||
// 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 (SnpshtPrevStauts)
|
||||
{
|
||||
case SNPSHTPREV_EMPTY:
|
||||
{
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case SNPSHTPREV_LOADING:
|
||||
{
|
||||
Graphics graphics(hdcMem);
|
||||
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;
|
||||
|
||||
case SNPSHTPREV_FILE:
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SNPSHTPREV_FAILED:
|
||||
{
|
||||
DrawIconEx(hdcMem,
|
||||
(width - BrokenImgSize) / 2,
|
||||
(height - BrokenImgSize) / 2,
|
||||
hBrokenImgIcon,
|
||||
BrokenImgSize,
|
||||
BrokenImgSize,
|
||||
NULL,
|
||||
NULL,
|
||||
DI_NORMAL | DI_COMPAT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// copy the content form off-screen dc to hdc
|
||||
BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
}
|
||||
|
||||
float GetLoadingDotWidth(int width, int height)
|
||||
{
|
||||
return min(width, height) / 20.0;
|
||||
}
|
||||
|
||||
float GetFrameDotShift(int Frame, int width, int height)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public:
|
||||
static ATL::CWndClassInfo& GetWndClassInfo()
|
||||
{
|
||||
DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
|
||||
static ATL::CWndClassInfo wc =
|
||||
{
|
||||
{
|
||||
sizeof(WNDCLASSEX),
|
||||
csStyle,
|
||||
StartWindowProc,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
LoadCursorW(NULL, IDC_ARROW),
|
||||
(HBRUSH)(COLOR_BTNFACE + 1),
|
||||
0,
|
||||
L"RAppsSnapshotPreview",
|
||||
NULL
|
||||
},
|
||||
NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
|
||||
};
|
||||
return wc;
|
||||
}
|
||||
|
||||
HWND Create(HWND hParent)
|
||||
{
|
||||
RECT r = { 0,0,0,0 };
|
||||
|
||||
return CWindowImpl::Create(hParent, r, L"", WS_CHILD | WS_VISIBLE);
|
||||
}
|
||||
|
||||
VOID PreviousDisplayCleanup()
|
||||
{
|
||||
if (bLoadingTimerOn)
|
||||
{
|
||||
KillTimer(TIMER_LOADING_ANIMATION);
|
||||
bLoadingTimerOn = FALSE;
|
||||
}
|
||||
LoadingAnimationFrame = 0;
|
||||
if (pImage)
|
||||
{
|
||||
delete pImage;
|
||||
pImage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VOID DisplayEmpty()
|
||||
{
|
||||
SetStatus(SNPSHTPREV_EMPTY);
|
||||
PreviousDisplayCleanup();
|
||||
}
|
||||
|
||||
VOID DisplayLoading()
|
||||
{
|
||||
SetStatus(SNPSHTPREV_LOADING);
|
||||
PreviousDisplayCleanup();
|
||||
bLoadingTimerOn = TRUE;
|
||||
SetTimer(TIMER_LOADING_ANIMATION, 1000 / LOADING_ANIMATION_FPS, 0);
|
||||
}
|
||||
|
||||
BOOL DisplayFile(LPCWSTR lpszFileName)
|
||||
{
|
||||
SetStatus(SNPSHTPREV_FILE);
|
||||
PreviousDisplayCleanup();
|
||||
pImage = Bitmap::FromFile(lpszFileName, 0);
|
||||
if (pImage->GetLastStatus() != Ok)
|
||||
{
|
||||
DisplayFailed();
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID DisplayFailed()
|
||||
{
|
||||
SetStatus(SNPSHTPREV_FAILED);
|
||||
PreviousDisplayCleanup();
|
||||
}
|
||||
|
||||
int GetRequestedWidth(int Height) // calculate requested window width by given height
|
||||
{
|
||||
switch (SnpshtPrevStauts)
|
||||
{
|
||||
case SNPSHTPREV_EMPTY:
|
||||
return 0;
|
||||
case SNPSHTPREV_LOADING:
|
||||
return 200;
|
||||
case SNPSHTPREV_FILE:
|
||||
if (pImage)
|
||||
{
|
||||
// return the width needed to display image inside the window.
|
||||
// and always keep window w/h ratio inside [ 1/SNPSHT_MAX_ASPECT_RAT, SNPSHT_MAX_ASPECT_RAT ]
|
||||
return (int)floor((float)Height *
|
||||
max(min((float)pImage->GetWidth() / (float)pImage->GetHeight(), (float)SNPSHT_MAX_ASPECT_RAT), 1.0/ (float)SNPSHT_MAX_ASPECT_RAT));
|
||||
}
|
||||
return 0;
|
||||
case SNPSHTPREV_FAILED:
|
||||
return 200;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
~CAppSnapshotPreview()
|
||||
{
|
||||
PreviousDisplayCleanup();
|
||||
}
|
||||
};
|
||||
|
||||
class CAppInfoDisplay :
|
||||
public CUiWindow<CWindowImpl<CAppInfoDisplay>>
|
||||
{
|
||||
|
@ -272,16 +621,18 @@ private:
|
|||
{
|
||||
RichEdit = new CAppRichEdit();
|
||||
RichEdit->Create(hwnd);
|
||||
|
||||
SnpshtPrev = new CAppSnapshotPreview();
|
||||
SnpshtPrev->Create(hwnd);
|
||||
break;
|
||||
}
|
||||
case WM_SIZE:
|
||||
{
|
||||
::MoveWindow(RichEdit->m_hWnd, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), TRUE);
|
||||
ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
break;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
|
||||
OnCommand(wParam, lParam);
|
||||
break;
|
||||
}
|
||||
|
@ -304,9 +655,94 @@ private:
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
VOID ResizeChildren()
|
||||
{
|
||||
CRect rect;
|
||||
GetWindowRect(&rect);
|
||||
ResizeChildren(rect.Width(), rect.Height());
|
||||
}
|
||||
|
||||
VOID ResizeChildren(int Width, int Height)
|
||||
{
|
||||
int SnpshtWidth = SnpshtPrev->GetRequestedWidth(Height);
|
||||
|
||||
// make sure richedit always have room to display
|
||||
SnpshtWidth = min(SnpshtWidth, Width - INFO_DISPLAY_PADDING - RICHEDIT_MIN_WIDTH);
|
||||
|
||||
DWORD dwError = ERROR_SUCCESS;
|
||||
HDWP hDwp = BeginDeferWindowPos(2);
|
||||
|
||||
if (hDwp)
|
||||
{
|
||||
hDwp = ::DeferWindowPos(hDwp, SnpshtPrev->m_hWnd, NULL,
|
||||
0, 0, SnpshtWidth, Height, 0);
|
||||
|
||||
if (hDwp)
|
||||
{
|
||||
// hide the padding if snapshot window width == 0
|
||||
int RicheditPosX = SnpshtWidth ? (SnpshtWidth + INFO_DISPLAY_PADDING) : 0;
|
||||
|
||||
hDwp = ::DeferWindowPos(hDwp, RichEdit->m_hWnd, NULL,
|
||||
RicheditPosX, 0, Width - RicheditPosX, Height, 0);
|
||||
|
||||
if (hDwp)
|
||||
{
|
||||
EndDeferWindowPos(hDwp);
|
||||
}
|
||||
else
|
||||
{
|
||||
dwError = GetLastError();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dwError = GetLastError();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dwError = GetLastError();
|
||||
}
|
||||
|
||||
|
||||
#if DBG
|
||||
ATLASSERT(dwError == ERROR_SUCCESS);
|
||||
#endif
|
||||
|
||||
UpdateWindow();
|
||||
}
|
||||
|
||||
VOID OnLink(ENLINK* Link)
|
||||
{
|
||||
switch (Link->msg)
|
||||
{
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
|
||||
RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM)pLink);
|
||||
|
||||
ShowPopupMenuEx(m_hWnd, m_hWnd, IDR_LINKMENU, -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
CAppRichEdit * RichEdit;
|
||||
CAppSnapshotPreview * SnpshtPrev;
|
||||
|
||||
static ATL::CWndClassInfo& GetWndClassInfo()
|
||||
{
|
||||
|
@ -336,51 +772,38 @@ public:
|
|||
{
|
||||
RECT r = { 0,0,0,0 };
|
||||
|
||||
return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE);
|
||||
return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
|
||||
}
|
||||
|
||||
BOOL ShowAvailableAppInfo(CAvailableApplicationInfo* Info)
|
||||
{
|
||||
ATL::CStringW SnapshotFilename;
|
||||
if (Info->RetrieveSnapshot(0, SnapshotFilename))
|
||||
{
|
||||
SnpshtPrev->DisplayFile(SnapshotFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
SnpshtPrev->DisplayEmpty();
|
||||
}
|
||||
ResizeChildren();
|
||||
return RichEdit->ShowAvailableAppInfo(Info);
|
||||
}
|
||||
|
||||
BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
|
||||
{
|
||||
SnpshtPrev->DisplayEmpty();
|
||||
ResizeChildren();
|
||||
return RichEdit->ShowInstalledAppInfo(Info);
|
||||
}
|
||||
|
||||
VOID SetWelcomeText()
|
||||
{
|
||||
SnpshtPrev->DisplayEmpty();
|
||||
ResizeChildren();
|
||||
RichEdit->SetWelcomeText();
|
||||
}
|
||||
|
||||
VOID OnLink(ENLINK* Link)
|
||||
{
|
||||
switch (Link->msg)
|
||||
{
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
|
||||
RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM)pLink);
|
||||
|
||||
ShowPopupMenuEx(m_hWnd, m_hWnd, IDR_LINKMENU, -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VOID OnCommand(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
WORD wCommand = LOWORD(wParam);
|
||||
|
@ -1804,8 +2227,12 @@ private:
|
|||
}
|
||||
|
||||
/* Load icon from file */
|
||||
ATL::CStringW szIconPath;
|
||||
szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->m_szName.GetString());
|
||||
ATL::CStringW szIconPath = szFolderPath;
|
||||
PathAppendW(szIconPath.GetBuffer(MAX_PATH), L"icons");
|
||||
PathAppendW(szIconPath.GetBuffer(), Info->m_szName.GetString());
|
||||
PathAddExtensionW(szIconPath.GetBuffer(), L".ico");
|
||||
szIconPath.ReleaseBuffer();
|
||||
|
||||
hIcon = (HICON) LoadImageW(NULL,
|
||||
szIconPath.GetString(),
|
||||
IMAGE_ICON,
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
#define MAX_SNAPSHOT_NUM 16
|
||||
|
||||
enum LicenseType
|
||||
{
|
||||
LICENSE_NONE,
|
||||
|
@ -22,6 +25,18 @@ inline BOOL IsLicenseType(INT x)
|
|||
return (x >= LICENSE_MIN && x <= LICENSE_MAX);
|
||||
}
|
||||
|
||||
struct AvailableStrings
|
||||
{
|
||||
ATL::CStringW szPath;
|
||||
ATL::CStringW szCabPath;
|
||||
ATL::CStringW szAppsPath;
|
||||
ATL::CStringW szSearchPath;
|
||||
ATL::CStringW szCabName;
|
||||
ATL::CStringW szCabDir;
|
||||
|
||||
AvailableStrings();
|
||||
};
|
||||
|
||||
struct CAvailableApplicationInfo
|
||||
{
|
||||
INT m_Category;
|
||||
|
@ -35,8 +50,9 @@ struct CAvailableApplicationInfo
|
|||
ATL::CStringW m_szSize;
|
||||
ATL::CStringW m_szUrlSite;
|
||||
ATL::CStringW m_szUrlDownload;
|
||||
ATL::CStringW m_szCDPath;
|
||||
ATL::CSimpleArray<LCID> m_LanguageLCIDs;
|
||||
ATL::CSimpleArray<ATL::CStringW> m_szSnapshotFilename;
|
||||
|
||||
ULONG m_SizeBytes;
|
||||
|
||||
// Caching mechanism related entries
|
||||
|
@ -48,17 +64,17 @@ struct CAvailableApplicationInfo
|
|||
ATL::CStringW m_szInstalledVersion;
|
||||
|
||||
// Create an object from file
|
||||
CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam);
|
||||
CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam, AvailableStrings& m_Strings);
|
||||
|
||||
// Load all info from the file
|
||||
VOID RefreshAppInfo();
|
||||
VOID RefreshAppInfo(AvailableStrings& m_Strings);
|
||||
BOOL HasLanguageInfo() const;
|
||||
BOOL HasNativeLanguage() const;
|
||||
BOOL HasEnglishLanguage() const;
|
||||
BOOL IsInstalled() const;
|
||||
BOOL HasInstalledVersion() const;
|
||||
BOOL HasUpdate() const;
|
||||
|
||||
BOOL RetrieveSnapshot(UINT Index, ATL::CStringW& SnapshotFileName) const;
|
||||
// Set a timestamp
|
||||
VOID SetLastWriteTime(FILETIME* ftTime);
|
||||
|
||||
|
@ -71,7 +87,7 @@ private:
|
|||
inline BOOL GetString(LPCWSTR lpKeyName, ATL::CStringW& ReturnedString);
|
||||
|
||||
// Lazily load general info from the file
|
||||
VOID RetrieveGeneralInfo();
|
||||
VOID RetrieveGeneralInfo(AvailableStrings& m_Strings);
|
||||
VOID RetrieveInstalledStatus();
|
||||
VOID RetrieveInstalledVersion();
|
||||
VOID RetrieveLanguages();
|
||||
|
@ -82,18 +98,6 @@ private:
|
|||
|
||||
typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, LPCWSTR szFolderPath, PVOID param);
|
||||
|
||||
struct AvailableStrings
|
||||
{
|
||||
ATL::CStringW szPath;
|
||||
ATL::CStringW szCabPath;
|
||||
ATL::CStringW szAppsPath;
|
||||
ATL::CStringW szSearchPath;
|
||||
ATL::CStringW szCabName;
|
||||
ATL::CStringW szCabDir;
|
||||
|
||||
AvailableStrings();
|
||||
};
|
||||
|
||||
class CAvailableApps
|
||||
{
|
||||
static AvailableStrings m_Strings;
|
||||
|
|
|
@ -9,7 +9,6 @@ INT GetClientWindowWidth(HWND hwnd);
|
|||
INT GetClientWindowHeight(HWND hwnd);
|
||||
|
||||
VOID CopyTextToClipboard(LPCWSTR lpszText);
|
||||
VOID SetWelcomeText();
|
||||
VOID ShowPopupMenuEx(HWND hwnd, HWND hwndOwner, UINT MenuID, UINT DefaultItem);
|
||||
VOID ShowPopupMenu(HWND hwnd, UINT MenuID, UINT DefaultItem);
|
||||
BOOL StartProcess(ATL::CStringW &Path, BOOL Wait);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#define IDI_UPDATE_DB 20
|
||||
#define IDI_CHECK_ALL 21
|
||||
#define IDI_SELECTEDFORINST 22
|
||||
#define IDI_BROKEN_IMAGE 23
|
||||
|
||||
/* Icons for categories */
|
||||
#define IDI_CAT_AUDIO 50
|
||||
|
|
|
@ -650,8 +650,19 @@ unsigned int WINAPI CDownloadManager::ThreadFunc(LPVOID param)
|
|||
}
|
||||
|
||||
// append a \ to the provided file system path, and the filename portion from the URL after that
|
||||
Path += L"\\";
|
||||
Path += (LPWSTR) (p + 1);
|
||||
|
||||
PathAddBackslashW(Path.GetBuffer(MAX_PATH));
|
||||
switch (InfoArray[iAppId].DLType)
|
||||
{
|
||||
case DLTYPE_DBUPDATE:
|
||||
case DLTYPE_DBUPDATE_UNOFFICIAL:
|
||||
PathAppendW(Path.GetBuffer(), L"rappmgr.cab"); // whatever the URL is, use the file name L"rappmgr.cab"
|
||||
break;
|
||||
case DLTYPE_APPLICATION:
|
||||
PathAppendW(Path.GetBuffer(), (LPWSTR)(p + 1)); // use the filename retrieved from URL
|
||||
break;
|
||||
}
|
||||
Path.ReleaseBuffer();
|
||||
|
||||
if ((InfoArray[iAppId].DLType == DLTYPE_APPLICATION) && InfoArray[iAppId].szSHA1[0] && GetFileAttributesW(Path.GetString()) != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
|
|
|
@ -177,14 +177,15 @@ BOOL StartProcess(LPWSTR lpPath, BOOL Wait)
|
|||
|
||||
BOOL GetStorageDirectory(ATL::CStringW& Directory)
|
||||
{
|
||||
if (!SHGetSpecialFolderPathW(NULL, Directory.GetBuffer(MAX_PATH), CSIDL_LOCAL_APPDATA, TRUE))
|
||||
LPWSTR DirectoryStr = Directory.GetBuffer(MAX_PATH);
|
||||
if (!SHGetSpecialFolderPathW(NULL, DirectoryStr, CSIDL_LOCAL_APPDATA, TRUE))
|
||||
{
|
||||
Directory.ReleaseBuffer();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PathAppendW(DirectoryStr, L"rapps");
|
||||
Directory.ReleaseBuffer();
|
||||
Directory += L"\\rapps";
|
||||
|
||||
return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ IDI_APPUPD ICON "res/appupd.ico"
|
|||
IDI_CATEGORY ICON "res/cat.ico"
|
||||
IDI_UPDATE_DB ICON "res/updatedb.ico"
|
||||
IDI_CHECK_ALL ICON "res/select.ico"
|
||||
IDI_SELECTEDFORINST ICON "res/select.ico"
|
||||
IDI_BROKEN_IMAGE ICON "res/brokenimg.ico"
|
||||
|
||||
/* Categories */
|
||||
IDI_CAT_AUDIO ICON "res/cats/audio.ico"
|
||||
|
@ -41,7 +43,6 @@ IDI_CAT_SCIENCE ICON "res/cats/science.ico"
|
|||
IDI_CAT_TOOLS ICON "res/cats/tools.ico"
|
||||
IDI_CAT_VIDEO ICON "res/cats/video.ico"
|
||||
IDI_CAT_THEMES ICON "res/cats/themes.ico"
|
||||
IDI_SELECTEDFORINST ICON "res/select.ico"
|
||||
|
||||
/* Accelerators -- key bindings */
|
||||
HOTKEYS ACCELERATORS
|
||||
|
|
BIN
base/applications/rapps/res/brokenimg.ico
Normal file
BIN
base/applications/rapps/res/brokenimg.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 149 KiB |
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <atlcom.h>
|
||||
|
||||
#include <gdiplus.h>
|
||||
|
||||
HWND hMainWnd;
|
||||
HINSTANCE hInst;
|
||||
SETTINGS_INFO SettingsInfo;
|
||||
|
@ -28,6 +30,10 @@ END_OBJECT_MAP()
|
|||
CRAppsModule gModule;
|
||||
CAtlWinModule gWinModule;
|
||||
|
||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
||||
ULONG_PTR gdiplusToken;
|
||||
|
||||
|
||||
static VOID InitializeAtlModule(HINSTANCE hInstance, BOOL bInitialize)
|
||||
{
|
||||
if (bInitialize)
|
||||
|
@ -40,6 +46,18 @@ static VOID InitializeAtlModule(HINSTANCE hInstance, BOOL bInitialize)
|
|||
}
|
||||
}
|
||||
|
||||
VOID InitializeGDIPlus(BOOL bInitialize)
|
||||
{
|
||||
if (bInitialize)
|
||||
{
|
||||
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
Gdiplus::GdiplusShutdown(gdiplusToken);
|
||||
}
|
||||
}
|
||||
|
||||
VOID FillDefaultSettings(PSETTINGS_INFO pSettingsInfo)
|
||||
{
|
||||
ATL::CStringW szDownloadDir;
|
||||
|
@ -129,6 +147,7 @@ INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
|
|||
BOOL bIsFirstLaunch;
|
||||
|
||||
InitializeAtlModule(hInstance, TRUE);
|
||||
InitializeGDIPlus(TRUE);
|
||||
|
||||
if (GetUserDefaultUILanguage() == MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT))
|
||||
{
|
||||
|
@ -169,6 +188,7 @@ INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
|
|||
if (hMutex)
|
||||
CloseHandle(hMutex);
|
||||
|
||||
InitializeGDIPlus(FALSE);
|
||||
InitializeAtlModule(hInstance, FALSE);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue