mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 18:26:39 +02:00
[FancyZones] Use Ctrl+Win+Alt+arrows to Expand/shrink windows to adjacent zones (#6446)
* Added an Alt key hook * Refactor a block of code into a method * Again refactored existing code * Apparently Win+Alt does not reach FancyZones * Using Ctrl+alt instead of Win+alt for now * It works * Fixed VD change * Remove unused member * Fix compilation error * Enable shrinking * Fixed comments in .h files * Remove newline * Refactored a function into two The next task is to simplify their code. * Updated a comment * Update a variable name * Reverted to the old implementation of directional move * More refactoring * Remove space * Fixed windows getting stuck * Changed function name
This commit is contained in:
@@ -143,12 +143,16 @@ public:
|
||||
MoveWindowIntoZoneByDirectionAndIndex(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
MoveWindowIntoZoneByDirectionAndPosition(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
ExtendWindowByDirectionAndPosition(HWND window, HWND windowZone, DWORD vkCode) noexcept;
|
||||
IFACEMETHODIMP_(void)
|
||||
MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
CalculateZones(RECT workArea, int zoneCount, int spacing) noexcept;
|
||||
IFACEMETHODIMP_(bool)
|
||||
IsZoneEmpty(int zoneIndex) noexcept;
|
||||
IFACEMETHODIMP_(std::vector<size_t>)
|
||||
GetCombinedZoneRange(const std::vector<size_t>& initialZones, const std::vector<size_t>& finalZones) noexcept;
|
||||
|
||||
private:
|
||||
bool CalculateFocusLayout(Rect workArea, int zoneCount) noexcept;
|
||||
@@ -161,6 +165,12 @@ private:
|
||||
|
||||
std::vector<winrt::com_ptr<IZone>> m_zones;
|
||||
std::map<HWND, std::vector<size_t>> m_windowIndexSet;
|
||||
|
||||
// Needed for ExtendWindowByDirectionAndPosition
|
||||
std::map<HWND, std::vector<size_t>> m_windowInitialIndexSet;
|
||||
std::map<HWND, size_t> m_windowFinalIndex;
|
||||
bool m_inExtendWindow = false;
|
||||
|
||||
ZoneSetConfig m_config;
|
||||
};
|
||||
|
||||
@@ -276,6 +286,13 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::v
|
||||
return;
|
||||
}
|
||||
|
||||
// Always clear the info related to SelectManyZones if it's not being used
|
||||
if (!m_inExtendWindow)
|
||||
{
|
||||
m_windowFinalIndex.erase(window);
|
||||
m_windowInitialIndexSet.erase(window);
|
||||
}
|
||||
|
||||
RECT size;
|
||||
bool sizeEmpty = true;
|
||||
size_t bitmask = 0;
|
||||
@@ -410,12 +427,15 @@ ZoneSet::MoveWindowIntoZoneByDirectionAndPosition(HWND window, HWND windowZone,
|
||||
else if (cycle)
|
||||
{
|
||||
// Try again from the position off the screen in the opposite direction to vkCode
|
||||
// Consider all zones as available
|
||||
zoneRects.resize(zoneObjects.size());
|
||||
std::transform(zoneObjects.begin(), zoneObjects.end(), zoneRects.begin(), [](auto zone) { return zone->GetZoneRect(); });
|
||||
windowRect = FancyZonesUtils::PrepareRectForCycling(windowRect, windowZoneRect, vkCode);
|
||||
result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
||||
|
||||
if (result < zoneRects.size())
|
||||
{
|
||||
MoveWindowIntoZoneByIndex(window, windowZone, freeZoneIndices[result]);
|
||||
MoveWindowIntoZoneByIndex(window, windowZone, result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -424,6 +444,93 @@ ZoneSet::MoveWindowIntoZoneByDirectionAndPosition(HWND window, HWND windowZone,
|
||||
return false;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(bool)
|
||||
ZoneSet::ExtendWindowByDirectionAndPosition(HWND window, HWND windowZone, DWORD vkCode) noexcept
|
||||
{
|
||||
if (m_zones.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RECT windowRect, windowZoneRect;
|
||||
if (GetWindowRect(window, &windowRect) && GetWindowRect(windowZone, &windowZoneRect))
|
||||
{
|
||||
auto zoneObjects = GetZones();
|
||||
auto oldZones = GetZoneIndexSetFromWindow(window);
|
||||
std::vector<bool> usedZoneIndices(zoneObjects.size(), false);
|
||||
std::vector<RECT> zoneRects;
|
||||
std::vector<size_t> freeZoneIndices;
|
||||
|
||||
// If selectManyZones = true for the second time, use the last zone into which we moved
|
||||
// instead of the window rect and enable moving to all zones except the old one
|
||||
auto finalIndexIt = m_windowFinalIndex.find(window);
|
||||
if (finalIndexIt != m_windowFinalIndex.end())
|
||||
{
|
||||
usedZoneIndices[finalIndexIt->second] = true;
|
||||
windowRect = zoneObjects[finalIndexIt->second]->GetZoneRect();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t idx : oldZones)
|
||||
{
|
||||
usedZoneIndices[idx] = true;
|
||||
}
|
||||
// Move to coordinates relative to windowZone
|
||||
windowRect.top -= windowZoneRect.top;
|
||||
windowRect.bottom -= windowZoneRect.top;
|
||||
windowRect.left -= windowZoneRect.left;
|
||||
windowRect.right -= windowZoneRect.left;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < zoneObjects.size(); i++)
|
||||
{
|
||||
if (!usedZoneIndices[i])
|
||||
{
|
||||
zoneRects.emplace_back(zoneObjects[i]->GetZoneRect());
|
||||
freeZoneIndices.emplace_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
size_t result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
||||
if (result < zoneRects.size())
|
||||
{
|
||||
size_t targetZone = freeZoneIndices[result];
|
||||
std::vector<size_t> resultIndexSet;
|
||||
|
||||
// First time with selectManyZones = true for this window?
|
||||
if (finalIndexIt == m_windowFinalIndex.end())
|
||||
{
|
||||
// Already zoned?
|
||||
if (oldZones.size())
|
||||
{
|
||||
m_windowInitialIndexSet[window] = oldZones;
|
||||
m_windowFinalIndex[window] = targetZone;
|
||||
resultIndexSet = GetCombinedZoneRange(oldZones, { targetZone });
|
||||
}
|
||||
else
|
||||
{
|
||||
m_windowInitialIndexSet[window] = { targetZone };
|
||||
m_windowFinalIndex[window] = targetZone;
|
||||
resultIndexSet = { targetZone };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto deletethis = m_windowInitialIndexSet[window];
|
||||
m_windowFinalIndex[window] = targetZone;
|
||||
resultIndexSet = GetCombinedZoneRange(m_windowInitialIndexSet[window], { targetZone });
|
||||
}
|
||||
|
||||
m_inExtendWindow = true;
|
||||
MoveWindowIntoZoneByIndexSet(window, windowZone, resultIndexSet);
|
||||
m_inExtendWindow = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void)
|
||||
ZoneSet::MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept
|
||||
{
|
||||
@@ -779,6 +886,48 @@ void ZoneSet::StampWindow(HWND window, size_t bitmask) noexcept
|
||||
SetProp(window, ZonedWindowProperties::PropertyMultipleZoneID, reinterpret_cast<HANDLE>(bitmask));
|
||||
}
|
||||
|
||||
std::vector<size_t> ZoneSet::GetCombinedZoneRange(const std::vector<size_t>& initialZones, const std::vector<size_t>& finalZones) noexcept
|
||||
{
|
||||
std::vector<size_t> combinedZones, result;
|
||||
std::set_union(begin(initialZones), end(initialZones), begin(finalZones), end(finalZones), std::back_inserter(combinedZones));
|
||||
|
||||
RECT boundingRect;
|
||||
bool boundingRectEmpty = true;
|
||||
auto zones = GetZones();
|
||||
|
||||
for (size_t zoneId : combinedZones)
|
||||
{
|
||||
RECT rect = zones[zoneId]->GetZoneRect();
|
||||
if (boundingRectEmpty)
|
||||
{
|
||||
boundingRect = rect;
|
||||
boundingRectEmpty = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
boundingRect.left = min(boundingRect.left, rect.left);
|
||||
boundingRect.top = min(boundingRect.top, rect.top);
|
||||
boundingRect.right = max(boundingRect.right, rect.right);
|
||||
boundingRect.bottom = max(boundingRect.bottom, rect.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
if (!boundingRectEmpty)
|
||||
{
|
||||
for (size_t zoneId = 0; zoneId < zones.size(); zoneId++)
|
||||
{
|
||||
RECT rect = zones[zoneId]->GetZoneRect();
|
||||
if (boundingRect.left <= rect.left && rect.right <= boundingRect.right &&
|
||||
boundingRect.top <= rect.top && rect.bottom <= boundingRect.bottom)
|
||||
{
|
||||
result.push_back(zoneId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
winrt::com_ptr<IZoneSet> MakeZoneSet(ZoneSetConfig const& config) noexcept
|
||||
{
|
||||
return winrt::make_self<ZoneSet>(config);
|
||||
|
||||
Reference in New Issue
Block a user