2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: GUI classes for RAPPS
5 * COPYRIGHT: Copyright 2015 David Quintana (gigaherz@gmail.com)
6 * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
7 * Copyright 2020 He Yang (1160386205@qq.com)
12 #include "crichedit.h"
14 #include "asyncinet.h"
19 #include <shlobj_undoc.h>
20 #include <shlguid_undoc.h>
27 #include <shellutils.h>
32 #define SEARCH_TIMER_ID 'SR'
33 #define TREEVIEW_ICON_SIZE 24
37 // **** CSideTreeView ****
39 CSideTreeView::CSideTreeView() :
41 hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE
, TREEVIEW_ICON_SIZE
,
42 GetSystemColorDepth() | ILC_MASK
,
47 HTREEITEM
CSideTreeView::AddItem(HTREEITEM hParent
, ATL::CStringW
&Text
, INT Image
, INT SelectedImage
, LPARAM lParam
)
49 return CUiWindow
<CTreeView
>::AddItem(hParent
, const_cast<LPWSTR
>(Text
.GetString()), Image
, SelectedImage
, lParam
);
52 HTREEITEM
CSideTreeView::AddCategory(HTREEITEM hRootItem
, UINT TextIndex
, UINT IconIndex
)
58 hIcon
= (HICON
)LoadImageW(hInst
,
59 MAKEINTRESOURCE(IconIndex
),
66 Index
= ImageList_AddIcon(hImageTreeView
, hIcon
);
70 szText
.LoadStringW(TextIndex
);
71 return AddItem(hRootItem
, szText
, Index
, Index
, TextIndex
);
74 HIMAGELIST
CSideTreeView::SetImageList()
76 return CUiWindow
<CTreeView
>::SetImageList(hImageTreeView
, TVSIL_NORMAL
);
79 VOID
CSideTreeView::DestroyImageList()
82 ImageList_Destroy(hImageTreeView
);
85 CSideTreeView::~CSideTreeView()
89 // **** CSideTreeView ****
93 // **** CMainWindow ****
95 CMainWindow::CMainWindow() :
97 SelectedEnumType(ENUM_ALL_INSTALLED
)
101 CMainWindow::~CMainWindow()
106 VOID
CMainWindow::InitCategoriesList()
108 HTREEITEM hRootItemInstalled
, hRootItemAvailable
;
110 hRootItemInstalled
= m_TreeView
->AddCategory(TVI_ROOT
, IDS_INSTALLED
, IDI_CATEGORY
);
111 m_TreeView
->AddCategory(hRootItemInstalled
, IDS_APPLICATIONS
, IDI_APPS
);
112 m_TreeView
->AddCategory(hRootItemInstalled
, IDS_UPDATES
, IDI_APPUPD
);
114 m_TreeView
->AddCategory(TVI_ROOT
, IDS_SELECTEDFORINST
, IDI_SELECTEDFORINST
);
116 hRootItemAvailable
= m_TreeView
->AddCategory(TVI_ROOT
, IDS_AVAILABLEFORINST
, IDI_CATEGORY
);
117 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_AUDIO
, IDI_CAT_AUDIO
);
118 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_VIDEO
, IDI_CAT_VIDEO
);
119 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_GRAPHICS
, IDI_CAT_GRAPHICS
);
120 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_GAMES
, IDI_CAT_GAMES
);
121 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_INTERNET
, IDI_CAT_INTERNET
);
122 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_OFFICE
, IDI_CAT_OFFICE
);
123 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_DEVEL
, IDI_CAT_DEVEL
);
124 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_EDU
, IDI_CAT_EDU
);
125 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_ENGINEER
, IDI_CAT_ENGINEER
);
126 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_FINANCE
, IDI_CAT_FINANCE
);
127 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_SCIENCE
, IDI_CAT_SCIENCE
);
128 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_TOOLS
, IDI_CAT_TOOLS
);
129 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_DRIVERS
, IDI_CAT_DRIVERS
);
130 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_LIBS
, IDI_CAT_LIBS
);
131 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_THEMES
, IDI_CAT_THEMES
);
132 m_TreeView
->AddCategory(hRootItemAvailable
, IDS_CAT_OTHER
, IDI_CAT_OTHER
);
134 m_TreeView
->SetImageList();
135 m_TreeView
->Expand(hRootItemInstalled
, TVE_EXPAND
);
136 m_TreeView
->Expand(hRootItemAvailable
, TVE_EXPAND
);
137 m_TreeView
->SelectItem(hRootItemAvailable
);
140 BOOL
CMainWindow::CreateStatusBar()
142 m_StatusBar
= new CUiWindow
<CStatusBar
>();
143 m_StatusBar
->m_VerticalAlignment
= UiAlign_RightBtm
;
144 m_StatusBar
->m_HorizontalAlignment
= UiAlign_Stretch
;
145 m_ClientPanel
->Children().Append(m_StatusBar
);
147 return m_StatusBar
->Create(m_hWnd
, (HMENU
)IDC_STATUSBAR
) != NULL
;
150 BOOL
CMainWindow::CreateTreeView()
152 m_TreeView
= new CSideTreeView();
153 m_TreeView
->m_VerticalAlignment
= UiAlign_Stretch
;
154 m_TreeView
->m_HorizontalAlignment
= UiAlign_Stretch
;
155 m_VSplitter
->First().Append(m_TreeView
);
157 return m_TreeView
->Create(m_hWnd
) != NULL
;
160 BOOL
CMainWindow::CreateApplicationView()
162 m_ApplicationView
= new CApplicationView(this); // pass this to ApplicationView for callback purpose
163 m_ApplicationView
->m_VerticalAlignment
= UiAlign_Stretch
;
164 m_ApplicationView
->m_HorizontalAlignment
= UiAlign_Stretch
;
165 m_VSplitter
->Second().Append(m_ApplicationView
);
167 return m_ApplicationView
->Create(m_hWnd
) != NULL
;
170 BOOL
CMainWindow::CreateVSplitter()
172 m_VSplitter
= new CUiSplitPanel();
173 m_VSplitter
->m_VerticalAlignment
= UiAlign_Stretch
;
174 m_VSplitter
->m_HorizontalAlignment
= UiAlign_Stretch
;
175 m_VSplitter
->m_DynamicFirst
= FALSE
;
176 m_VSplitter
->m_Horizontal
= FALSE
;
177 m_VSplitter
->m_MinFirst
= 0;
179 // TODO: m_MinSecond should be calculate dynamically instead of hard-coded
180 m_VSplitter
->m_MinSecond
= 480;
181 m_VSplitter
->m_Pos
= 240;
182 m_ClientPanel
->Children().Append(m_VSplitter
);
184 return m_VSplitter
->Create(m_hWnd
) != NULL
;
187 BOOL
CMainWindow::CreateLayout()
192 m_ClientPanel
= new CUiPanel();
193 m_ClientPanel
->m_VerticalAlignment
= UiAlign_Stretch
;
194 m_ClientPanel
->m_HorizontalAlignment
= UiAlign_Stretch
;
197 b
= b
&& CreateStatusBar();
198 b
= b
&& CreateVSplitter();
201 b
= b
&& CreateTreeView();
202 b
= b
&& CreateApplicationView();
208 /* Size status bar */
209 m_StatusBar
->SendMessageW(WM_SIZE
, 0, 0);
211 ::GetWindowRect(m_StatusBar
->m_hWnd
, &rBottom
);
213 m_VSplitter
->m_Margin
.bottom
= rBottom
.bottom
- rBottom
.top
;
220 VOID
CMainWindow::LayoutCleanup()
223 delete m_ApplicationView
;
229 BOOL
CMainWindow::InitControls()
233 InitCategoriesList();
235 UpdateStatusBarText();
243 VOID
CMainWindow::OnSize(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
245 if (wParam
== SIZE_MINIMIZED
)
248 /* Size status bar */
249 m_StatusBar
->SendMessage(WM_SIZE
, 0, 0);
252 RECT r
= { 0, 0, LOWORD(lParam
), HIWORD(lParam
) };
254 INT count
= m_ClientPanel
->CountSizableChildren();
256 hdwp
= BeginDeferWindowPos(count
);
259 hdwp
= m_ClientPanel
->OnParentSize(r
, hdwp
);
262 EndDeferWindowPos(hdwp
);
267 BOOL
CMainWindow::RemoveSelectedAppFromRegistry()
269 if (!IsInstalledEnum(SelectedEnumType
))
272 ATL::CStringW szMsgText
, szMsgTitle
;
274 if (!szMsgText
.LoadStringW(IDS_APP_REG_REMOVE
) ||
275 !szMsgTitle
.LoadStringW(IDS_INFORMATION
))
278 if (MessageBoxW(szMsgText
, szMsgTitle
, MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
280 CInstalledApplicationInfo
*InstalledApp
= (CInstalledApplicationInfo
*)m_ApplicationView
->GetFocusedItemData();
284 LSTATUS Result
= InstalledApp
->RemoveFromRegistry();
285 if (Result
!= ERROR_SUCCESS
)
287 // TODO: popup a messagebox telling user it fails somehow
291 // as it's already removed form registry, this will also remove it from the list
292 UpdateApplicationsList(-1);
299 BOOL
CMainWindow::UninstallSelectedApp(BOOL bModify
)
301 if (!IsInstalledEnum(SelectedEnumType
))
304 CInstalledApplicationInfo
*InstalledApp
= (CInstalledApplicationInfo
*)m_ApplicationView
->GetFocusedItemData();
308 return InstalledApp
->UninstallApplication(bModify
);
311 BOOL
CMainWindow::ProcessWindowMessage(HWND hwnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
&theResult
, DWORD dwMapId
)
318 ::PostMessageW(hwnd
, WM_CLOSE
, 0, 0);
324 SaveSettings(hwnd
, &SettingsInfo
);
327 m_AvailableApps
.FreeCachedEntries();
328 m_InstalledApps
.FreeCachedEntries();
330 delete m_ClientPanel
;
337 OnCommand(wParam
, lParam
);
342 LPNMHDR data
= (LPNMHDR
)lParam
;
348 if (data
->hwndFrom
== m_TreeView
->m_hWnd
)
350 switch (((LPNMTREEVIEW
)lParam
)->itemNew
.lParam
)
353 UpdateApplicationsList(ENUM_ALL_INSTALLED
);
356 case IDS_APPLICATIONS
:
357 UpdateApplicationsList(ENUM_INSTALLED_APPLICATIONS
);
361 UpdateApplicationsList(ENUM_UPDATES
);
364 case IDS_AVAILABLEFORINST
:
365 UpdateApplicationsList(ENUM_ALL_AVAILABLE
);
369 UpdateApplicationsList(ENUM_CAT_AUDIO
);
373 UpdateApplicationsList(ENUM_CAT_DEVEL
);
376 case IDS_CAT_DRIVERS
:
377 UpdateApplicationsList(ENUM_CAT_DRIVERS
);
381 UpdateApplicationsList(ENUM_CAT_EDU
);
384 case IDS_CAT_ENGINEER
:
385 UpdateApplicationsList(ENUM_CAT_ENGINEER
);
388 case IDS_CAT_FINANCE
:
389 UpdateApplicationsList(ENUM_CAT_FINANCE
);
393 UpdateApplicationsList(ENUM_CAT_GAMES
);
396 case IDS_CAT_GRAPHICS
:
397 UpdateApplicationsList(ENUM_CAT_GRAPHICS
);
400 case IDS_CAT_INTERNET
:
401 UpdateApplicationsList(ENUM_CAT_INTERNET
);
405 UpdateApplicationsList(ENUM_CAT_LIBS
);
409 UpdateApplicationsList(ENUM_CAT_OFFICE
);
413 UpdateApplicationsList(ENUM_CAT_OTHER
);
416 case IDS_CAT_SCIENCE
:
417 UpdateApplicationsList(ENUM_CAT_SCIENCE
);
421 UpdateApplicationsList(ENUM_CAT_TOOLS
);
425 UpdateApplicationsList(ENUM_CAT_VIDEO
);
429 UpdateApplicationsList(ENUM_CAT_THEMES
);
432 case IDS_SELECTEDFORINST
:
433 UpdateApplicationsList(ENUM_CAT_SELECTED
);
438 HMENU mainMenu
= ::GetMenu(hwnd
);
440 /* Disable/enable items based on treeview selection */
441 if (IsSelectedNodeInstalled())
443 EnableMenuItem(mainMenu
, ID_REGREMOVE
, MF_ENABLED
);
444 EnableMenuItem(mainMenu
, ID_INSTALL
, MF_GRAYED
);
445 EnableMenuItem(mainMenu
, ID_UNINSTALL
, MF_ENABLED
);
446 EnableMenuItem(mainMenu
, ID_MODIFY
, MF_ENABLED
);
450 EnableMenuItem(mainMenu
, ID_REGREMOVE
, MF_GRAYED
);
451 EnableMenuItem(mainMenu
, ID_INSTALL
, MF_ENABLED
);
452 EnableMenuItem(mainMenu
, ID_UNINSTALL
, MF_GRAYED
);
453 EnableMenuItem(mainMenu
, ID_MODIFY
, MF_GRAYED
);
463 OnSize(hwnd
, wParam
, lParam
);
468 LPRECT pRect
= (LPRECT
)lParam
;
470 if (pRect
->right
- pRect
->left
< 565)
471 pRect
->right
= pRect
->left
+ 565;
473 if (pRect
->bottom
- pRect
->top
< 300)
474 pRect
->bottom
= pRect
->top
+ 300;
479 case WM_SYSCOLORCHANGE
:
481 /* Forward WM_SYSCOLORCHANGE to common controls */
482 m_ApplicationView
->SendMessageW(WM_SYSCOLORCHANGE
, wParam
, lParam
);
483 m_TreeView
->SendMessageW(WM_SYSCOLORCHANGE
, wParam
, lParam
);
488 if (wParam
== SEARCH_TIMER_ID
)
490 ::KillTimer(hwnd
, SEARCH_TIMER_ID
);
492 UpdateApplicationsList(-1);
500 BOOL
CMainWindow::IsSelectedNodeInstalled()
502 HTREEITEM hSelectedItem
= m_TreeView
->GetSelection();
505 tItem
.mask
= TVIF_PARAM
| TVIF_HANDLE
;
506 tItem
.hItem
= hSelectedItem
;
507 m_TreeView
->GetItem(&tItem
);
508 switch (tItem
.lParam
)
511 case IDS_APPLICATIONS
:
519 VOID
CMainWindow::ShowAboutDlg()
522 ATL::CStringW szAuthors
;
525 szApp
.LoadStringW(IDS_APPTITLE
);
526 szAuthors
.LoadStringW(IDS_APP_AUTHORS
);
527 hIcon
= LoadIconW(hInst
, MAKEINTRESOURCEW(IDI_MAIN
));
528 ShellAboutW(m_hWnd
, szApp
, szAuthors
, hIcon
);
532 VOID
CMainWindow::OnCommand(WPARAM wParam
, LPARAM lParam
)
534 WORD wCommand
= LOWORD(wParam
);
541 CreateSettingsDlg(m_hWnd
);
545 PostMessageW(WM_CLOSE
, 0, 0);
549 if (IsAvailableEnum(SelectedEnumType
))
551 ATL::CSimpleArray
<CAvailableApplicationInfo
> AppsList
;
553 // enum all selected apps
554 m_AvailableApps
.Enum(ENUM_CAT_SELECTED
, s_EnumSelectedAppForDownloadProc
, (PVOID
)&AppsList
);
556 if (AppsList
.GetSize())
558 if (DownloadListOfApplications(AppsList
, FALSE
))
560 m_AvailableApps
.RemoveAllSelected();
561 UpdateApplicationsList(-1);
566 // use the currently focused item in application-view
567 CAvailableApplicationInfo
*FocusedApps
= (CAvailableApplicationInfo
*)m_ApplicationView
->GetFocusedItemData();
570 if (DownloadApplication(FocusedApps
, FALSE
))
572 UpdateApplicationsList(-1);
577 // TODO: in this case, Install button in toolbar (and all other places) should be disabled
578 // or at least popup a messagebox telling user to select/check some app first
585 if (UninstallSelectedApp(FALSE
))
586 UpdateApplicationsList(-1);
590 if (UninstallSelectedApp(TRUE
))
591 UpdateApplicationsList(-1);
595 RemoveSelectedAppFromRegistry();
599 UpdateApplicationsList(-1);
603 CAvailableApps::ForceUpdateAppsDB();
604 UpdateApplicationsList(-1);
608 MessageBoxW(L
"Help not implemented yet", NULL
, MB_OK
);
616 m_ApplicationView
->CheckAll();
622 BOOL CALLBACK
CMainWindow::EnumInstalledAppProc(CInstalledApplicationInfo
*Info
)
624 if (!SearchPatternMatch(Info
->szDisplayName
.GetString(), szSearchPattern
))
628 return m_ApplicationView
->AddInstalledApplication(Info
, Info
); // currently, the callback param is Info itself
631 BOOL CALLBACK
CMainWindow::EnumAvailableAppProc(CAvailableApplicationInfo
*Info
, BOOL bInitialCheckState
)
633 if (!SearchPatternMatch(Info
->m_szName
.GetString(), szSearchPattern
) &&
634 !SearchPatternMatch(Info
->m_szDesc
.GetString(), szSearchPattern
))
638 return m_ApplicationView
->AddAvailableApplication(Info
, bInitialCheckState
, Info
); // currently, the callback param is Info itself
641 BOOL CALLBACK
CMainWindow::s_EnumInstalledAppProc(CInstalledApplicationInfo
*Info
, PVOID param
)
643 CMainWindow
*pThis
= (CMainWindow
*)param
;
644 return pThis
->EnumInstalledAppProc(Info
);
647 BOOL CALLBACK
CMainWindow::s_EnumAvailableAppProc(CAvailableApplicationInfo
*Info
, BOOL bInitialCheckState
, PVOID param
)
649 CMainWindow
*pThis
= (CMainWindow
*)param
;
650 return pThis
->EnumAvailableAppProc(Info
, bInitialCheckState
);
653 BOOL CALLBACK
CMainWindow::s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo
*Info
, BOOL bInitialCheckState
, PVOID param
)
655 ATL::CSimpleArray
<CAvailableApplicationInfo
> *pAppList
= (ATL::CSimpleArray
<CAvailableApplicationInfo
> *)param
;
656 pAppList
->Add(*Info
);
660 VOID
CMainWindow::UpdateStatusBarText()
664 ATL::CStringW szBuffer
;
666 szBuffer
.Format(IDS_APPS_COUNT
, m_ApplicationView
->GetItemCount(), m_AvailableApps
.GetSelectedCount());
667 m_StatusBar
->SetText(szBuffer
);
671 VOID
CMainWindow::UpdateApplicationsList(INT EnumType
)
677 // keep the old enum type
678 EnumType
= SelectedEnumType
;
682 SelectedEnumType
= EnumType
;
685 m_ApplicationView
->SetRedraw(FALSE
);
686 if (IsInstalledEnum(EnumType
))
688 // set the display type of application-view. this will remove all the item in application-view too.
689 m_ApplicationView
->SetDisplayAppType(AppViewTypeInstalledApps
);
691 // enum installed softwares
692 m_InstalledApps
.Enum(EnumType
, s_EnumInstalledAppProc
, this);
694 else if (IsAvailableEnum(EnumType
))
696 // set the display type of application-view. this will remove all the item in application-view too.
697 m_ApplicationView
->SetDisplayAppType(AppViewTypeAvailableApps
);
699 // enum available softwares
700 m_AvailableApps
.Enum(EnumType
, s_EnumAvailableAppProc
, this);
702 m_ApplicationView
->SetRedraw(TRUE
);
703 m_ApplicationView
->RedrawWindow(0, 0, RDW_INVALIDATE
| RDW_ALLCHILDREN
); // force the child window to repaint
704 UpdateStatusBarText();
708 ATL::CWndClassInfo
&CMainWindow::GetWndClassInfo()
710 DWORD csStyle
= CS_VREDRAW
| CS_HREDRAW
;
711 static ATL::CWndClassInfo wc
=
720 LoadIconW(_AtlBaseModule
.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN
)),
721 LoadCursorW(NULL
, IDC_ARROW
),
722 (HBRUSH
)(COLOR_BTNFACE
+ 1),
723 MAKEINTRESOURCEW(IDR_MAINMENU
),
727 NULL
, NULL
, IDC_ARROW
, TRUE
, 0, _T("")
732 HWND
CMainWindow::Create()
734 ATL::CStringW szWindowName
;
735 szWindowName
.LoadStringW(IDS_APPTITLE
);
738 (SettingsInfo
.bSaveWndPos
? SettingsInfo
.Left
: CW_USEDEFAULT
),
739 (SettingsInfo
.bSaveWndPos
? SettingsInfo
.Top
: CW_USEDEFAULT
),
740 (SettingsInfo
.bSaveWndPos
? SettingsInfo
.Width
: 680),
741 (SettingsInfo
.bSaveWndPos
? SettingsInfo
.Height
: 450)
746 return CWindowImpl::Create(NULL
, r
, szWindowName
.GetString(), WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
, WS_EX_WINDOWEDGE
);
749 // this function is called when a item of application-view is checked/unchecked
750 // CallbackParam is the param passed to application-view when adding the item (the one getting focus now).
751 BOOL
CMainWindow::ItemCheckStateChanged(BOOL bChecked
, LPVOID CallbackParam
)
757 if (!m_AvailableApps
.AddSelected((CAvailableApplicationInfo
*)CallbackParam
))
764 if (!m_AvailableApps
.RemoveSelected((CAvailableApplicationInfo
*)CallbackParam
))
770 UpdateStatusBarText();
779 // this function is called when one or more application(s) should be installed install
780 // if Info is not zero, this app should be installed. otherwise those checked apps should be installed
781 BOOL
CMainWindow::InstallApplication(CAvailableApplicationInfo
*Info
)
785 if (DownloadApplication(Info
, FALSE
))
787 UpdateApplicationsList(-1);
793 ATL::CSimpleArray
<CAvailableApplicationInfo
> AppsList
;
795 // enum all selected apps
796 m_AvailableApps
.Enum(ENUM_CAT_SELECTED
, s_EnumSelectedAppForDownloadProc
, (PVOID
)&AppsList
);
798 if (AppsList
.GetSize())
800 if (DownloadListOfApplications(AppsList
, FALSE
))
802 m_AvailableApps
.RemoveAllSelected();
803 UpdateApplicationsList(-1);
812 BOOL
CMainWindow::SearchTextChanged(ATL::CStringW
&SearchText
)
814 if (szSearchPattern
== SearchText
)
819 szSearchPattern
= SearchText
;
822 SystemParametersInfoW(SPI_GETMENUSHOWDELAY
, 0, &dwDelay
, 0);
823 SetTimer(SEARCH_TIMER_ID
, dwDelay
);
828 void CMainWindow::HandleTabOrder(int direction
)
830 ATL::CSimpleArray
<HWND
> TabOrderHwndList
;
832 m_TreeView
->AppendTabOrderWindow(direction
, TabOrderHwndList
);
833 m_ApplicationView
->AppendTabOrderWindow(direction
, TabOrderHwndList
);
836 if (TabOrderHwndList
.GetSize() == 0)
838 // in case the list is empty
844 if ((FocusIndex
= TabOrderHwndList
.Find(GetFocus())) == -1)
846 FocusIndex
= 0; // focus the first window in the list
850 FocusIndex
+= direction
;
851 FocusIndex
+= TabOrderHwndList
.GetSize(); // FocusIndex might be negative. we don't want to mod a negative number
852 FocusIndex
%= TabOrderHwndList
.GetSize();
855 ::SetFocus(TabOrderHwndList
[FocusIndex
]);
858 // **** CMainWindow ****
862 VOID
MainWindowLoop(INT nShowCmd
)
867 CMainWindow
* wnd
= new CMainWindow();
871 hMainWnd
= wnd
->Create();
875 /* Maximize it if we must */
876 wnd
->ShowWindow((SettingsInfo
.bSaveWndPos
&& SettingsInfo
.Maximized
) ? SW_MAXIMIZE
: nShowCmd
);
879 /* Load the menu hotkeys */
880 KeyBrd
= LoadAcceleratorsW(NULL
, MAKEINTRESOURCEW(HOTKEYS
));
883 while (GetMessageW(&Msg
, NULL
, 0, 0))
885 if (!TranslateAcceleratorW(hMainWnd
, KeyBrd
, &Msg
))
887 if (Msg
.message
== WM_CHAR
&&
888 Msg
.wParam
== VK_TAB
)
890 // Move backwards if shift is held down
891 int direction
= (GetKeyState(VK_SHIFT
) & 0x8000) ? -1 : 1;
893 wnd
->HandleTabOrder(direction
);
897 TranslateMessage(&Msg
);
898 DispatchMessageW(&Msg
);