mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
[PowerRename] Fluent UX (#13678)
* PowerRename new UI * Add scrollviewer * Don't deploy PowerRenameUI_new * Visual updates * Visual updates * Updates * Update Resources.resw * Added docs button * Update MainWindow.xaml * Wire Docs button * RegEx -> regular expressions * Update Show only renamed list on search/replace text changed * Update Show only renamed list on search/replace text changed - proper fix Set searchTerm to NULL when cleared - fix Show only renamed files on clear searchTerm * Files/folders input error handling * Fix renaming with keeping UI window opened After renaming folder, all of it's children need path update. Without path update, further renaming of children items would fail. * Update only children, not all items with greater depth * Fix dictionary false positives * Remove .NET dep * Rename PowerRenameUI_new to PowerRenameUILib Rename executable PowerRenameUIHost to PowerRename Co-authored-by: Laute <Niels.Laute@philips.com>
This commit is contained in:
917
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.cpp
Normal file
917
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.cpp
Normal file
@@ -0,0 +1,917 @@
|
||||
// PowerRenameUIHost.cpp : Defines the entry point for the application.
|
||||
//
|
||||
#include "pch.h"
|
||||
|
||||
#include "PowerRenameUIHost.h"
|
||||
#include <settings.h>
|
||||
#include <trace.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <common/utils/process_path.h>
|
||||
|
||||
#define MAX_LOADSTRING 100
|
||||
|
||||
const wchar_t c_WindowClass[] = L"PowerRename";
|
||||
HINSTANCE g_hostHInst;
|
||||
|
||||
int AppWindow::Show(HINSTANCE hInstance, std::vector<std::wstring> files)
|
||||
{
|
||||
auto window = AppWindow(hInstance, files);
|
||||
window.CreateAndShowWindow();
|
||||
return window.MessageLoop(window.m_accelerators.get());
|
||||
}
|
||||
|
||||
LRESULT AppWindow::MessageHandler(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
HANDLE_MSG(WindowHandle(), WM_CREATE, OnCreate);
|
||||
HANDLE_MSG(WindowHandle(), WM_COMMAND, OnCommand);
|
||||
HANDLE_MSG(WindowHandle(), WM_DESTROY, OnDestroy);
|
||||
HANDLE_MSG(WindowHandle(), WM_SIZE, OnResize);
|
||||
default:
|
||||
return base_type::MessageHandler(message, wParam, lParam);
|
||||
}
|
||||
|
||||
return base_type::MessageHandler(message, wParam, lParam);
|
||||
}
|
||||
|
||||
AppWindow::AppWindow(HINSTANCE hInstance, std::vector<std::wstring> files) noexcept :
|
||||
m_instance{ hInstance }, m_managerEvents{ this }
|
||||
{
|
||||
HRESULT hr = CPowerRenameManager::s_CreateInstance(&m_prManager);
|
||||
// Create the factory for our items
|
||||
CComPtr<IPowerRenameItemFactory> prItemFactory;
|
||||
hr = CPowerRenameItem::s_CreateInstance(nullptr, IID_PPV_ARGS(&prItemFactory));
|
||||
hr = m_prManager->PutRenameItemFactory(prItemFactory);
|
||||
hr = m_prManager->Advise(&m_managerEvents, &m_cookie);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CComPtr<IShellItemArray> shellItemArray;
|
||||
// To test PowerRenameUIHost uncomment this line and update the path to
|
||||
// your local (absolute or relative) path which you want to see in PowerRename
|
||||
//files.push_back(L"<path>");
|
||||
|
||||
if (!files.empty())
|
||||
{
|
||||
hr = CreateShellItemArrayFromPaths(files, &shellItemArray);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CComPtr<IEnumShellItems> enumShellItems;
|
||||
hr = shellItemArray->EnumItems(&enumShellItems);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
EnumerateShellItems(enumShellItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::CreateAndShowWindow()
|
||||
{
|
||||
m_accelerators.reset(LoadAcceleratorsW(m_instance, MAKEINTRESOURCE(IDC_POWERRENAMEUIHOST)));
|
||||
|
||||
WNDCLASSEXW wcex = { sizeof(wcex) };
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.hInstance = m_instance;
|
||||
wcex.hIcon = LoadIconW(m_instance, MAKEINTRESOURCE(IDC_POWERRENAMEUIHOST));
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
|
||||
wcex.lpszClassName = c_WindowClass;
|
||||
wcex.hIconSm = LoadIconW(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
|
||||
RegisterClassExW(&wcex); // don't test result, handle error at CreateWindow
|
||||
|
||||
wchar_t title[64];
|
||||
LoadStringW(m_instance, IDS_APP_TITLE, title, ARRAYSIZE(title));
|
||||
|
||||
m_window = CreateWindowW(c_WindowClass, title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, m_instance, this);
|
||||
THROW_LAST_ERROR_IF(!m_window);
|
||||
|
||||
ShowWindow(m_window, SW_SHOWNORMAL);
|
||||
UpdateWindow(m_window);
|
||||
SetFocus(m_window);
|
||||
}
|
||||
|
||||
bool AppWindow::OnCreate(HWND, LPCREATESTRUCT) noexcept
|
||||
{
|
||||
m_mainUserControl = winrt::PowerRenameUILib::MainWindow();
|
||||
m_xamlIsland = CreateDesktopWindowsXamlSource(WS_TABSTOP, m_mainUserControl);
|
||||
|
||||
PopulateExplorerItems();
|
||||
SetHandlers();
|
||||
ReadSettings();
|
||||
|
||||
m_mainUserControl.UIUpdatesItem().ButtonRenameEnabled(false);
|
||||
InitAutoComplete();
|
||||
SearchReplaceChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AppWindow::OnCommand(HWND, int id, HWND hwndControl, UINT codeNotify) noexcept
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case IDM_ABOUT:
|
||||
DialogBoxW(m_instance, MAKEINTRESOURCE(IDD_ABOUTBOX), WindowHandle(), [](HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -> INT_PTR {
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
|
||||
{
|
||||
EndDialog(hDlg, LOWORD(wParam));
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
});
|
||||
break;
|
||||
|
||||
case IDM_EXIT:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::OnDestroy(HWND hwnd) noexcept
|
||||
{
|
||||
base_type::OnDestroy(hwnd);
|
||||
}
|
||||
|
||||
void AppWindow::OnResize(HWND, UINT state, int cx, int cy) noexcept
|
||||
{
|
||||
SetWindowPos(m_xamlIsland, NULL, 0, 0, cx, cy, SWP_SHOWWINDOW);
|
||||
}
|
||||
|
||||
HRESULT AppWindow::CreateShellItemArrayFromPaths(
|
||||
std::vector<std::wstring> files,
|
||||
IShellItemArray** shellItemArray)
|
||||
{
|
||||
*shellItemArray = nullptr;
|
||||
PIDLIST_ABSOLUTE* itemList = nullptr;
|
||||
itemList = new (std::nothrow) PIDLIST_ABSOLUTE[files.size()];
|
||||
HRESULT hr = itemList ? S_OK : E_OUTOFMEMORY;
|
||||
UINT itemsCnt = 0;
|
||||
for (const auto& file : files)
|
||||
{
|
||||
const DWORD BUFSIZE = 4096;
|
||||
TCHAR buffer[BUFSIZE] = TEXT("");
|
||||
auto retval = GetFullPathName(file.c_str(), BUFSIZE, buffer, NULL);
|
||||
if (retval != 0 && PathFileExists(buffer))
|
||||
{
|
||||
hr = SHParseDisplayName(buffer, nullptr, &itemList[itemsCnt], 0, nullptr);
|
||||
++itemsCnt;
|
||||
}
|
||||
}
|
||||
if (SUCCEEDED(hr) && itemsCnt > 0)
|
||||
{
|
||||
hr = SHCreateShellItemArrayFromIDLists(itemsCnt, const_cast<LPCITEMIDLIST*>(itemList), shellItemArray);
|
||||
|
||||
for (UINT i = 0; i < itemsCnt; i++)
|
||||
{
|
||||
CoTaskMemFree(itemList[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
delete[] itemList;
|
||||
return hr;
|
||||
}
|
||||
|
||||
void AppWindow::PopulateExplorerItems()
|
||||
{
|
||||
UINT count = 0;
|
||||
m_prManager->GetVisibleItemCount(&count);
|
||||
|
||||
UINT currDepth = 0;
|
||||
std::stack<UINT> parents{};
|
||||
UINT prevId = 0;
|
||||
parents.push(0);
|
||||
|
||||
for (UINT i = 0; i < count; ++i)
|
||||
{
|
||||
CComPtr<IPowerRenameItem> renameItem;
|
||||
if (SUCCEEDED(m_prManager->GetVisibleItemByIndex(i, &renameItem)))
|
||||
{
|
||||
int id = 0;
|
||||
renameItem->GetId(&id);
|
||||
|
||||
PWSTR originalName = nullptr;
|
||||
renameItem->GetOriginalName(&originalName);
|
||||
PWSTR newName = nullptr;
|
||||
renameItem->GetNewName(&newName);
|
||||
|
||||
bool selected;
|
||||
renameItem->GetSelected(&selected);
|
||||
|
||||
UINT depth = 0;
|
||||
renameItem->GetDepth(&depth);
|
||||
|
||||
bool isFolder = false;
|
||||
bool isSubFolderContent = false;
|
||||
winrt::check_hresult(renameItem->GetIsFolder(&isFolder));
|
||||
|
||||
if (depth > currDepth)
|
||||
{
|
||||
parents.push(prevId);
|
||||
currDepth = depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (currDepth > depth)
|
||||
{
|
||||
parents.pop();
|
||||
currDepth--;
|
||||
}
|
||||
currDepth = depth;
|
||||
}
|
||||
m_mainUserControl.AddExplorerItem(
|
||||
id, originalName, newName == nullptr ? hstring{} : hstring{ newName }, isFolder ? 0 : 1, parents.top(), selected);
|
||||
prevId = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT AppWindow::InitAutoComplete()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (CSettingsInstance().GetMRUEnabled())
|
||||
{
|
||||
hr = CPowerRenameMRU::CPowerRenameMRUSearch_CreateInstance(&m_searchMRU);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
for (const auto& item : m_searchMRU->GetMRUStrings())
|
||||
{
|
||||
if (!item.empty())
|
||||
{
|
||||
m_mainUserControl.AppendSearchMRU(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = CPowerRenameMRU::CPowerRenameMRUReplace_CreateInstance(&m_replaceMRU);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
for (const auto& item : m_replaceMRU->GetMRUStrings())
|
||||
{
|
||||
if (!item.empty())
|
||||
{
|
||||
m_mainUserControl.AppendReplaceMRU(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::EnumerateShellItems(_In_ IEnumShellItems* enumShellItems)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
// Enumerate the data object and populate the manager
|
||||
if (m_prManager)
|
||||
{
|
||||
m_disableCountUpdate = true;
|
||||
|
||||
// Ensure we re-create the enumerator
|
||||
m_prEnum = nullptr;
|
||||
hr = CPowerRenameEnum::s_CreateInstance(nullptr, m_prManager, IID_PPV_ARGS(&m_prEnum));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = m_prEnum->Start(enumShellItems);
|
||||
}
|
||||
|
||||
m_disableCountUpdate = false;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void AppWindow::SearchReplaceChanged(bool forceRenaming)
|
||||
{
|
||||
// Pass updated search and replace terms to the IPowerRenameRegEx handler
|
||||
CComPtr<IPowerRenameRegEx> prRegEx;
|
||||
if (m_prManager && SUCCEEDED(m_prManager->GetRenameRegEx(&prRegEx)))
|
||||
{
|
||||
winrt::hstring searchTerm = m_mainUserControl.AutoSuggestBoxSearch().Text();
|
||||
prRegEx->PutSearchTerm(searchTerm.c_str(), forceRenaming);
|
||||
|
||||
winrt::hstring replaceTerm = m_mainUserControl.AutoSuggestBoxReplace().Text();
|
||||
prRegEx->PutReplaceTerm(replaceTerm.c_str(), forceRenaming);
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::ValidateFlags(PowerRenameFlags flag)
|
||||
{
|
||||
if (flag == Uppercase)
|
||||
{
|
||||
if (m_mainUserControl.ToggleButtonUpperCase().IsChecked())
|
||||
{
|
||||
m_mainUserControl.ToggleButtonLowerCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonTitleCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonCapitalize().IsChecked(false);
|
||||
}
|
||||
}
|
||||
else if (flag == Lowercase)
|
||||
{
|
||||
if (m_mainUserControl.ToggleButtonLowerCase().IsChecked())
|
||||
{
|
||||
m_mainUserControl.ToggleButtonUpperCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonTitleCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonCapitalize().IsChecked(false);
|
||||
}
|
||||
}
|
||||
else if (flag == Titlecase)
|
||||
{
|
||||
if (m_mainUserControl.ToggleButtonTitleCase().IsChecked())
|
||||
{
|
||||
m_mainUserControl.ToggleButtonUpperCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonLowerCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonCapitalize().IsChecked(false);
|
||||
}
|
||||
}
|
||||
else if (flag == Capitalized)
|
||||
{
|
||||
if (m_mainUserControl.ToggleButtonCapitalize().IsChecked())
|
||||
{
|
||||
m_mainUserControl.ToggleButtonUpperCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonLowerCase().IsChecked(false);
|
||||
m_mainUserControl.ToggleButtonTitleCase().IsChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
m_flagValidationInProgress = true;
|
||||
}
|
||||
|
||||
void AppWindow::UpdateFlag(PowerRenameFlags flag, UpdateFlagCommand command)
|
||||
{
|
||||
DWORD flags{};
|
||||
m_prManager->GetFlags(&flags);
|
||||
|
||||
if (command == UpdateFlagCommand::Set)
|
||||
{
|
||||
flags |= flag;
|
||||
}
|
||||
else if (command == UpdateFlagCommand::Reset)
|
||||
{
|
||||
flags &= ~flag;
|
||||
}
|
||||
|
||||
// Ensure we update flags
|
||||
if (m_prManager)
|
||||
{
|
||||
m_prManager->PutFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::SetHandlers()
|
||||
{
|
||||
m_mainUserControl.UIUpdatesItem().PropertyChanged([&](winrt::Windows::Foundation::IInspectable const& sender, Data::PropertyChangedEventArgs const& e) {
|
||||
std::wstring property{ e.PropertyName() };
|
||||
if (property == L"ShowAll")
|
||||
{
|
||||
SwitchView();
|
||||
}
|
||||
else if (property == L"ChangedItemId")
|
||||
{
|
||||
ToggleItem(m_mainUserControl.UIUpdatesItem().ChangedExplorerItemId(), m_mainUserControl.UIUpdatesItem().Checked());
|
||||
}
|
||||
else if (property == L"ToggleAll")
|
||||
{
|
||||
ToggleAll();
|
||||
}
|
||||
else if (property == L"Rename")
|
||||
{
|
||||
Rename(m_mainUserControl.UIUpdatesItem().CloseUIWindow());
|
||||
}
|
||||
});
|
||||
|
||||
// AutoSuggestBox Search
|
||||
m_mainUserControl.AutoSuggestBoxSearch().TextChanged([&](winrt::Windows::Foundation::IInspectable const& sender, AutoSuggestBoxTextChangedEventArgs const&) {
|
||||
SearchReplaceChanged();
|
||||
});
|
||||
|
||||
// AutoSuggestBox Replace
|
||||
m_mainUserControl.AutoSuggestBoxReplace().TextChanged([&](winrt::Windows::Foundation::IInspectable const& sender, AutoSuggestBoxTextChangedEventArgs const&) {
|
||||
SearchReplaceChanged();
|
||||
});
|
||||
|
||||
// ToggleButton UpperCase
|
||||
m_mainUserControl.ToggleButtonUpperCase().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(Uppercase);
|
||||
UpdateFlag(Uppercase, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonUpperCase().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(Uppercase, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// ToggleButton LowerCase
|
||||
m_mainUserControl.ToggleButtonLowerCase().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(Lowercase);
|
||||
UpdateFlag(Lowercase, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonLowerCase().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(Lowercase, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// ToggleButton TitleCase
|
||||
m_mainUserControl.ToggleButtonTitleCase().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(Titlecase);
|
||||
UpdateFlag(Titlecase, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonTitleCase().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(Titlecase, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// ToggleButton Capitalize
|
||||
m_mainUserControl.ToggleButtonCapitalize().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(Capitalized);
|
||||
UpdateFlag(Capitalized, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonCapitalize().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(Capitalized, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// CheckBox Regex
|
||||
m_mainUserControl.CheckBoxRegex().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(UseRegularExpressions);
|
||||
UpdateFlag(UseRegularExpressions, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.CheckBoxRegex().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(UseRegularExpressions, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// CheckBox CaseSensitive
|
||||
m_mainUserControl.CheckBoxCaseSensitive().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(CaseSensitive);
|
||||
UpdateFlag(CaseSensitive, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.CheckBoxCaseSensitive().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(CaseSensitive, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// ComboBox RenameParts
|
||||
m_mainUserControl.ComboBoxRenameParts().SelectionChanged([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
if (m_mainUserControl.ComboBoxRenameParts().SelectedIndex() == 0)
|
||||
{ // Filename + extension
|
||||
UpdateFlag(NameOnly, UpdateFlagCommand::Reset);
|
||||
UpdateFlag(ExtensionOnly, UpdateFlagCommand::Reset);
|
||||
}
|
||||
else if (m_mainUserControl.ComboBoxRenameParts().SelectedIndex() == 1) // Filename Only
|
||||
{
|
||||
ValidateFlags(NameOnly);
|
||||
UpdateFlag(ExtensionOnly, UpdateFlagCommand::Reset);
|
||||
UpdateFlag(NameOnly, UpdateFlagCommand::Set);
|
||||
}
|
||||
else if (m_mainUserControl.ComboBoxRenameParts().SelectedIndex() == 2) // Extension Only
|
||||
{
|
||||
ValidateFlags(ExtensionOnly);
|
||||
UpdateFlag(NameOnly, UpdateFlagCommand::Reset);
|
||||
UpdateFlag(ExtensionOnly, UpdateFlagCommand::Set);
|
||||
}
|
||||
});
|
||||
|
||||
// CheckBox MatchAllOccurences
|
||||
m_mainUserControl.CheckBoxMatchAll().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(MatchAllOccurences);
|
||||
UpdateFlag(MatchAllOccurences, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.CheckBoxMatchAll().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(MatchAllOccurences, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// ToggleButton IncludeFiles
|
||||
m_mainUserControl.ToggleButtonIncludeFiles().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(ExcludeFiles);
|
||||
UpdateFlag(ExcludeFiles, UpdateFlagCommand::Reset);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonIncludeFiles().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(ExcludeFiles, UpdateFlagCommand::Set);
|
||||
});
|
||||
|
||||
// ToggleButton IncludeFolders
|
||||
m_mainUserControl.ToggleButtonIncludeFolders().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(ExcludeFolders);
|
||||
UpdateFlag(ExcludeFolders, UpdateFlagCommand::Reset);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonIncludeFolders().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(ExcludeFolders, UpdateFlagCommand::Set);
|
||||
});
|
||||
|
||||
// ToggleButton IncludeSubfolders
|
||||
m_mainUserControl.ToggleButtonIncludeSubfolders().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(ExcludeSubfolders);
|
||||
UpdateFlag(ExcludeSubfolders, UpdateFlagCommand::Reset);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonIncludeSubfolders().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(ExcludeSubfolders, UpdateFlagCommand::Set);
|
||||
});
|
||||
|
||||
// CheckBox EnumerateItems
|
||||
m_mainUserControl.ToggleButtonEnumerateItems().Checked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ValidateFlags(EnumerateItems);
|
||||
UpdateFlag(EnumerateItems, UpdateFlagCommand::Set);
|
||||
});
|
||||
m_mainUserControl.ToggleButtonEnumerateItems().Unchecked([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
UpdateFlag(EnumerateItems, UpdateFlagCommand::Reset);
|
||||
});
|
||||
|
||||
// ButtonSettings
|
||||
m_mainUserControl.ButtonSettings().Click([&](winrt::Windows::Foundation::IInspectable const& sender, RoutedEventArgs const&) {
|
||||
OpenSettingsApp();
|
||||
});
|
||||
}
|
||||
|
||||
void AppWindow::ToggleItem(int32_t id, bool checked)
|
||||
{
|
||||
CComPtr<IPowerRenameItem> spItem;
|
||||
m_prManager->GetItemById(id, &spItem);
|
||||
spItem->PutSelected(checked);
|
||||
UpdateCounts();
|
||||
}
|
||||
|
||||
void AppWindow::ToggleAll()
|
||||
{
|
||||
UINT itemCount = 0;
|
||||
m_prManager->GetItemCount(&itemCount);
|
||||
bool selected = m_mainUserControl.CheckBoxSelectAll().IsChecked().GetBoolean();
|
||||
for (UINT i = 0; i < itemCount; i++)
|
||||
{
|
||||
CComPtr<IPowerRenameItem> spItem;
|
||||
if (SUCCEEDED(m_prManager->GetItemByIndex(i, &spItem)))
|
||||
{
|
||||
spItem->PutSelected(selected);
|
||||
}
|
||||
}
|
||||
UpdateCounts();
|
||||
}
|
||||
|
||||
void AppWindow::SwitchView()
|
||||
{
|
||||
m_prManager->SwitchFilter(0);
|
||||
PopulateExplorerItems();
|
||||
}
|
||||
|
||||
void AppWindow::Rename(bool closeWindow)
|
||||
{
|
||||
if (m_prManager)
|
||||
{
|
||||
m_prManager->Rename(m_window, closeWindow);
|
||||
}
|
||||
|
||||
// Persist the current settings. We only do this when
|
||||
// a rename is actually performed. Not when the user
|
||||
// closes/cancels the dialog.
|
||||
WriteSettings();
|
||||
}
|
||||
|
||||
HRESULT AppWindow::ReadSettings()
|
||||
{
|
||||
// Check if we should read flags from settings
|
||||
// or the defaults from the manager.
|
||||
DWORD flags = 0;
|
||||
if (CSettingsInstance().GetPersistState())
|
||||
{
|
||||
flags = CSettingsInstance().GetFlags();
|
||||
|
||||
m_mainUserControl.AutoSuggestBoxSearch().Text(CSettingsInstance().GetSearchText().c_str());
|
||||
m_mainUserControl.AutoSuggestBoxReplace().Text(CSettingsInstance().GetReplaceText().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_prManager->GetFlags(&flags);
|
||||
}
|
||||
|
||||
m_prManager->PutFlags(flags);
|
||||
SetCheckboxesFromFlags(flags);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::WriteSettings()
|
||||
{
|
||||
// Check if we should store our settings
|
||||
if (CSettingsInstance().GetPersistState())
|
||||
{
|
||||
DWORD flags = 0;
|
||||
m_prManager->GetFlags(&flags);
|
||||
CSettingsInstance().SetFlags(flags);
|
||||
|
||||
winrt::hstring searchTerm = m_mainUserControl.AutoSuggestBoxSearch().Text();
|
||||
CSettingsInstance().SetSearchText(std::wstring{ searchTerm });
|
||||
|
||||
if (CSettingsInstance().GetMRUEnabled() && m_searchMRU)
|
||||
{
|
||||
CComPtr<IPowerRenameMRU> spSearchMRU;
|
||||
if (SUCCEEDED(m_searchMRU->QueryInterface(IID_PPV_ARGS(&spSearchMRU))))
|
||||
{
|
||||
spSearchMRU->AddMRUString(searchTerm.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
winrt::hstring replaceTerm = m_mainUserControl.AutoSuggestBoxReplace().Text();
|
||||
CSettingsInstance().SetReplaceText(std::wstring{ replaceTerm });
|
||||
|
||||
if (CSettingsInstance().GetMRUEnabled() && m_replaceMRU)
|
||||
{
|
||||
CComPtr<IPowerRenameMRU> spReplaceMRU;
|
||||
if (SUCCEEDED(m_replaceMRU->QueryInterface(IID_PPV_ARGS(&spReplaceMRU))))
|
||||
{
|
||||
spReplaceMRU->AddMRUString(replaceTerm.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Trace::SettingsChanged();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OpenSettingsApp()
|
||||
{
|
||||
std::wstring path = get_module_folderpath(g_hostHInst);
|
||||
path += L"\\..\\..\\PowerToys.exe";
|
||||
|
||||
std::wstring openSettings = L"--open-settings=PowerRename";
|
||||
|
||||
CString commandLine;
|
||||
commandLine.Format(_T("\"%s\""), path.c_str());
|
||||
commandLine.AppendFormat(_T(" %s"), openSettings.c_str());
|
||||
|
||||
int nSize = commandLine.GetLength() + 1;
|
||||
LPTSTR lpszCommandLine = new TCHAR[nSize];
|
||||
_tcscpy_s(lpszCommandLine, nSize, commandLine);
|
||||
|
||||
STARTUPINFO startupInfo;
|
||||
ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
|
||||
startupInfo.cb = sizeof(STARTUPINFO);
|
||||
startupInfo.wShowWindow = SW_SHOWNORMAL;
|
||||
|
||||
PROCESS_INFORMATION processInformation;
|
||||
|
||||
// Start the resizer
|
||||
CreateProcess(
|
||||
NULL,
|
||||
lpszCommandLine,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&startupInfo,
|
||||
&processInformation);
|
||||
|
||||
delete[] lpszCommandLine;
|
||||
|
||||
if (!CloseHandle(processInformation.hProcess))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
if (!CloseHandle(processInformation.hThread))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void AppWindow::SetCheckboxesFromFlags(DWORD flags)
|
||||
{
|
||||
if (flags & CaseSensitive)
|
||||
{
|
||||
m_mainUserControl.CheckBoxCaseSensitive().IsChecked(true);
|
||||
}
|
||||
if (flags & MatchAllOccurences)
|
||||
{
|
||||
m_mainUserControl.CheckBoxMatchAll().IsChecked(true);
|
||||
}
|
||||
if (flags & UseRegularExpressions)
|
||||
{
|
||||
m_mainUserControl.CheckBoxRegex().IsChecked(true);
|
||||
}
|
||||
if (flags & EnumerateItems)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonEnumerateItems().IsChecked(true);
|
||||
}
|
||||
if (flags & ExcludeFiles)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonIncludeFiles().IsChecked(false);
|
||||
}
|
||||
if (flags & ExcludeFolders)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonIncludeFolders().IsChecked(false);
|
||||
}
|
||||
if (flags & ExcludeSubfolders)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonIncludeSubfolders().IsChecked(false);
|
||||
}
|
||||
if (flags & NameOnly)
|
||||
{
|
||||
m_mainUserControl.ComboBoxRenameParts().SelectedIndex(1);
|
||||
}
|
||||
else if (flags & ExtensionOnly)
|
||||
{
|
||||
m_mainUserControl.ComboBoxRenameParts().SelectedIndex(2);
|
||||
}
|
||||
if (flags & Uppercase)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonUpperCase().IsChecked(true);
|
||||
}
|
||||
else if (flags & Lowercase)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonLowerCase().IsChecked(true);
|
||||
}
|
||||
else if (flags & Titlecase)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonTitleCase().IsChecked(true);
|
||||
}
|
||||
else if (flags & Capitalized)
|
||||
{
|
||||
m_mainUserControl.ToggleButtonCapitalize().IsChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::UpdateCounts()
|
||||
{
|
||||
// This method is CPU intensive. We disable it during certain operations
|
||||
// for performance reasons.
|
||||
if (m_disableCountUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UINT selectedCount = 0;
|
||||
UINT renamingCount = 0;
|
||||
if (m_prManager)
|
||||
{
|
||||
m_prManager->GetSelectedItemCount(&selectedCount);
|
||||
m_prManager->GetRenameItemCount(&renamingCount);
|
||||
}
|
||||
|
||||
if (m_selectedCount != selectedCount ||
|
||||
m_renamingCount != renamingCount)
|
||||
{
|
||||
m_selectedCount = selectedCount;
|
||||
m_renamingCount = renamingCount;
|
||||
|
||||
// Update counts UI elements if/when added
|
||||
|
||||
// Update Rename button state
|
||||
m_mainUserControl.UIUpdatesItem().ButtonRenameEnabled(renamingCount > 0);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnItemAdded(_In_ IPowerRenameItem* renameItem)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnUpdate(_In_ IPowerRenameItem* renameItem)
|
||||
{
|
||||
int id;
|
||||
HRESULT hr = renameItem->GetId(&id);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PWSTR newName = nullptr;
|
||||
hr = renameItem->GetNewName(&newName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hstring newNameStr = newName == nullptr ? hstring{} : newName;
|
||||
m_mainUserControl.UpdateExplorerItem(id, newNameStr);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateCounts();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnRename(_In_ IPowerRenameItem* renameItem)
|
||||
{
|
||||
int id;
|
||||
HRESULT hr = renameItem->GetId(&id);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PWSTR newName = nullptr;
|
||||
hr = renameItem->GetOriginalName(&newName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hstring newNameStr = newName == nullptr ? hstring{} : newName;
|
||||
m_mainUserControl.UpdateRenamedExplorerItem(id, newNameStr);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateCounts();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnError(_In_ IPowerRenameItem* renameItem)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnRegExStarted(_In_ DWORD threadId)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnRegExCanceled(_In_ DWORD threadId)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnRegExCompleted(_In_ DWORD threadId)
|
||||
{
|
||||
if (m_flagValidationInProgress)
|
||||
{
|
||||
m_flagValidationInProgress = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD filter = 0;
|
||||
m_prManager->GetFilter(&filter);
|
||||
if (filter == PowerRenameFilters::ShouldRename)
|
||||
{
|
||||
m_mainUserControl.ExplorerItems().Clear();
|
||||
PopulateExplorerItems();
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnRenameStarted()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT AppWindow::OnRenameCompleted(bool closeUIWindowAfterRenaming)
|
||||
{
|
||||
if (closeUIWindowAfterRenaming)
|
||||
{
|
||||
// Close the window
|
||||
PostMessage(m_window, WM_CLOSE, (WPARAM)0, (LPARAM)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Force renaming work to start so newly renamed items are processed right away
|
||||
SearchReplaceChanged(true);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
|
||||
_In_opt_ HINSTANCE hPrevInstance,
|
||||
_In_ LPWSTR lpCmdLine,
|
||||
_In_ int nCmdShow)
|
||||
{
|
||||
#define BUFSIZE 4096 * 4
|
||||
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (hStdin == INVALID_HANDLE_VALUE)
|
||||
ExitProcess(1);
|
||||
BOOL bSuccess;
|
||||
WCHAR chBuf[BUFSIZE];
|
||||
DWORD dwRead;
|
||||
std::vector<std::wstring> files;
|
||||
for (;;)
|
||||
{
|
||||
// Read from standard input and stop on error or no data.
|
||||
bSuccess = ReadFile(hStdin, chBuf, BUFSIZE * sizeof(wchar_t), &dwRead, NULL);
|
||||
|
||||
if (!bSuccess || dwRead == 0)
|
||||
break;
|
||||
|
||||
std::wstring inputBatch{ chBuf, dwRead / sizeof(wchar_t) };
|
||||
|
||||
std::wstringstream ss(inputBatch);
|
||||
std::wstring item;
|
||||
wchar_t delimiter = '?';
|
||||
while (std::getline(ss, item, delimiter))
|
||||
{
|
||||
files.push_back(item);
|
||||
}
|
||||
|
||||
if (!bSuccess)
|
||||
break;
|
||||
}
|
||||
|
||||
g_hostHInst = hInstance;
|
||||
winrt::init_apartment(winrt::apartment_type::single_threaded);
|
||||
|
||||
winrt::PowerRenameUILib::App app;
|
||||
const auto result = AppWindow::Show(hInstance, files);
|
||||
app.Close();
|
||||
}
|
||||
153
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.h
Normal file
153
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
#include "resource.h"
|
||||
#include "XamlBridge.h"
|
||||
|
||||
#include <PowerRenameEnum.h>
|
||||
#include <PowerRenameItem.h>
|
||||
#include <PowerRenameManager.h>
|
||||
#include <PowerRenameInterfaces.h>
|
||||
#include <PowerRenameMRU.h>
|
||||
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.system.h>
|
||||
#pragma push_macro("GetCurrentTime")
|
||||
#undef GetCurrentTime
|
||||
#include <winrt/windows.ui.xaml.hosting.h>
|
||||
#pragma pop_macro("GetCurrentTime")
|
||||
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
|
||||
#include <winrt/windows.ui.xaml.controls.h>
|
||||
#include <winrt/windows.ui.xaml.controls.primitives.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#include <winrt/Windows.ui.xaml.data.h>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
#include <winrt/PowerRenameUILib.h>
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::UI;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Composition;
|
||||
using namespace Windows::UI::Xaml::Hosting;
|
||||
using namespace Windows::Foundation::Numerics;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
|
||||
class AppWindow : public DesktopWindowT<AppWindow>
|
||||
{
|
||||
public:
|
||||
// Proxy class to Advise() PRManager, as AppWindow can't implement IPowerRenameManagerEvents
|
||||
class UIHostPowerRenameManagerEvents : public IPowerRenameManagerEvents
|
||||
{
|
||||
public:
|
||||
UIHostPowerRenameManagerEvents(AppWindow* app) :
|
||||
m_refCount{ 1 }, m_app{ app }
|
||||
{
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_refCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG)
|
||||
Release()
|
||||
{
|
||||
long refCount = InterlockedDecrement(&m_refCount);
|
||||
|
||||
if (refCount == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
return refCount;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppv)
|
||||
{
|
||||
static const QITAB qit[] = {
|
||||
QITABENT(UIHostPowerRenameManagerEvents, IPowerRenameManagerEvents),
|
||||
{ 0 }
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
HRESULT OnItemAdded(_In_ IPowerRenameItem* renameItem) override { return m_app->OnItemAdded(renameItem); }
|
||||
HRESULT OnUpdate(_In_ IPowerRenameItem* renameItem) override { return m_app->OnUpdate(renameItem); }
|
||||
HRESULT OnRename(_In_ IPowerRenameItem* renameItem) override { return m_app->OnRename(renameItem); }
|
||||
HRESULT OnError(_In_ IPowerRenameItem* renameItem) override { return m_app->OnError(renameItem); }
|
||||
HRESULT OnRegExStarted(_In_ DWORD threadId) override { return m_app->OnRegExStarted(threadId); }
|
||||
HRESULT OnRegExCanceled(_In_ DWORD threadId) override { return m_app->OnRegExCanceled(threadId); }
|
||||
HRESULT OnRegExCompleted(_In_ DWORD threadId) override { return m_app->OnRegExCompleted(threadId); }
|
||||
HRESULT OnRenameStarted() override { return m_app->OnRenameStarted(); }
|
||||
HRESULT OnRenameCompleted(bool closeUIWindowAfterRenaming) override { return m_app->OnRenameCompleted(closeUIWindowAfterRenaming); }
|
||||
|
||||
private:
|
||||
long m_refCount;
|
||||
|
||||
AppWindow* m_app;
|
||||
};
|
||||
|
||||
static int Show(HINSTANCE hInstance, std::vector<std::wstring> files);
|
||||
LRESULT MessageHandler(UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
|
||||
private:
|
||||
enum class UpdateFlagCommand
|
||||
{
|
||||
Set = 0,
|
||||
Reset
|
||||
};
|
||||
|
||||
AppWindow(HINSTANCE hInstance, std::vector<std::wstring> files) noexcept;
|
||||
void CreateAndShowWindow();
|
||||
bool OnCreate(HWND, LPCREATESTRUCT) noexcept;
|
||||
void OnCommand(HWND, int id, HWND hwndControl, UINT codeNotify) noexcept;
|
||||
void OnDestroy(HWND hwnd) noexcept;
|
||||
void OnResize(HWND, UINT state, int cx, int cy) noexcept;
|
||||
HRESULT CreateShellItemArrayFromPaths(std::vector<std::wstring> files, IShellItemArray** shellItemArray);
|
||||
|
||||
void PopulateExplorerItems();
|
||||
HRESULT InitAutoComplete();
|
||||
HRESULT EnumerateShellItems(_In_ IEnumShellItems* enumShellItems);
|
||||
void SearchReplaceChanged(bool forceRenaming = false);
|
||||
void ValidateFlags(PowerRenameFlags flag);
|
||||
void UpdateFlag(PowerRenameFlags flag, UpdateFlagCommand command);
|
||||
void SetHandlers();
|
||||
void ToggleItem(int32_t id, bool checked);
|
||||
void ToggleAll();
|
||||
void SwitchView();
|
||||
void Rename(bool closeWindow);
|
||||
HRESULT ReadSettings();
|
||||
HRESULT WriteSettings();
|
||||
HRESULT OpenSettingsApp();
|
||||
void SetCheckboxesFromFlags(DWORD flags);
|
||||
void UpdateCounts();
|
||||
|
||||
HRESULT OnItemAdded(_In_ IPowerRenameItem* renameItem);
|
||||
HRESULT OnUpdate(_In_ IPowerRenameItem* renameItem);
|
||||
HRESULT OnRename(_In_ IPowerRenameItem* renameItem);
|
||||
HRESULT OnError(_In_ IPowerRenameItem* renameItem);
|
||||
HRESULT OnRegExStarted(_In_ DWORD threadId);
|
||||
HRESULT OnRegExCanceled(_In_ DWORD threadId);
|
||||
HRESULT OnRegExCompleted(_In_ DWORD threadId);
|
||||
HRESULT OnRenameStarted();
|
||||
HRESULT OnRenameCompleted(bool closeUIWindowAfterRenaming);
|
||||
|
||||
wil::unique_haccel m_accelerators;
|
||||
const HINSTANCE m_instance;
|
||||
HWND m_xamlIsland{};
|
||||
HWND m_window{};
|
||||
winrt::PowerRenameUILib::MainWindow m_mainUserControl{ nullptr };
|
||||
|
||||
bool m_disableCountUpdate = false;
|
||||
CComPtr<IPowerRenameManager> m_prManager;
|
||||
CComPtr<IUnknown> m_dataSource;
|
||||
CComPtr<IPowerRenameEnum> m_prEnum;
|
||||
UIHostPowerRenameManagerEvents m_managerEvents;
|
||||
DWORD m_cookie = 0;
|
||||
CComPtr<IPowerRenameMRU> m_searchMRU;
|
||||
CComPtr<IPowerRenameMRU> m_replaceMRU;
|
||||
UINT m_selectedCount = 0;
|
||||
UINT m_renamingCount = 0;
|
||||
|
||||
bool m_flagValidationInProgress = false;
|
||||
};
|
||||
BIN
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.ico
Normal file
BIN
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
BIN
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.rc
Normal file
BIN
src/modules/powerrename/PowerRenameUIHost/PowerRenameUIHost.rc
Normal file
Binary file not shown.
@@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{f7ec4e6c-19ca-4fbd-9918-b8ac5fef4f63}</ProjectGuid>
|
||||
<RootNamespace>PowerRenameUIHost</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>$(WindowsTargetPlatformVersion)</TargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WindowsAppContainer>false</WindowsAppContainer>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WindowsAppContainer>false</WindowsAppContainer>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings"></ImportGroup>
|
||||
<ImportGroup Label="Shared"></ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\Solution.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\Solution.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\PowerRename\</OutDir>
|
||||
<TargetName>PowerRename</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\PowerRename\</OutDir>
|
||||
<TargetName>PowerRename</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\;$(ProjectDir)..\..\..\common\Telemetry;$(ProjectDir)..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\;$(ProjectDir)..\..\..\common\Telemetry;$(ProjectDir)..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="PowerRenameUIHost.h" />
|
||||
<ClInclude Include="Resource.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="XamlBridge.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PowerRenameUIHost.cpp" />
|
||||
<ClCompile Include="XamlBridge.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PowerRenameUIHost.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="PowerRenameUIHost.ico" />
|
||||
<Image Include="small.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="app.manifest" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
<Import Project="..\..\..\..\packages\boost.1.72.0.0\build\boost.targets" Condition="Exists('..\..\..\..\packages\boost.1.72.0.0\build\boost.targets')" />
|
||||
<Import Project="..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets" Condition="Exists('..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.SDK.6.1.2\build\Microsoft.Toolkit.Win32.UI.SDK.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.7\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.210803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\boost.1.72.0.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost.1.72.0.0\build\boost.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_regex-vc142.1.72.0.0\build\boost_regex-vc142.targets'))" />
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<AppProjectName>PowerRenameUILib</AppProjectName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AppIncludeDirectories>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\;$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\Generated Files\;</AppIncludeDirectories>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\$(AppProjectName)\$(AppProjectName).vcxproj" />
|
||||
<ProjectReference Include="..\lib\PowerRenameLib.vcxproj">
|
||||
<Project>{51920f1f-c28c-4adf-8660-4238766796c2}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerRenameUIHost.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="XamlBridge.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PowerRenameUIHost.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XamlBridge.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PowerRenameUIHost.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="PowerRenameUIHost.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
<Image Include="small.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="app.manifest" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
30
src/modules/powerrename/PowerRenameUIHost/Resource.h
Normal file
30
src/modules/powerrename/PowerRenameUIHost/Resource.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by PowerRenameUIHost.rc
|
||||
|
||||
#define IDS_APP_TITLE 103
|
||||
|
||||
#define IDR_MAINFRAME 128
|
||||
#define IDD_POWERRENAMEUIHOST_DIALOG 102
|
||||
#define IDD_ABOUTBOX 103
|
||||
#define IDM_ABOUT 104
|
||||
#define IDM_EXIT 105
|
||||
#define IDI_POWERRENAMEUIHOST 107
|
||||
#define IDI_SMALL 108
|
||||
#define IDC_POWERRENAMEUIHOST 109
|
||||
#define IDC_MYICON 2
|
||||
#ifndef IDC_STATIC
|
||||
#define IDC_STATIC -1
|
||||
#endif
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
#define _APS_NO_MFC 130
|
||||
#define _APS_NEXT_RESOURCE_VALUE 129
|
||||
#define _APS_NEXT_COMMAND_VALUE 32771
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 110
|
||||
#endif
|
||||
#endif
|
||||
249
src/modules/powerrename/PowerRenameUIHost/XamlBridge.cpp
Normal file
249
src/modules/powerrename/PowerRenameUIHost/XamlBridge.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "XamlBridge.h"
|
||||
#include "Resource.h"
|
||||
#include <exception>
|
||||
|
||||
bool DesktopWindow::FilterMessage(const MSG* msg)
|
||||
{
|
||||
// When multiple child windows are present it is needed to pre dispatch messages to all
|
||||
// DesktopWindowXamlSource instances so keyboard accelerators and
|
||||
// keyboard focus work correctly.
|
||||
for (auto& xamlSource : m_xamlSources)
|
||||
{
|
||||
BOOL xamlSourceProcessedMessage = FALSE;
|
||||
winrt::check_hresult(xamlSource.as<IDesktopWindowXamlSourceNative2>()->PreTranslateMessage(msg, &xamlSourceProcessedMessage));
|
||||
if (xamlSourceProcessedMessage != FALSE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto static invalidReason = static_cast<winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason>(-1);
|
||||
|
||||
winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason GetReasonFromKey(WPARAM key)
|
||||
{
|
||||
auto reason = invalidReason;
|
||||
if (key == VK_TAB)
|
||||
{
|
||||
byte keyboardState[256] = {};
|
||||
WINRT_VERIFY(::GetKeyboardState(keyboardState));
|
||||
reason = (keyboardState[VK_SHIFT] & 0x80) ?
|
||||
winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Last :
|
||||
winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First;
|
||||
}
|
||||
else if (key == VK_LEFT)
|
||||
{
|
||||
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Left;
|
||||
}
|
||||
else if (key == VK_RIGHT)
|
||||
{
|
||||
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right;
|
||||
}
|
||||
else if (key == VK_UP)
|
||||
{
|
||||
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Up;
|
||||
}
|
||||
else if (key == VK_DOWN)
|
||||
{
|
||||
reason = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down;
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource DesktopWindow::GetNextFocusedIsland(const MSG* msg)
|
||||
{
|
||||
if (msg->message == WM_KEYDOWN)
|
||||
{
|
||||
const auto key = msg->wParam;
|
||||
auto reason = GetReasonFromKey(key);
|
||||
if (reason != invalidReason)
|
||||
{
|
||||
const BOOL previous =
|
||||
(reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First ||
|
||||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down ||
|
||||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right) ?
|
||||
false :
|
||||
true;
|
||||
|
||||
const auto currentFocusedWindow = ::GetFocus();
|
||||
const auto nextElement = ::GetNextDlgTabItem(m_window.get(), currentFocusedWindow, previous);
|
||||
for (auto& xamlSource : m_xamlSources)
|
||||
{
|
||||
HWND islandWnd{};
|
||||
winrt::check_hresult(xamlSource.as<IDesktopWindowXamlSourceNative>()->get_WindowHandle(&islandWnd));
|
||||
if (nextElement == islandWnd)
|
||||
{
|
||||
return xamlSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource DesktopWindow::GetFocusedIsland()
|
||||
{
|
||||
for (auto& xamlSource : m_xamlSources)
|
||||
{
|
||||
if (xamlSource.HasFocus())
|
||||
{
|
||||
return xamlSource;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool DesktopWindow::NavigateFocus(MSG* msg)
|
||||
{
|
||||
if (const auto nextFocusedIsland = GetNextFocusedIsland(msg))
|
||||
{
|
||||
const auto previousFocusedWindow = ::GetFocus();
|
||||
RECT rect = {};
|
||||
WINRT_VERIFY(::GetWindowRect(previousFocusedWindow, &rect));
|
||||
const auto nativeIsland = nextFocusedIsland.as<IDesktopWindowXamlSourceNative>();
|
||||
HWND islandWnd = nullptr;
|
||||
winrt::check_hresult(nativeIsland->get_WindowHandle(&islandWnd));
|
||||
POINT pt = { rect.left, rect.top };
|
||||
SIZE size = { rect.right - rect.left, rect.bottom - rect.top };
|
||||
::ScreenToClient(islandWnd, &pt);
|
||||
const auto hintRect = winrt::Windows::Foundation::Rect({ static_cast<float>(pt.x), static_cast<float>(pt.y), static_cast<float>(size.cx), static_cast<float>(size.cy) });
|
||||
const auto reason = GetReasonFromKey(msg->wParam);
|
||||
const auto request = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationRequest(reason, hintRect);
|
||||
m_lastFocusRequestId = request.CorrelationId();
|
||||
const auto result = nextFocusedIsland.NavigateFocus(request);
|
||||
return result.WasFocusMoved();
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool islandIsFocused = GetFocusedIsland() != nullptr;
|
||||
byte keyboardState[256] = {};
|
||||
WINRT_VERIFY(::GetKeyboardState(keyboardState));
|
||||
const bool isMenuModifier = keyboardState[VK_MENU] & 0x80;
|
||||
if (islandIsFocused && !isMenuModifier)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const bool isDialogMessage = !!IsDialogMessage(m_window.get(), msg);
|
||||
return isDialogMessage;
|
||||
}
|
||||
}
|
||||
|
||||
int DesktopWindow::MessageLoop(HACCEL accelerators)
|
||||
{
|
||||
MSG msg = {};
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
const bool processedMessage = FilterMessage(&msg);
|
||||
if (!processedMessage && !TranslateAcceleratorW(msg.hwnd, accelerators, &msg))
|
||||
{
|
||||
if (!NavigateFocus(&msg))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return static_cast<int>(msg.wParam);
|
||||
}
|
||||
|
||||
static const WPARAM invalidKey = (WPARAM)-1;
|
||||
|
||||
WPARAM GetKeyFromReason(winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason reason)
|
||||
{
|
||||
auto key = invalidKey;
|
||||
if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Last || reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First)
|
||||
{
|
||||
key = VK_TAB;
|
||||
}
|
||||
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Left)
|
||||
{
|
||||
key = VK_LEFT;
|
||||
}
|
||||
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right)
|
||||
{
|
||||
key = VK_RIGHT;
|
||||
}
|
||||
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Up)
|
||||
{
|
||||
key = VK_UP;
|
||||
}
|
||||
else if (reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down)
|
||||
{
|
||||
key = VK_DOWN;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
void DesktopWindow::OnTakeFocusRequested(winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource const& sender, winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSourceTakeFocusRequestedEventArgs const& args)
|
||||
{
|
||||
if (args.Request().CorrelationId() != m_lastFocusRequestId)
|
||||
{
|
||||
const auto reason = args.Request().Reason();
|
||||
const BOOL previous =
|
||||
(reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::First ||
|
||||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Down ||
|
||||
reason == winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Right) ?
|
||||
false :
|
||||
true;
|
||||
|
||||
const auto nativeXamlSource = sender.as<IDesktopWindowXamlSourceNative>();
|
||||
HWND senderHwnd = nullptr;
|
||||
winrt::check_hresult(nativeXamlSource->get_WindowHandle(&senderHwnd));
|
||||
|
||||
MSG msg = {};
|
||||
msg.hwnd = senderHwnd;
|
||||
msg.message = WM_KEYDOWN;
|
||||
msg.wParam = GetKeyFromReason(reason);
|
||||
if (!NavigateFocus(&msg))
|
||||
{
|
||||
const auto nextElement = ::GetNextDlgTabItem(m_window.get(), senderHwnd, previous);
|
||||
::SetFocus(nextElement);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto request = winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationRequest(winrt::Windows::UI::Xaml::Hosting::XamlSourceFocusNavigationReason::Restore);
|
||||
m_lastFocusRequestId = request.CorrelationId();
|
||||
sender.NavigateFocus(request);
|
||||
}
|
||||
}
|
||||
|
||||
HWND DesktopWindow::CreateDesktopWindowsXamlSource(DWORD extraWindowStyles, const winrt::Windows::UI::Xaml::UIElement& content)
|
||||
{
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource desktopSource;
|
||||
|
||||
auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();
|
||||
// Parent the DesktopWindowXamlSource object to current window
|
||||
winrt::check_hresult(interop->AttachToWindow(m_window.get()));
|
||||
HWND xamlSourceWindow{}; // Lifetime controlled desktopSource
|
||||
winrt::check_hresult(interop->get_WindowHandle(&xamlSourceWindow));
|
||||
const DWORD style = GetWindowLongW(xamlSourceWindow, GWL_STYLE) | extraWindowStyles;
|
||||
SetWindowLongW(xamlSourceWindow, GWL_STYLE, style);
|
||||
|
||||
desktopSource.Content(content);
|
||||
|
||||
m_takeFocusEventRevokers.push_back(desktopSource.TakeFocusRequested(winrt::auto_revoke, { this, &DesktopWindow::OnTakeFocusRequested }));
|
||||
m_xamlSources.push_back(desktopSource);
|
||||
|
||||
return xamlSourceWindow;
|
||||
}
|
||||
|
||||
void DesktopWindow::ClearXamlIslands()
|
||||
{
|
||||
for (auto& takeFocusRevoker : m_takeFocusEventRevokers)
|
||||
{
|
||||
takeFocusRevoker.revoke();
|
||||
}
|
||||
m_takeFocusEventRevokers.clear();
|
||||
|
||||
for (auto& xamlSource : m_xamlSources)
|
||||
{
|
||||
xamlSource.Close();
|
||||
}
|
||||
m_xamlSources.clear();
|
||||
}
|
||||
108
src/modules/powerrename/PowerRenameUIHost/XamlBridge.h
Normal file
108
src/modules/powerrename/PowerRenameUIHost/XamlBridge.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include <unknwn.h> // To enable support for non-WinRT interfaces, unknwn.h must be included before any C++/WinRT headers.
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#pragma push_macro("GetCurrentTime")
|
||||
#undef GetCurrentTime
|
||||
#include <winrt/Windows.UI.Xaml.Hosting.h>
|
||||
#pragma pop_macro("GetCurrentTime")
|
||||
#include <winrt/Windows.UI.Xaml.Markup.h>
|
||||
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
|
||||
#include <windowsx.h>
|
||||
#include <wil/resource.h>
|
||||
|
||||
class DesktopWindow
|
||||
{
|
||||
protected:
|
||||
int MessageLoop(HACCEL accelerators);
|
||||
HWND CreateDesktopWindowsXamlSource(DWORD extraStyles, const winrt::Windows::UI::Xaml::UIElement& content);
|
||||
void ClearXamlIslands();
|
||||
|
||||
HWND WindowHandle() const
|
||||
{
|
||||
return m_window.get();
|
||||
}
|
||||
|
||||
static void OnNCCreate(HWND window, LPARAM lparam) noexcept
|
||||
{
|
||||
auto cs = reinterpret_cast<CREATESTRUCT*>(lparam);
|
||||
auto that = static_cast<DesktopWindow*>(cs->lpCreateParams);
|
||||
that->m_window.reset(window); // take ownership of the window
|
||||
SetWindowLongPtrW(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource GetFocusedIsland();
|
||||
bool FilterMessage(const MSG* msg);
|
||||
void OnTakeFocusRequested(winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource const& sender, winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSourceTakeFocusRequestedEventArgs const& args);
|
||||
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource GetNextFocusedIsland(const MSG* msg);
|
||||
bool NavigateFocus(MSG* msg);
|
||||
|
||||
wil::unique_hwnd m_window;
|
||||
winrt::guid m_lastFocusRequestId;
|
||||
std::vector<winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource::TakeFocusRequested_revoker> m_takeFocusEventRevokers;
|
||||
std::vector<winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource> m_xamlSources;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DesktopWindowT : public DesktopWindow
|
||||
{
|
||||
protected:
|
||||
using base_type = DesktopWindowT<T>;
|
||||
|
||||
static LRESULT __stdcall WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||
{
|
||||
if (message == WM_NCCREATE)
|
||||
{
|
||||
OnNCCreate(window, lparam);
|
||||
}
|
||||
else if (message == WM_NCDESTROY)
|
||||
{
|
||||
SetWindowLongPtrW(window, GWLP_USERDATA, 0);
|
||||
}
|
||||
else if (auto that = reinterpret_cast<T*>(GetWindowLongPtrW(window, GWLP_USERDATA)))
|
||||
{
|
||||
return that->MessageHandler(message, wparam, lparam);
|
||||
}
|
||||
|
||||
return DefWindowProcW(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
LRESULT MessageHandler(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
HANDLE_MSG(WindowHandle(), WM_DESTROY, OnDestroy);
|
||||
HANDLE_MSG(WindowHandle(), WM_ACTIVATE, OnActivate);
|
||||
HANDLE_MSG(WindowHandle(), WM_SETFOCUS, OnSetFocus);
|
||||
}
|
||||
return DefWindowProcW(WindowHandle(), message, wParam, lParam);
|
||||
}
|
||||
|
||||
void OnDestroy(HWND)
|
||||
{
|
||||
ClearXamlIslands();
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
private:
|
||||
void OnActivate(HWND, UINT state, HWND hwndActDeact, BOOL fMinimized)
|
||||
{
|
||||
if (state == WA_INACTIVE)
|
||||
{
|
||||
m_hwndLastFocus = GetFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void OnSetFocus(HWND, HWND hwndOldFocus)
|
||||
{
|
||||
if (m_hwndLastFocus)
|
||||
{
|
||||
SetFocus(m_hwndLastFocus);
|
||||
}
|
||||
}
|
||||
|
||||
HWND m_hwndLastFocus = nullptr;
|
||||
};
|
||||
8
src/modules/powerrename/PowerRenameUIHost/app.manifest
Normal file
8
src/modules/powerrename/PowerRenameUIHost/app.manifest
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmV3="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
|
||||
<asmV3:file name="PowerRenameUILib.dll">
|
||||
<activatableClass name="PowerRenameUILib.App" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
|
||||
<activatableClass name="PowerRenameUILib.XamlMetadataProvider" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
|
||||
<activatableClass name="PowerRenameUILib.MainWindow" threadingModel="both" xmlns="urn:schemas-microsoft-com:winrt.v1" />
|
||||
</asmV3:file>
|
||||
</assembly>
|
||||
15
src/modules/powerrename/PowerRenameUIHost/framework.h
Normal file
15
src/modules/powerrename/PowerRenameUIHost/framework.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// header.h : include file for standard system include files,
|
||||
// or project specific include files
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
// #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
// C RunTime Header Files
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include <tchar.h>
|
||||
10
src/modules/powerrename/PowerRenameUIHost/packages.config
Normal file
10
src/modules/powerrename/PowerRenameUIHost/packages.config
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="boost" version="1.72.0.0" targetFramework="native" />
|
||||
<package id="boost_regex-vc142" version="1.72.0.0" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.SDK" version="6.1.2" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.7" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.210803.1" targetFramework="native" />
|
||||
</packages>
|
||||
1
src/modules/powerrename/PowerRenameUIHost/pch.cpp
Normal file
1
src/modules/powerrename/PowerRenameUIHost/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
5
src/modules/powerrename/PowerRenameUIHost/pch.h
Normal file
5
src/modules/powerrename/PowerRenameUIHost/pch.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "framework.h"
|
||||
#include <atlstr.h>
|
||||
#include <stack>
|
||||
BIN
src/modules/powerrename/PowerRenameUIHost/small.ico
Normal file
BIN
src/modules/powerrename/PowerRenameUIHost/small.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
8
src/modules/powerrename/PowerRenameUIHost/targetver.h
Normal file
8
src/modules/powerrename/PowerRenameUIHost/targetver.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
Reference in New Issue
Block a user