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 
22 #define LISTVIEW_ICON_SIZE 32
23 
24 // default broken-image icon size
25 #define BROKENIMG_ICON_SIZE 96
26 
27 // the boundary of w/h ratio of scrnshot preview window
28 #define SCRNSHOT_MAX_ASPECT_RAT 2.5
29 
30 // padding between scrnshot preview and richedit (in pixel)
31 #define INFO_DISPLAY_PADDING 10
32 
33 // minimum width of richedit
34 #define RICHEDIT_MIN_WIDTH 160
35 
36 // padding between controls in toolbar
37 #define TOOLBAR_PADDING 6
38 
39 // user-defined window message
40 #define WM_RAPPS_DOWNLOAD_COMPLETE                                                                                     \
41     (WM_USER + 1) // notify download complete. wParam is error code, and lParam is a pointer to ScrnshotDownloadParam
42 #define WM_RAPPS_RESIZE_CHILDREN (WM_USER + 2) // ask parent window to resize children.
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     END_MSG_MAP()
214 
215     LRESULT
216     OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
217 
218   public:
219     CAppsListView();
220     ~CAppsListView();
221 
222     VOID
223     SetWatermark(const CStringW &Text);
224     VOID
225     SetCheckboxesVisible(BOOL bIsVisible);
226 
227     VOID
228     ColumnClick(LPNMLISTVIEW pnmv);
229 
230     BOOL
231     AddColumn(INT Index, CStringW &Text, INT Width, INT Format);
232     void
233     DeleteColumn(INT Index);
234 
235     INT
236     AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam);
237 
238     HIMAGELIST
239     GetImageList(int iImageList);
240 
241     static INT CALLBACK
242     s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
243 
244     INT
245     CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem);
246 
247     HWND
248     Create(HWND hwndParent);
249 
250     BOOL
251     GetCheckState(INT item);
252     VOID
253     SetCheckState(INT item, BOOL fCheck);
254     VOID
255     CheckAll();
256 
257     PVOID
258     GetFocusedItemData();
259 
260     BOOL
261     SetDisplayAppType(APPLICATION_VIEW_TYPE AppType);
262     BOOL
263     SetViewMode(DWORD ViewMode);
264 
265     BOOL
266     AddApplication(CAppInfo *AppInfo, BOOL InitialCheckState);
267 
268     // this function is called when parent window receiving an notification about checkstate changing
269     VOID
270     ItemCheckStateNotify(int iItem, BOOL bCheck);
271 };
272 
273 class CMainToolbar : public CUiWindow<CToolbar<>>
274 {
275     const INT m_iToolbarHeight;
276     DWORD m_dButtonsWidthMax;
277 
278     VOID
279     AddImageToImageList(HIMAGELIST hImageList, UINT ImageIndex);
280 
281     HIMAGELIST
282     InitImageList();
283 
284   public:
285     CMainToolbar();
286 
287     VOID
288     OnGetDispInfo(LPTOOLTIPTEXT lpttt);
289 
290     HWND
291     Create(HWND hwndParent);
292 
293     VOID
294     HideButtonCaption();
295     VOID
296     ShowButtonCaption();
297 
298     DWORD
299     GetMaxButtonsWidth() const;
300 };
301 
302 class CSearchBar : public CWindow
303 {
304   public:
305     const INT m_Width;
306     const INT m_Height;
307 
308     CSearchBar();
309 
310     VOID
311     SetText(LPCWSTR lpszText);
312 
313     HWND
314     Create(HWND hwndParent);
315 };
316 
317 class CComboBox : public CWindow
318 {
319     // ID refers to different types of view
320     enum
321     {
322         m_AppDisplayTypeDetails,
323         m_AppDisplayTypeList,
324         m_AppDisplayTypeTile
325     };
326 
327     // string ID for different. this should correspond with the enum above.
328     const UINT m_TypeStringID[3] = {IDS_APP_DISPLAY_DETAILS, IDS_APP_DISPLAY_LIST, IDS_APP_DISPLAY_TILE};
329 
330     const int m_DefaultSelectType = m_AppDisplayTypeDetails;
331 
332   public:
333     int m_Width;
334     int m_Height;
335 
336     CComboBox();
337 
338     HWND
339     Create(HWND hwndParent);
340 };
341 
342 class CApplicationView : public CUiWindow<CWindowImpl<CApplicationView>>
343 {
344   private:
345     CUiPanel *m_Panel = NULL;
346     CMainToolbar *m_Toolbar = NULL;
347     CUiWindow<CComboBox> *m_ComboBox = NULL;
348     CUiWindow<CSearchBar> *m_SearchBar = NULL;
349     CAppsListView *m_ListView = NULL;
350     CAppInfoDisplay *m_AppsInfo = NULL;
351     CUiSplitPanel *m_HSplitter = NULL;
352     CMainWindow *m_MainWindow = NULL;
353     APPLICATION_VIEW_TYPE ApplicationViewType = AppViewTypeAvailableApps;
354 
355     BOOL
356     ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &theResult, DWORD dwMapId);
357 
358     BOOL
359     CreateToolbar();
360     BOOL
361     CreateSearchBar();
362     BOOL
363     CreateComboBox();
364     BOOL
365     CreateHSplitter();
366     BOOL
367     CreateListView();
368     BOOL
369     CreateAppInfoDisplay();
370 
371     VOID
372     OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam);
373     VOID
374     OnCommand(WPARAM wParam, LPARAM lParam);
375 
376   public:
377     CApplicationView(CMainWindow *MainWindow);
378     ~CApplicationView();
379 
380     static ATL::CWndClassInfo &
381     GetWndClassInfo();
382 
383     HWND
384     Create(HWND hwndParent);
385     void
386     SetRedraw(BOOL bRedraw);
387     void
388     SetFocusOnSearchBar();
389     BOOL
390     SetDisplayAppType(APPLICATION_VIEW_TYPE AppType);
391 
392     BOOL
393     AddApplication(CAppInfo *InstAppInfo, BOOL InitialCheckState);
394     VOID
395     SetWatermark(const CStringW &Text);
396 
397     void
398     CheckAll();
399     PVOID
400     GetFocusedItemData();
401     int
402     GetItemCount();
403     VOID
404     AppendTabOrderWindow(int Direction, ATL::CSimpleArray<HWND> &TabOrderList);
405 
406     // this function is called when a item of listview get focus.
407     // CallbackParam is the param passed to listview when adding the item (the one getting focus now).
408     VOID
409     ItemGetFocus(LPVOID CallbackParam);
410 
411     // this function is called when a item of listview is checked/unchecked
412     // CallbackParam is the param passed to listview when adding the item (the one getting focus now).
413     VOID
414     ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam);
415 };
416