Basic support for snapping to multiple zones (#1955)

* Refactor a method which resizes windows

* Completed initial work for MultiZones

Without changing any test, they all pass!

* Implemented a basic version of Multizones, updated some tests

* Reduced the sensitivity radius

* Added a few must-have unit tests for Multizones

* Some fixups

* Took care of the conflict between this and #1938

* Improved how zones are detected, reverted a change in one unit test

* Resolved another merge conflict

* Fixed bugs related to stamping
This commit is contained in:
Ivan Stošić
2020-04-10 16:09:08 +02:00
committed by GitHub
parent e896e1b3dd
commit 629ba763d7
11 changed files with 328 additions and 128 deletions

View File

@@ -150,6 +150,7 @@ public:
void AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept;
void MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept;
void MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept;
protected:
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
@@ -695,6 +696,12 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
}
void FancyZones::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index) noexcept
{
std::shared_lock readLock(m_lock);
MoveWindowIntoZoneByIndexSet(window, monitor, { index });
}
void FancyZones::MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet) noexcept
{
std::shared_lock readLock(m_lock);
if (window != m_windowMoveSize)
@@ -706,7 +713,7 @@ void FancyZones::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int in
if (zoneWindow != m_zoneWindowMap.end())
{
const auto& zoneWindowPtr = zoneWindow->second;
zoneWindowPtr->MoveWindowIntoZoneByIndex(window, index);
zoneWindowPtr->MoveWindowIntoZoneByIndexSet(window, indexSet);
}
}
}

View File

@@ -4,6 +4,7 @@
#include <common/monitors.h>
#include "Zone.h"
#include "Settings.h"
#include "util.h"
struct Zone : winrt::implements<Zone, IZone>
{
@@ -20,6 +21,7 @@ public:
IFACEMETHODIMP_(void) RemoveWindowFromZone(HWND window, bool restoreSize) noexcept;
IFACEMETHODIMP_(void) SetId(size_t id) noexcept { m_id = id; }
IFACEMETHODIMP_(size_t) Id() noexcept { return m_id; }
IFACEMETHODIMP_(RECT) ComputeActualZoneRect(HWND window, HWND zoneWindow) noexcept;
private:
void SizeWindowToZone(HWND window, HWND zoneWindow) noexcept;
@@ -61,12 +63,11 @@ IFACEMETHODIMP_(void) Zone::RemoveWindowFromZone(HWND window, bool restoreSize)
void Zone::SizeWindowToZone(HWND window, HWND zoneWindow) noexcept
{
// Skip invisible windows
if (!IsWindowVisible(window))
{
return;
}
SizeWindowToRect(window, ComputeActualZoneRect(window, zoneWindow));
}
RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) noexcept
{
// Take care of 1px border
RECT newWindowRect = m_zoneRect;
@@ -111,29 +112,7 @@ void Zone::SizeWindowToZone(HWND window, HWND zoneWindow) noexcept
newWindowRect.bottom = newWindowRect.top + (windowRect.bottom - windowRect.top);
}
WINDOWPLACEMENT placement{};
::GetWindowPlacement(window, &placement);
//wait if SW_SHOWMINIMIZED would be removed from window (Issue #1685)
for (int i = 0; i < 5 && (placement.showCmd & SW_SHOWMINIMIZED) != 0; i++)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
::GetWindowPlacement(window, &placement);
}
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
if ((placement.showCmd & SW_SHOWMINIMIZED) == 0)
{
placement.showCmd = SW_RESTORE | SW_SHOWNA;
}
placement.rcNormalPosition = newWindowRect;
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
::SetWindowPlacement(window, &placement);
// Do it again, allowing Windows to resize the window and set correct scaling
// This fixes Issue #365
::SetWindowPlacement(window, &placement);
return newWindowRect;
}
void Zone::StampZone(HWND window, bool stamp) noexcept

View File

@@ -42,9 +42,20 @@ interface __declspec(uuid("{8228E934-B6EF-402A-9892-15A1441BF8B0}")) IZone : pub
*/
IFACEMETHOD_(void, SetId)(size_t id) = 0;
/**
* @retirns Zone identifier.
* @returns Zone identifier.
*/
IFACEMETHOD_(size_t, Id)() = 0;
/**
* Compute the coordinates of the rectangle to which a window should be resized.
*
* @param window Handle of window which should be assigned to zone.
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
* current monitor desktop work area.
* @returns a RECT structure, describing global coordinates to which a window should be resized
*/
IFACEMETHOD_(RECT, ComputeActualZoneRect)(HWND window, HWND zoneWindow) = 0;
};
winrt::com_ptr<IZone> MakeZone(const RECT& zoneRect) noexcept;

View File

@@ -122,14 +122,16 @@ public:
IFACEMETHODIMP_(JSONHelpers::ZoneSetLayoutType)
LayoutType() noexcept { return m_config.LayoutType; }
IFACEMETHODIMP AddZone(winrt::com_ptr<IZone> zone) noexcept;
IFACEMETHODIMP_(winrt::com_ptr<IZone>)
ZoneFromPoint(POINT pt) noexcept;
IFACEMETHODIMP_(std::vector<int>)
ZonesFromPoint(POINT pt) noexcept;
IFACEMETHODIMP_(int)
GetZoneIndexFromWindow(HWND window) noexcept;
IFACEMETHODIMP_(std::vector<winrt::com_ptr<IZone>>)
GetZones() noexcept { return m_zones; }
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByIndex(HWND window, HWND zoneWindow, int index) noexcept;
MoveWindowIntoZoneByIndex(HWND window, HWND zoneWindow, int index, bool stampZone) noexcept;
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::vector<int>& indexSet, bool stampZone) noexcept;
IFACEMETHODIMP_(bool)
MoveWindowIntoZoneByDirection(HWND window, HWND zoneWindow, DWORD vkCode, bool cycle) noexcept;
IFACEMETHODIMP_(void)
@@ -162,41 +164,79 @@ IFACEMETHODIMP ZoneSet::AddZone(winrt::com_ptr<IZone> zone) noexcept
return S_OK;
}
IFACEMETHODIMP_(winrt::com_ptr<IZone>)
ZoneSet::ZoneFromPoint(POINT pt) noexcept
IFACEMETHODIMP_(std::vector<int>)
ZoneSet::ZonesFromPoint(POINT pt) noexcept
{
winrt::com_ptr<IZone> smallestKnownZone = nullptr;
// To reduce redundant calculations, we will store the last known zones area.
int smallestKnownZoneArea = INT32_MAX;
for (auto iter = m_zones.rbegin(); iter != m_zones.rend(); iter++)
const int SENSITIVITY_RADIUS = 20;
std::vector<int> capturedZones;
std::vector<int> strictlyCapturedZones;
for (size_t i = 0; i < m_zones.size(); i++)
{
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
auto zone = m_zones[i];
RECT newZoneRect = zone->GetZoneRect();
if (newZoneRect.left < newZoneRect.right && newZoneRect.top < newZoneRect.bottom) // proper zone
{
RECT* newZoneRect = &zone->GetZoneRect();
if (PtInRect(newZoneRect, pt))
if (newZoneRect.left - SENSITIVITY_RADIUS <= pt.x && pt.x <= newZoneRect.right + SENSITIVITY_RADIUS &&
newZoneRect.top - SENSITIVITY_RADIUS <= pt.y && pt.y <= newZoneRect.bottom + SENSITIVITY_RADIUS)
{
if (smallestKnownZone == nullptr)
{
smallestKnownZone = zone;
capturedZones.emplace_back(static_cast<int>(i));
}
RECT* r = &smallestKnownZone->GetZoneRect();
smallestKnownZoneArea = (r->right - r->left) * (r->bottom - r->top);
}
else
if (newZoneRect.left <= pt.x && pt.x < newZoneRect.right &&
newZoneRect.top <= pt.y && pt.y < newZoneRect.bottom)
{
int newZoneArea = (newZoneRect->right - newZoneRect->left) * (newZoneRect->bottom - newZoneRect->top);
if (newZoneArea < smallestKnownZoneArea)
{
smallestKnownZone = zone;
smallestKnownZoneArea = newZoneArea;
}
}
strictlyCapturedZones.emplace_back(static_cast<int>(i));
}
}
}
return smallestKnownZone;
// If only one zone is captured, but it's not strictly captured
// don't consider it as captured
if (capturedZones.size() == 1 && strictlyCapturedZones.size() == 0)
{
return {};
}
// If captured zones do not overlap, return all of them
// Otherwise, return the smallest one
bool overlap = false;
for (size_t i = 0; i < capturedZones.size(); ++i)
{
for (size_t j = i + 1; j < capturedZones.size(); ++j)
{
auto rectI = m_zones[capturedZones[i]]->GetZoneRect();
auto rectJ = m_zones[capturedZones[j]]->GetZoneRect();
if (max(rectI.top, rectJ.top) < min(rectI.bottom, rectJ.bottom) &&
max(rectI.left, rectJ.left) < min(rectI.right, rectJ.right))
{
overlap = true;
i = capturedZones.size() - 1;
break;
}
}
}
if (overlap)
{
size_t smallestIdx = 0;
for (size_t i = 1; i < capturedZones.size(); ++i)
{
auto rectS = m_zones[capturedZones[smallestIdx]]->GetZoneRect();
auto rectI = m_zones[capturedZones[i]]->GetZoneRect();
int smallestSize = (rectS.bottom - rectS.top) * (rectS.right - rectS.left);
int iSize = (rectI.bottom - rectI.top) * (rectI.right - rectI.left);
if (iSize <= smallestSize)
{
smallestIdx = i;
}
}
capturedZones = { capturedZones[smallestIdx] };
}
return capturedZones;
}
IFACEMETHODIMP_(int)
@@ -217,7 +257,7 @@ ZoneSet::GetZoneIndexFromWindow(HWND window) noexcept
}
IFACEMETHODIMP_(void)
ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index) noexcept
ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index, bool stampZone) noexcept
{
if (m_zones.empty())
{
@@ -236,7 +276,55 @@ ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index) noex
if (auto zone = m_zones.at(index))
{
zone->AddWindowToZone(window, windowZone, false);
zone->AddWindowToZone(window, windowZone, stampZone);
}
}
IFACEMETHODIMP_(void)
ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::vector<int>& indexSet, bool stampZone) noexcept
{
if (m_zones.empty())
{
return;
}
while (auto zoneDrop = ZoneFromWindow(window))
{
zoneDrop->RemoveWindowFromZone(window, !IsZoomed(window));
}
if (indexSet.size() == 1)
{
MoveWindowIntoZoneByIndex(window, windowZone, indexSet[0], stampZone);
return;
}
RECT size;
bool sizeEmpty = true;
for (int index : indexSet)
{
if (index < static_cast<int>(m_zones.size()))
{
RECT newSize = m_zones.at(index)->ComputeActualZoneRect(window, windowZone);
if (!sizeEmpty)
{
size.left = min(size.left, newSize.left);
size.top = min(size.top, newSize.top);
size.right = max(size.right, newSize.right);
size.bottom = max(size.bottom, newSize.bottom);
}
else
{
size = newSize;
sizeEmpty = false;
}
}
}
if (!sizeEmpty)
{
SizeWindowToRect(window, size);
}
}
@@ -306,10 +394,8 @@ ZoneSet::MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient)
zoneDrop->RemoveWindowFromZone(window, !IsZoomed(window));
}
if (auto zone = ZoneFromPoint(ptClient))
{
zone->AddWindowToZone(window, zoneWindow, true);
}
auto zones = ZonesFromPoint(ptClient);
MoveWindowIntoZoneByIndexSet(window, zoneWindow, zones, true);
}
IFACEMETHODIMP_(bool)

View File

@@ -24,12 +24,12 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
*/
IFACEMETHOD(AddZone)(winrt::com_ptr<IZone> zone) = 0;
/**
* Get zone from cursor coordinates.
* Get zones from cursor coordinates.
*
* @param pt Cursor coordinates.
* @returns Zone object (defining coordinates of the zone).
* @returns Vector of indices, corresponding to the current set of zones - the zones considered active.
*/
IFACEMETHOD_(winrt::com_ptr<IZone>, ZoneFromPoint)(POINT pt) = 0;
IFACEMETHOD_(std::vector<int>, ZonesFromPoint)(POINT pt) = 0;
/**
* Get index of the zone inside zone layout by window assigned to it.
*
@@ -48,8 +48,20 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
* current monitor desktop work area.
* @param index Zone index within zone layout.
* @param stampZone Whether the window being added to the zone should be stamped.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, HWND zoneWindow, int index) = 0;
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, HWND zoneWindow, int index, bool stampZone) = 0;
/**
* Assign window to the zones based on the set of zone indices inside zone layout.
*
* @param window Handle of window which should be assigned to zone.
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
* current monitor desktop work area.
* @param indexSet The set of zone indices within zone layout.
* @param stampZone Whether the window being added to the zone should be stamped,
in case a single window is to be added.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByIndexSet)(HWND window, HWND zoneWindow, const std::vector<int>& indexSet, bool stampZone) = 0;
/**
* Assign window to the zone based on direction (using WIN + LEFT/RIGHT arrow).
*

View File

@@ -148,7 +148,7 @@ namespace ZoneWindowDrawUtils
COLORREF highlightColor,
int zoneOpacity,
const std::vector<winrt::com_ptr<IZone>>& zones,
const winrt::com_ptr<IZone>& highlightZone,
const std::vector<int>& highlightZones,
bool flashMode,
bool drawHints) noexcept
{
@@ -158,15 +158,22 @@ namespace ZoneWindowDrawUtils
ColorSetting colorHighlight{ OpacitySettingToAlpha(zoneOpacity), 0, 255, 0, -2 };
ColorSetting const colorFlash{ OpacitySettingToAlpha(zoneOpacity), RGB(81, 92, 107), 200, RGB(104, 118, 138), -2 };
std::vector<bool> isHighlighted(zones.size(), false);
for (int x : highlightZones)
{
isHighlighted[x] = true;
}
for (auto iter = zones.begin(); iter != zones.end(); iter++)
{
int zoneId = static_cast<int>(iter - zones.begin());
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
if (!zone)
{
continue;
}
if (zone != highlightZone)
if (!isHighlighted[zoneId])
{
if (flashMode)
{
@@ -182,13 +189,12 @@ namespace ZoneWindowDrawUtils
DrawZone(hdc, colorViewer, zone, zones, flashMode);
}
}
}
if (highlightZone)
else
{
colorHighlight.fill = highlightColor;
colorHighlight.border = zoneBorderColor;
DrawZone(hdc, colorHighlight, highlightZone, zones, flashMode);
DrawZone(hdc, colorHighlight, zone, zones, flashMode);
}
}
}
}
@@ -210,6 +216,8 @@ public:
IsDragEnabled() noexcept { return m_dragEnabled; }
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByIndex(HWND window, int index) noexcept;
IFACEMETHODIMP_(void)
MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<int>& indexSet) noexcept;
IFACEMETHODIMP_(bool)
MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode, bool cycle) noexcept;
IFACEMETHODIMP_(void)
@@ -238,7 +246,7 @@ private:
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
void OnPaint(wil::unique_hdc& hdc) noexcept;
void OnKeyUp(WPARAM wparam) noexcept;
winrt::com_ptr<IZone> ZoneFromPoint(POINT pt) noexcept;
std::vector<int> ZonesFromPoint(POINT pt) noexcept;
void CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept;
void FlashZones() noexcept;
@@ -253,7 +261,7 @@ private:
bool m_dragEnabled{};
winrt::com_ptr<IZoneSet> m_activeZoneSet;
std::vector<winrt::com_ptr<IZoneSet>> m_zoneSets;
winrt::com_ptr<IZone> m_highlightZone;
std::vector<int> m_highlightZone;
WPARAM m_keyLast{};
size_t m_keyCycle{};
static const UINT m_showAnimationDuration = 200; // ms
@@ -363,7 +371,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnter(HWND window, bool dragEnabled) noexcept
m_dragEnabled = dragEnabled;
m_windowMoveSize = window;
m_drawHints = true;
m_highlightZone = nullptr;
m_highlightZone = {};
ShowZoneWindow();
return S_OK;
}
@@ -378,13 +386,13 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable
if (dragEnabled)
{
auto highlightZone = ZoneFromPoint(ptClient);
auto highlightZone = ZonesFromPoint(ptClient);
redraw = (highlightZone != m_highlightZone);
m_highlightZone = std::move(highlightZone);
}
else if (m_highlightZone)
else if (m_highlightZone.size())
{
m_highlightZone = nullptr;
m_highlightZone = {};
redraw = true;
}
@@ -432,10 +440,16 @@ ZoneWindow::RestoreOrginalTransparency() noexcept
IFACEMETHODIMP_(void)
ZoneWindow::MoveWindowIntoZoneByIndex(HWND window, int index) noexcept
{
MoveWindowIntoZoneByIndexSet(window, { index });
}
IFACEMETHODIMP_(void)
ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<int>& indexSet) noexcept
{
if (m_activeZoneSet)
{
m_activeZoneSet->MoveWindowIntoZoneByIndex(window, m_window.get(), index);
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window.get(), indexSet, false);
}
}
@@ -518,7 +532,7 @@ ZoneWindow::HideZoneWindow() noexcept
m_keyLast = 0;
m_windowMoveSize = nullptr;
m_drawHints = false;
m_highlightZone = nullptr;
m_highlightZone = {};
}
}
@@ -685,13 +699,13 @@ void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept
}
}
winrt::com_ptr<IZone> ZoneWindow::ZoneFromPoint(POINT pt) noexcept
std::vector<int> ZoneWindow::ZonesFromPoint(POINT pt) noexcept
{
if (m_activeZoneSet)
{
return m_activeZoneSet->ZoneFromPoint(pt);
return m_activeZoneSet->ZonesFromPoint(pt);
}
return nullptr;
return {};
}
void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept
@@ -739,7 +753,7 @@ void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::Inp
{
m_host->MoveWindowsOnActiveZoneSetChange();
}
m_highlightZone = nullptr;
m_highlightZone = {};
}
void ZoneWindow::FlashZones() noexcept

View File

@@ -53,6 +53,13 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
* @param index Zone index within zone layout.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByIndex)(HWND window, int index) = 0;
/**
* Assign window to the zones based on the set of zone indices inside zone layout.
*
* @param window Handle of window which should be assigned to zone.
* @param indexSet The set of zone indices within zone layout.
*/
IFACEMETHOD_(void, MoveWindowIntoZoneByIndexSet)(HWND window, const std::vector<int>& indexSet) = 0;
/**
* Assign window to the zone based on direction (using WIN + LEFT/RIGHT arrow).
*

View File

@@ -108,3 +108,30 @@ void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo)
monitorInfo = std::move(sortedMonitorInfo);
}
void SizeWindowToRect(HWND window, RECT rect) noexcept
{
WINDOWPLACEMENT placement{};
::GetWindowPlacement(window, &placement);
//wait if SW_SHOWMINIMIZED would be removed from window (Issue #1685)
for (int i = 0; i < 5 && (placement.showCmd & SW_SHOWMINIMIZED) != 0; i++)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
::GetWindowPlacement(window, &placement);
}
// Do not restore minimized windows. We change their placement though so they restore to the correct zone.
if ((placement.showCmd & SW_SHOWMINIMIZED) == 0)
{
placement.showCmd = SW_RESTORE | SW_SHOWNA;
}
placement.rcNormalPosition = rect;
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
::SetWindowPlacement(window, &placement);
// Do it again, allowing Windows to resize the window and set correct scaling
// This fixes Issue #365
::SetWindowPlacement(window, &placement);
}

View File

@@ -118,3 +118,4 @@ inline BYTE OpacitySettingToAlpha(int opacity)
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
void SizeWindowToRect(HWND window, RECT rect) noexcept;

View File

@@ -132,8 +132,8 @@ namespace FancyZonesUnitTests
TEST_METHOD (ZoneFromPointEmpty)
{
auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 });
Assert::IsTrue(nullptr == actual);
auto actual = m_set->ZonesFromPoint(POINT{ 0, 0 });
Assert::IsTrue(actual.size() == 0);
}
TEST_METHOD (ZoneFromPointInner)
@@ -146,9 +146,9 @@ namespace FancyZonesUnitTests
{
for (int j = top + 1; j < bottom; j++)
{
auto actual = m_set->ZoneFromPoint(POINT{ i, j });
Assert::IsTrue(actual != nullptr);
compareZones(expected, actual);
auto actual = m_set->ZonesFromPoint(POINT{ i, j });
Assert::IsTrue(actual.size() == 1);
compareZones(expected, m_set->GetZones()[actual[0]]);
}
}
}
@@ -161,29 +161,29 @@ namespace FancyZonesUnitTests
for (int i = left; i < right; i++)
{
auto actual = m_set->ZoneFromPoint(POINT{ i, top });
Assert::IsTrue(actual != nullptr);
compareZones(expected, actual);
auto actual = m_set->ZonesFromPoint(POINT{ i, top });
Assert::IsTrue(actual.size() == 1);
compareZones(expected, m_set->GetZones()[actual[0]]);
}
for (int i = top; i < bottom; i++)
{
auto actual = m_set->ZoneFromPoint(POINT{ left, i });
Assert::IsTrue(actual != nullptr);
compareZones(expected, actual);
auto actual = m_set->ZonesFromPoint(POINT{ left, i });
Assert::IsTrue(actual.size() == 1);
compareZones(expected, m_set->GetZones()[actual[0]]);
}
//bottom and right borders considered to be outside
for (int i = left; i < right; i++)
{
auto actual = m_set->ZoneFromPoint(POINT{ i, bottom });
Assert::IsTrue(nullptr == actual);
auto actual = m_set->ZonesFromPoint(POINT{ i, bottom });
Assert::IsTrue(actual.size() == 0);
}
for (int i = top; i < bottom; i++)
{
auto actual = m_set->ZoneFromPoint(POINT{ right, i });
Assert::IsTrue(nullptr == actual);
auto actual = m_set->ZonesFromPoint(POINT{ right, i });
Assert::IsTrue(actual.size() == 0);
}
}
@@ -193,8 +193,8 @@ namespace FancyZonesUnitTests
winrt::com_ptr<IZone> zone = MakeZone({ left, top, right, bottom });
m_set->AddZone(zone);
auto actual = m_set->ZoneFromPoint(POINT{ 101, 101 });
Assert::IsTrue(actual == nullptr);
auto actual = m_set->ZonesFromPoint(POINT{ 200, 200 });
Assert::IsTrue(actual.size() == 0);
}
TEST_METHOD (ZoneFromPointOverlapping)
@@ -208,9 +208,65 @@ namespace FancyZonesUnitTests
winrt::com_ptr<IZone> zone4 = MakeZone({ 10, 10, 50, 50 });
m_set->AddZone(zone4);
auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 });
Assert::IsTrue(actual != nullptr);
compareZones(zone2, actual);
// zone4 is expected because it's the smallest one, and it's considered to be inside
// since Multizones support
auto actual = m_set->ZonesFromPoint(POINT{ 50, 50 });
Assert::IsTrue(actual.size() == 1);
compareZones(zone4, m_set->GetZones()[actual[0]]);
}
TEST_METHOD (ZoneFromPointMultizoneHorizontal)
{
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
m_set->AddZone(zone1);
winrt::com_ptr<IZone> zone2 = MakeZone({ 100, 0, 200, 100 });
m_set->AddZone(zone2);
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 100, 100, 200 });
m_set->AddZone(zone3);
winrt::com_ptr<IZone> zone4 = MakeZone({ 100, 100, 200, 200 });
m_set->AddZone(zone4);
auto actual = m_set->ZonesFromPoint(POINT{ 50, 100 });
Assert::IsTrue(actual.size() == 2);
compareZones(zone1, m_set->GetZones()[actual[0]]);
compareZones(zone3, m_set->GetZones()[actual[1]]);
}
TEST_METHOD (ZoneFromPointMultizoneVertical)
{
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
m_set->AddZone(zone1);
winrt::com_ptr<IZone> zone2 = MakeZone({ 100, 0, 200, 100 });
m_set->AddZone(zone2);
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 100, 100, 200 });
m_set->AddZone(zone3);
winrt::com_ptr<IZone> zone4 = MakeZone({ 100, 100, 200, 200 });
m_set->AddZone(zone4);
auto actual = m_set->ZonesFromPoint(POINT{ 100, 50 });
Assert::IsTrue(actual.size() == 2);
compareZones(zone1, m_set->GetZones()[actual[0]]);
compareZones(zone2, m_set->GetZones()[actual[1]]);
}
TEST_METHOD(ZoneFromPointMultizoneQuad)
{
winrt::com_ptr<IZone> zone1 = MakeZone({ 0, 0, 100, 100 });
m_set->AddZone(zone1);
winrt::com_ptr<IZone> zone2 = MakeZone({ 100, 0, 200, 100 });
m_set->AddZone(zone2);
winrt::com_ptr<IZone> zone3 = MakeZone({ 0, 100, 100, 200 });
m_set->AddZone(zone3);
winrt::com_ptr<IZone> zone4 = MakeZone({ 100, 100, 200, 200 });
m_set->AddZone(zone4);
auto actual = m_set->ZonesFromPoint(POINT{ 100, 100 });
Assert::IsTrue(actual.size() == 4);
compareZones(zone1, m_set->GetZones()[actual[0]]);
compareZones(zone2, m_set->GetZones()[actual[1]]);
compareZones(zone3, m_set->GetZones()[actual[2]]);
compareZones(zone4, m_set->GetZones()[actual[3]]);
}
TEST_METHOD (ZoneFromPointWithNotNormalizedRect)
@@ -218,8 +274,8 @@ namespace FancyZonesUnitTests
winrt::com_ptr<IZone> zone = MakeZone({ 100, 100, 0, 0 });
m_set->AddZone(zone);
auto actual = m_set->ZoneFromPoint(POINT{ 50, 50 });
Assert::IsTrue(actual == nullptr);
auto actual = m_set->ZonesFromPoint(POINT{ 50, 50 });
Assert::IsTrue(actual.size() == 0);
}
TEST_METHOD (ZoneFromPointWithZeroRect)
@@ -227,8 +283,8 @@ namespace FancyZonesUnitTests
winrt::com_ptr<IZone> zone = MakeZone({ 0, 0, 0, 0 });
m_set->AddZone(zone);
auto actual = m_set->ZoneFromPoint(POINT{ 0, 0 });
Assert::IsTrue(actual == nullptr);
auto actual = m_set->ZonesFromPoint(POINT{ 0, 0 });
Assert::IsTrue(actual.size() == 0);
}
TEST_METHOD (ZoneIndexFromWindow)
@@ -316,7 +372,7 @@ namespace FancyZonesUnitTests
m_set->AddZone(zone3);
HWND window = Mocks::Window();
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1, false);
Assert::IsFalse(zone1->ContainsWindow(window));
Assert::IsTrue(zone2->ContainsWindow(window));
Assert::IsFalse(zone3->ContainsWindow(window));
@@ -325,7 +381,7 @@ namespace FancyZonesUnitTests
TEST_METHOD (MoveWindowIntoZoneByIndexWithNoZones)
{
HWND window = Mocks::Window();
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
}
TEST_METHOD (MoveWindowIntoZoneByIndexWithInvalidIndex)
@@ -338,7 +394,7 @@ namespace FancyZonesUnitTests
m_set->AddZone(zone3);
HWND window = Mocks::Window();
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 100, false);
Assert::IsFalse(zone1->ContainsWindow(window));
Assert::IsFalse(zone2->ContainsWindow(window));
Assert::IsFalse(zone3->ContainsWindow(window));
@@ -355,17 +411,17 @@ namespace FancyZonesUnitTests
m_set->AddZone(zone3);
HWND window = Mocks::Window();
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
Assert::IsTrue(zone1->ContainsWindow(window));
Assert::IsFalse(zone2->ContainsWindow(window));
Assert::IsFalse(zone3->ContainsWindow(window));
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 1, false);
Assert::IsFalse(zone1->ContainsWindow(window));
Assert::IsTrue(zone2->ContainsWindow(window));
Assert::IsFalse(zone3->ContainsWindow(window));
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 2);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 2, false);
Assert::IsFalse(zone1->ContainsWindow(window));
Assert::IsFalse(zone2->ContainsWindow(window));
Assert::IsTrue(zone3->ContainsWindow(window));
@@ -382,9 +438,9 @@ namespace FancyZonesUnitTests
m_set->AddZone(zone3);
HWND window = Mocks::Window();
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
m_set->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
Assert::IsTrue(zone1->ContainsWindow(window));
Assert::IsFalse(zone2->ContainsWindow(window));
Assert::IsFalse(zone3->ContainsWindow(window));
@@ -401,7 +457,7 @@ namespace FancyZonesUnitTests
m_set->AddZone(zone1);
auto window = Mocks::Window();
m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 101, 101 });
m_set->MoveWindowIntoZoneByPoint(window, Mocks::Window(), POINT{ 200, 200 });
Assert::IsFalse(zone1->ContainsWindow(window));
}

View File

@@ -445,7 +445,7 @@ namespace FancyZonesUnitTests
Assert::AreEqual(expected, actual);
const auto zoneSet = zoneWindow->ActiveZoneSet();
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), false);
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
const auto actualZoneIndex = zoneSet->GetZoneIndexFromWindow(window);
Assert::AreNotEqual(-1, actualZoneIndex);
}
@@ -458,7 +458,7 @@ namespace FancyZonesUnitTests
zoneWindow->MoveSizeEnter(window, true);
const auto expected = S_OK;
const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ 0, 0 });
const auto actual = zoneWindow->MoveSizeEnd(window, POINT{ -100, -100 });
Assert::AreEqual(expected, actual);
const auto zoneSet = zoneWindow->ActiveZoneSet();
@@ -501,7 +501,7 @@ namespace FancyZonesUnitTests
Assert::AreEqual(expected, actual);
const auto zoneSet = zoneWindow->ActiveZoneSet();
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), false);
zoneSet->MoveWindowIntoZoneByIndex(window, Mocks::Window(), 0, false);
const auto actualZoneIndex = zoneSet->GetZoneIndexFromWindow(window);
Assert::AreNotEqual(-1, actualZoneIndex); //with invalid point zone remains the same
}