1 #pragma once
2 
3 #include "rapps.h"
4 #include "rosui.h"
5 #include "crichedit.h"
6 #include "asyncinet.h"
7 
8 #include <shlobj_undoc.h>
9 #include <shlguid_undoc.h>
10 
11 #include <atlbase.h>
12 #include <atlcom.h>
13 #include <atltypes.h>
14 #include <atlwin.h>
15 #include <wininet.h>
16 #include <shellutils.h>
17 #include <ui/rosctrls.h>
18 #include <gdiplus.h>
19 #include <math.h>
20 
21 extern HICON g_hDefaultPackageIcon;
22 
23 // default broken-image icon size
24 #define BROKENIMG_ICON_SIZE 96
25 
26 // the boundary of w/h ratio of scrnshot preview window
27 #define SCRNSHOT_MAX_ASPECT_RAT 2.5
28 
29 // padding between scrnshot preview and richedit (in pixel)
30 #define INFO_DISPLAY_PADDING 10
31 
32 // minimum width of richedit
33 #define RICHEDIT_MIN_WIDTH 160
34 
35 // padding between controls in toolbar
36 #define TOOLBAR_PADDING 6
37 
38 // user-defined window message
39 #define WM_RAPPS_DOWNLOAD_COMPLETE                                                                                     \
40     (WM_USER + 1) // notify download complete. wParam is error code, and lParam is a pointer to ScrnshotDownloadParam
41 #define WM_RAPPS_RESIZE_CHILDREN (WM_USER + 2) // ask parent window to resize children.
42 #define WM_RAPPSLIST_ASYNCICON (WM_APP + 0)
43 
44 enum SCRNSHOT_STATUS
45 {
46     SCRNSHOT_PREV_EMPTY,   // show nothing
47     SCRNSHOT_PREV_LOADING, // image is loading (most likely downloading)
48     SCRNSHOT_PREV_IMAGE,   // display image from a file
49     SCRNSHOT_PREV_FAILED   // image can not be shown (download failure or wrong image)
50 };
51 
52 #define TIMER_LOADING_ANIMATION 1 // Timer ID
53 
54 #define LOADING_ANIMATION_PERIOD 3 // Animation cycling period (in seconds)
55 #define LOADING_ANIMATION_FPS 18   // Animation Frame Per Second
56 
57 #define PI 3.1415927
58 
59 // retrieve the value using a mask
60 #define STATEIMAGETOINDEX(x) (((x)&LVIS_STATEIMAGEMASK) >> 12)
61 
62 // for listview with extend style LVS_EX_CHECKBOXES, State image 1 is the unchecked box, and state image 2 is the
63 // checked box. see this: https://docs.microsoft.com/en-us/windows/win32/controls/extended-list-view-styles
64 #define STATEIMAGE_UNCHECKED 1
65 #define STATEIMAGE_CHECKED 2
66 
67 class CMainWindow;
68 
69 enum APPLICATION_VIEW_TYPE
70 {
71     AppViewTypeAvailableApps,
72     AppViewTypeInstalledApps
73 };
74 
75 typedef struct __ScrnshotDownloadParam
76 {
77     LONGLONG ID;
78     HANDLE hFile;
79     HWND hwndNotify;
80     CStringW DownloadFileName;
81 } ScrnshotDownloadParam;
82 
83 class CAppRichEdit : public CUiWindow<CRichEdit>
84 {
85   public:
86     VOID
87     LoadAndInsertText(UINT uStringID, const CStringW &szText, DWORD TextFlags);
88     VOID
89     LoadAndInsertText(UINT uStringID, DWORD StringFlags);
90     VOID
91     InsertTextWithString(UINT StringID, const CStringW &Text, DWORD TextFlags);
92     VOID
93     SetWelcomeText();
94 };
95 
96 int
97 ScrnshotDownloadCallback(pASYNCINET AsyncInet, ASYNC_EVENT Event, WPARAM wParam, LPARAM lParam, VOID *Extension);
98 
99 class CAppScrnshotPreview : public CWindowImpl<CAppScrnshotPreview>
100 {
101   private:
102     CStringW m_BasePath;
103     SCRNSHOT_STATUS ScrnshotPrevStauts = SCRNSHOT_PREV_EMPTY;
104     Gdiplus::Image *pImage = NULL;
105     HICON hBrokenImgIcon = NULL;
106     BOOL bLoadingTimerOn = FALSE;
107     int LoadingAnimationFrame = 0;
108     int BrokenImgSize = BROKENIMG_ICON_SIZE;
109     pASYNCINET AsyncInet = NULL;
110     LONGLONG ContentID = 0; // used to determine whether image has been switched when download complete. Increase by 1
111                             // each time the content of this window changed
112     CStringW TempImagePath; // currently displayed temp file
113 
114     BOOL
115     ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId);
116 
117     VOID
118     DisplayLoading();
119     VOID
120     DisplayFailed();
121     BOOL
122     DisplayFile(LPCWSTR lpszFileName);
123     VOID
124     SetStatus(SCRNSHOT_STATUS Status);
125 
126     VOID
127     PaintOnDC(HDC hdc, int width, int height, BOOL bDrawBkgnd);
128     float
129     GetLoadingDotWidth(int width, int height);
130     float
131     GetFrameDotShift(int Frame, int width, int height);
132 
133   public:
134     static ATL::CWndClassInfo &
135     GetWndClassInfo();
136 
137     HWND
138     Create(HWND hParent);
139     VOID
140     PreviousDisplayCleanup();
141     VOID
142     DisplayEmpty();
143     BOOL
144     DisplayImage(LPCWSTR lpszLocation);
145 
146     // calculate requested window width by given height
147     int
148     GetRequestedWidth(int Height);
149 
150     CAppScrnshotPreview(const CStringW &BasePath);
151     ~CAppScrnshotPreview();
152 };
153 
154 class CAppInfoDisplay : public CUiWindow<CWindowImpl<CAppInfoDisplay>>
155 {
156     LPWSTR pLink = NULL;
157 
158   private:
159     BOOL
160     ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId);
161     VOID
162     OnLink(ENLINK *Link);
163 
164     VOID
165     ResizeChildren();
166     VOID
167     ResizeChildren(int Width, int Height);
168 
169   public:
170     CAppRichEdit *RichEdit = NULL;
171     CAppScrnshotPreview *ScrnshotPrev = NULL;
172 
173     static ATL::CWndClassInfo &
174     GetWndClassInfo();
175 
176     HWND
177     Create(HWND hwndParent);
178 
179     VOID
180     ShowAppInfo(CAppInfo *Info);
181     VOID
182     SetWelcomeText();
183     VOID
184     OnCommand(WPARAM wParam, LPARAM lParam);
185 
186     ~CAppInfoDisplay();
187 };
188 
189 class CAppsListView : public CUiWindow<CWindowImpl<CAppsListView, CListView>>
190 {
191     struct SortContext
192     {
193         CAppsListView *lvw;
194         INT iSubItem;
195     };
196 
197     BOOL bIsAscending = TRUE;
198     BOOL bHasCheckboxes = FALSE;
199 
200     INT ItemCount = 0;
201     INT CheckedItemCount = 0;
202     INT ColumnCount = 0;
203 
204     INT nLastHeaderID = -1;
205 
206     APPLICATION_VIEW_TYPE ApplicationViewType = AppViewTypeAvailableApps;
207 
208     HIMAGELIST m_hImageListView = NULL;
209     CStringW m_Watermark;
210 
211     BEGIN_MSG_MAP(CAppsListView)
212     MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
213     MESSAGE_HANDLER(WM_RAPPSLIST_ASYNCICON, OnAsyncIcon)
214     END_MSG_MAP()
215 
216     LRESULT
217     OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
218     LRESULT
219     OnAsyncIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
220 
221   public:
222     CAppsListView();
223     ~CAppsListView();
224 
225     VOID
226     SetWatermark(const CStringW &Text);
227     VOID
228     SetCheckboxesVisible(BOOL bIsVisible);
229 
230     VOID
231     ColumnClick(LPNMLISTVIEW pnmv);
232 
233     BOOL
234     AddColumn(INT Index, CStringW &Text, INT Width, INT Format);
235     void
236     DeleteColumn(INT Index);
237 
238     INT
239     AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam);
240 
241     HIMAGELIST
242     GetImageList(int iImageList);
243 
244     static INT CALLBACK
245     s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
246 
247     INT
248     CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem);
249 
250     HWND
251     Create(HWND hwndParent);
252 
253     BOOL
254     GetCheckState(INT item);
255     VOID
256     SetCheckState(INT item, BOOL fCheck);
257     VOID
258     CheckAll();
259 
260     PVOID
261     GetFocusedItemData();
262 
263     BOOL
264     SetDisplayAppType(APPLICATION_VIEW_TYPE AppType);
265     BOOL
266     SetViewMode(DWORD ViewMode);
267 
268     BOOL
269     AddApplication(CAppInfo *AppInfo, BOOL InitialCheckState);
270 
271     // this function is called when parent window receiving an notification about checkstate changing
272     VOID
273     ItemCheckStateNotify(int iItem, BOOL bCheck);
274 };
275 
276 class CMainToolbar : public CUiWindow<CToolbar<>>
277 {
278     const INT m_iToolbarHeight;
279     DWORD m_dButtonsWidthMax;
280 
281     VOID
282     AddImageToImageList(HIMAGELIST hImageList, UINT ImageIndex);
283 
284     HIMAGELIST
285     InitImageList();
286 
287   public:
288     CMainToolbar();
289 
290     VOID
291     OnGetDispInfo(LPTOOLTIPTEXT lpttt);
292 
293     HWND
294     Create(HWND hwndParent);
295 
296     VOID
297     HideButtonCaption();
298     VOID
299     ShowButtonCaption();
300 
301     DWORD
302     GetMaxButtonsWidth() const;
303 };
304 
305 class CSearchBar : public CWindow
306 {
307   public:
308     const INT m_Width;
309     const INT m_Height;
310 
311     CSearchBar();
312 
313     VOID
314     SetText(LPCWSTR lpszText);
315 
316     HWND
317     Create(HWND hwndParent);
318 };
319 
320 class CComboBox : public CWindow
321 {
322     // ID refers to different types of view
323     enum
324     {
325         m_AppDisplayTypeDetails,
326         m_AppDisplayTypeList,
327         m_AppDisplayTypeTile
328     };
329 
330     // string ID for different. this should correspond with the enum above.
331     const UINT m_TypeStringID[3] = {IDS_APP_DISPLAY_DETAILS, IDS_APP_DISPLAY_LIST, IDS_APP_DISPLAY_TILE};
332 
333     const int m_DefaultSelectType = m_AppDisplayTypeDetails;
334 
335   public:
336     int m_Width;
337     int m_Height;
338 
339     CComboBox();
340 
341     HWND
342     Create(HWND hwndParent);
343 };
344 
345 class CApplicationView : public CUiWindow<CWindowImpl<CApplicationView>>
346 {
347   private:
348     CUiPanel *m_Panel = NULL;
349     CMainToolbar *m_Toolbar = NULL;
350     CUiWindow<CComboBox> *m_ComboBox = NULL;
351     CUiWindow<CSearchBar> *m_SearchBar = NULL;
352     CAppsListView *m_ListView = NULL;
353     CAppInfoDisplay *m_AppsInfo = NULL;
354     CUiSplitPanel *m_HSplitter = NULL;
355     CMainWindow *m_MainWindow = NULL;
356     APPLICATION_VIEW_TYPE ApplicationViewType = AppViewTypeAvailableApps;
357 
358     BOOL
359     ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId);
360 
361     BOOL
362     CreateToolbar();
363     BOOL
364     CreateSearchBar();
365     BOOL
366     CreateComboBox();
367     BOOL
368     CreateHSplitter();
369     BOOL
370     CreateListView();
371     BOOL
372     CreateAppInfoDisplay();
373 
374     VOID
375     OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam);
376     VOID
377     OnCommand(WPARAM wParam, LPARAM lParam);
378 
379   public:
380     CApplicationView(CMainWindow *MainWindow);
381     ~CApplicationView();
382 
383     static ATL::CWndClassInfo &
384     GetWndClassInfo();
385 
386     HWND
387     Create(HWND hwndParent);
388     void
389     SetRedraw(BOOL bRedraw);
390     void
391     SetFocusOnSearchBar();
392     BOOL
393     SetDisplayAppType(APPLICATION_VIEW_TYPE AppType);
394 
395     BOOL
396     AddApplication(CAppInfo *InstAppInfo, BOOL InitialCheckState);
397     VOID
398     SetWatermark(const CStringW &Text);
399 
400     void
401     CheckAll();
402     PVOID
403     GetFocusedItemData();
404     int
405     GetItemCount();
406     VOID
407     AppendTabOrderWindow(int Direction, ATL::CSimpleArray<HWND> &TabOrderList);
408 
409     struct RESTORELISTSELECTION {
410         LVITEMW Item;
411         WCHAR Name[MAX_PATH];
412     };
413     VOID
414     GetRestoreListSelectionData(RESTORELISTSELECTION &Restore);
415     VOID
416     RestoreListSelection(const RESTORELISTSELECTION &Restore);
417 
418     // this function is called when a item of listview get focus.
419     // CallbackParam is the param passed to listview when adding the item (the one getting focus now).
420     VOID
421     ItemGetFocus(LPVOID CallbackParam);
422 
423     // this function is called when a item of listview is checked/unchecked
424     // CallbackParam is the param passed to listview when adding the item (the one getting focus now).
425     VOID
426     ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam);
427 };
428