Skip to content

Commit

Permalink
[FancyZones] Overlapping zones selection algorithm - settings (#9874)
Browse files Browse the repository at this point in the history
* Started work

* Removed bools in favor of an enum, renamed some

* Done something but it still doesn't work

* Settings are now correctly saved

* I'm getting a crash, I need to rebuild from scratch

* Settings page looks alright

* Completed work. Unit tests?

* Use ComboBox instead

* Add telemetry

* Update text
  • Loading branch information
ivan100sic committed Feb 25, 2021
1 parent 889360b commit f839a40
Show file tree
Hide file tree
Showing 15 changed files with 114 additions and 21 deletions.
6 changes: 6 additions & 0 deletions src/modules/fancyzones/lib/FancyZones.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone
return m_windowMoveHandler.InMoveSize();
}

IFACEMETHODIMP_(Settings::OverlappingZonesAlgorithm)
GetOverlappingZonesAlgorithm() noexcept
{
return m_settings->GetSettings()->overlappingZonesAlgorithm;
}

LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
void OnDisplayChange(DisplayChangeType changeType) noexcept;
void AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) noexcept;
Expand Down
6 changes: 6 additions & 0 deletions src/modules/fancyzones/lib/FancyZones.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <common/hooks/WinHookEvent.h>
#include "Settings.h"

#include <functional>

Expand Down Expand Up @@ -102,6 +103,11 @@ interface __declspec(uuid("{5C8D99D6-34B2-4F4A-A8E5-7483F6869775}")) IZoneWindow
*/
IFACEMETHOD_(bool, InMoveSize)
() = 0;
/**
* @returns Enumeration value indicating the algorithm used to choose one of multiple overlapped zones to highlight.
*/
IFACEMETHOD_(Settings::OverlappingZonesAlgorithm, GetOverlappingZonesAlgorithm)
() = 0;
};

winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance, const winrt::com_ptr<IFancyZonesSettings>& settings, std::function<void()> disableCallback) noexcept;
17 changes: 12 additions & 5 deletions src/modules/fancyzones/lib/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace NonLocalizable
const wchar_t OverrideSnapHotKeysID[] = L"fancyzones_overrideSnapHotkeys";
const wchar_t MoveWindowAcrossMonitorsID[] = L"fancyzones_moveWindowAcrossMonitors";
const wchar_t MoveWindowsBasedOnPositionID[] = L"fancyzones_moveWindowsBasedOnPosition";
const wchar_t OverlappingZonesAlgorithmID[] = L"fancyzones_overlappingZonesAlgorithm";
const wchar_t DisplayChangeMoveWindowsID[] = L"fancyzones_displayChange_moveWindows";
const wchar_t ZoneSetChangeMoveWindowsID[] = L"fancyzones_zoneSetChange_moveWindows";
const wchar_t AppLastZoneMoveWindowsID[] = L"fancyzones_appLastZone_moveWindows";
Expand Down Expand Up @@ -79,16 +80,12 @@ struct FancyZonesSettings : winrt::implements<FancyZonesSettings, IFancyZonesSet
PCWSTR name;
bool* value;
int resourceId;
} m_configBools[14 /* 15 */] = {
// "Turning FLASHING_ZONE option off"
} m_configBools[14] = {
{ NonLocalizable::ShiftDragID, &m_settings.shiftDrag, IDS_SETTING_DESCRIPTION_SHIFTDRAG },
{ NonLocalizable::MouseSwitchID, &m_settings.mouseSwitch, IDS_SETTING_DESCRIPTION_MOUSESWITCH },
{ NonLocalizable::OverrideSnapHotKeysID, &m_settings.overrideSnapHotkeys, IDS_SETTING_DESCRIPTION_OVERRIDE_SNAP_HOTKEYS },
{ NonLocalizable::MoveWindowAcrossMonitorsID, &m_settings.moveWindowAcrossMonitors, IDS_SETTING_DESCRIPTION_MOVE_WINDOW_ACROSS_MONITORS },
{ NonLocalizable::MoveWindowsBasedOnPositionID, &m_settings.moveWindowsBasedOnPosition, IDS_SETTING_DESCRIPTION_MOVE_WINDOWS_BASED_ON_POSITION },

// "Turning FLASHING_ZONE option off"
//{ L"fancyzones_zoneSetChange_flashZones", &m_settings.zoneSetChange_flashZones, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_FLASHZONES },
{ NonLocalizable::DisplayChangeMoveWindowsID, &m_settings.displayChange_moveWindows, IDS_SETTING_DESCRIPTION_DISPLAYCHANGE_MOVEWINDOWS },
{ NonLocalizable::ZoneSetChangeMoveWindowsID, &m_settings.zoneSetChange_moveWindows, IDS_SETTING_DESCRIPTION_ZONESETCHANGE_MOVEWINDOWS },
{ NonLocalizable::AppLastZoneMoveWindowsID, &m_settings.appLastZone_moveWindows, IDS_SETTING_DESCRIPTION_APPLASTZONE_MOVEWINDOWS },
Expand Down Expand Up @@ -238,6 +235,15 @@ void FancyZonesSettings::LoadSettings(PCWSTR config, bool fromFile) noexcept
{
m_settings.zoneHighlightOpacity = *val;
}

if (auto val = values.get_int_value(NonLocalizable::OverlappingZonesAlgorithmID))
{
// Avoid undefined behavior
if (*val >= 0 || *val < (int)Settings::OverlappingZonesAlgorithm::EnumElements)
{
m_settings.overlappingZonesAlgorithm = (Settings::OverlappingZonesAlgorithm)*val;
}
}
}
catch (...)
{
Expand All @@ -264,6 +270,7 @@ void FancyZonesSettings::SaveSettings() noexcept
values.add_property(NonLocalizable::ZoneBorderColorID, m_settings.zoneBorderColor);
values.add_property(NonLocalizable::ZoneHighlightColorID, m_settings.zoneHighlightColor);
values.add_property(NonLocalizable::ZoneHighlightOpacityID, m_settings.zoneHighlightOpacity);
values.add_property(NonLocalizable::OverlappingZonesAlgorithmID, (int)m_settings.overlappingZonesAlgorithm);
values.add_property(NonLocalizable::EditorHotkeyID, m_settings.editorHotkey.get_json());
values.add_property(NonLocalizable::ExcludedAppsID, m_settings.excludedApps);

Expand Down
9 changes: 9 additions & 0 deletions src/modules/fancyzones/lib/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ namespace ZonedWindowProperties

struct Settings
{
enum struct OverlappingZonesAlgorithm : int
{
Smallest = 0,
Largest = 1,
Positional = 2,
EnumElements = 3, // number of elements in the enum, not counting this
};

// The values specified here are the defaults.
bool shiftDrag = true;
bool mouseSwitch = false;
Expand All @@ -34,6 +42,7 @@ struct Settings
std::wstring zoneBorderColor = L"#FFFFFF";
std::wstring zoneHighlightColor = L"#008CFF";
int zoneHighlightOpacity = 50;
OverlappingZonesAlgorithm overlappingZonesAlgorithm = OverlappingZonesAlgorithm::Smallest;
PowerToysSettings::HotkeyObject editorHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, VK_OEM_3);
std::wstring excludedApps = L"";
std::vector<std::wstring> excludedAppsArray;
Expand Down
10 changes: 6 additions & 4 deletions src/modules/fancyzones/lib/ZoneSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,16 @@ ZoneSet::ZonesFromPoint(POINT pt) const noexcept

try
{
using Algorithm = Settings::OverlappingZonesAlgorithm;

switch (m_config.SelectionAlgorithm)
{
case ZoneSelectionAlgorithm::SUBREGION:
return ZoneSelectSubregion(capturedZones, pt);
case ZoneSelectionAlgorithm::SMALLEST:
case Algorithm::Smallest:
return ZoneSelectPriority(capturedZones, [&](auto zone1, auto zone2) { return zoneArea(zone1) < zoneArea(zone2); });
case ZoneSelectionAlgorithm::LARGEST:
case Algorithm::Largest:
return ZoneSelectPriority(capturedZones, [&](auto zone1, auto zone2) { return zoneArea(zone1) > zoneArea(zone2); });
case Algorithm::Positional:
return ZoneSelectSubregion(capturedZones, pt);
}
}
catch (std::out_of_range)
Expand Down
15 changes: 5 additions & 10 deletions src/modules/fancyzones/lib/ZoneSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,32 +152,27 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
IFACEMETHOD_(std::vector<size_t>, GetCombinedZoneRange)(const std::vector<size_t>& initialZones, const std::vector<size_t>& finalZones) const = 0;
};

enum struct ZoneSelectionAlgorithm
{
SMALLEST = 0,
LARGEST = 1,
SUBREGION = 2,
};

struct ZoneSetConfig
{
ZoneSetConfig(
GUID id,
FancyZonesDataTypes::ZoneSetLayoutType layoutType,
HMONITOR monitor,
int sensitivityRadius) noexcept :
int sensitivityRadius,
Settings::OverlappingZonesAlgorithm selectionAlgorithm = {}) noexcept :
Id(id),
LayoutType(layoutType),
Monitor(monitor),
SensitivityRadius(sensitivityRadius)
SensitivityRadius(sensitivityRadius),
SelectionAlgorithm(selectionAlgorithm)
{
}

GUID Id{};
FancyZonesDataTypes::ZoneSetLayoutType LayoutType{};
HMONITOR Monitor{};
int SensitivityRadius;
ZoneSelectionAlgorithm SelectionAlgorithm = ZoneSelectionAlgorithm::SMALLEST;
Settings::OverlappingZonesAlgorithm SelectionAlgorithm = Settings::OverlappingZonesAlgorithm::Smallest;
};

winrt::com_ptr<IZoneSet> MakeZoneSet(ZoneSetConfig const& config) noexcept;
3 changes: 2 additions & 1 deletion src/modules/fancyzones/lib/ZoneWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ void ZoneWindow::CalculateZoneSet() noexcept
zoneSetId,
activeZoneSet.type,
m_monitor,
sensitivityRadius));
sensitivityRadius,
m_host->GetOverlappingZonesAlgorithm()));

RECT workArea;
if (m_monitor)
Expand Down
2 changes: 2 additions & 0 deletions src/modules/fancyzones/lib/trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#define NumberOfZonesKey "NumberOfZones"
#define NumberOfWindowsKey "NumberOfWindows"
#define InputModeKey "InputMode"
#define OverlappingZonesAlgorithmKey "OverlappingZonesAlgorithm"

TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
Expand Down Expand Up @@ -260,6 +261,7 @@ void Trace::SettingsChanged(const Settings& settings) noexcept
TraceLoggingWideString(settings.zoneBorderColor.c_str(), ZoneBorderColorKey),
TraceLoggingWideString(settings.zoneHighlightColor.c_str(), ZoneHighlightColorKey),
TraceLoggingInt32(settings.zoneHighlightOpacity, ZoneHighlightOpacityKey),
TraceLoggingInt32((int)settings.overlappingZonesAlgorithm, OverlappingZonesAlgorithmKey),
TraceLoggingWideString(hotkeyStr.c_str(), HotkeyKey),
TraceLoggingInt32(static_cast<int>(settings.excludedAppsArray.size()), ExcludedAppsCountKey));
}
Expand Down
2 changes: 1 addition & 1 deletion src/modules/fancyzones/tests/UnitTests/ZoneSet.Spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace FancyZonesUnitTests
auto hres = CoCreateGuid(&m_id);
Assert::AreEqual(S_OK, hres);

ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), DefaultValues::SensitivityRadius);
ZoneSetConfig m_config = ZoneSetConfig(m_id, m_layoutType, Mocks::Monitor(), DefaultValues::SensitivityRadius, Settings::OverlappingZonesAlgorithm::Smallest);
m_set = MakeZoneSet(m_config);
}

Expand Down
5 changes: 5 additions & 0 deletions src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ namespace FancyZonesUnitTests
{
return false;
}
IFACEMETHODIMP_(Settings::OverlappingZonesAlgorithm)
GetOverlappingZonesAlgorithm() noexcept
{
return Settings::OverlappingZonesAlgorithm::Smallest;
}

IZoneWindow* m_zoneWindow;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public FZConfigProperties()
FancyzonesMouseSwitch = new BoolProperty();
FancyzonesMoveWindowsAcrossMonitors = new BoolProperty();
FancyzonesMoveWindowsBasedOnPosition = new BoolProperty();
FancyzonesOverlappingZonesAlgorithm = new IntProperty();
FancyzonesDisplayChangeMoveWindows = new BoolProperty();
FancyzonesZoneSetChangeMoveWindows = new BoolProperty();
FancyzonesAppLastZoneMoveWindows = new BoolProperty();
Expand Down Expand Up @@ -50,6 +51,9 @@ public FZConfigProperties()
[JsonPropertyName("fancyzones_moveWindowsBasedOnPosition")]
public BoolProperty FancyzonesMoveWindowsBasedOnPosition { get; set; }

[JsonPropertyName("fancyzones_overlappingZonesAlgorithm")]
public IntProperty FancyzonesOverlappingZonesAlgorithm { get; set; }

[JsonPropertyName("fancyzones_displayChange_moveWindows")]
public BoolProperty FancyzonesDisplayChangeMoveWindows { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ private enum MoveWindowBehaviour
MoveWindowBasedOnPosition,
}

private enum OverlappingZonesAlgorithm
{
Smallest = 0,
Largest = 1,
Positional = 2,
}

public FancyZonesViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<FancyZonesSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
{
// To obtain the general settings configurations of PowerToys Settings.
Expand All @@ -58,6 +65,7 @@ public FancyZonesViewModel(ISettingsRepository<GeneralSettings> settingsReposito
_overrideSnapHotkeys = Settings.Properties.FancyzonesOverrideSnapHotkeys.Value;
_moveWindowsAcrossMonitors = Settings.Properties.FancyzonesMoveWindowsAcrossMonitors.Value;
_moveWindowBehaviour = Settings.Properties.FancyzonesMoveWindowsBasedOnPosition.Value ? MoveWindowBehaviour.MoveWindowBasedOnPosition : MoveWindowBehaviour.MoveWindowBasedOnZoneIndex;
_overlappingZonesAlgorithm = (OverlappingZonesAlgorithm)Settings.Properties.FancyzonesOverlappingZonesAlgorithm.Value;
_displayChangemoveWindows = Settings.Properties.FancyzonesDisplayChangeMoveWindows.Value;
_zoneSetChangeMoveWindows = Settings.Properties.FancyzonesZoneSetChangeMoveWindows.Value;
_appLastZoneMoveWindows = Settings.Properties.FancyzonesAppLastZoneMoveWindows.Value;
Expand Down Expand Up @@ -92,6 +100,7 @@ public FancyZonesViewModel(ISettingsRepository<GeneralSettings> settingsReposito
private bool _overrideSnapHotkeys;
private bool _moveWindowsAcrossMonitors;
private MoveWindowBehaviour _moveWindowBehaviour;
private OverlappingZonesAlgorithm _overlappingZonesAlgorithm;
private bool _displayChangemoveWindows;
private bool _zoneSetChangeMoveWindows;
private bool _appLastZoneMoveWindows;
Expand Down Expand Up @@ -257,6 +266,24 @@ public bool MoveWindowsBasedOnZoneIndex
}
}

public int OverlappingZonesAlgorithmIndex
{
get
{
return (int)_overlappingZonesAlgorithm;
}

set
{
if (value != (int)_overlappingZonesAlgorithm)
{
_overlappingZonesAlgorithm = (OverlappingZonesAlgorithm)value;
Settings.Properties.FancyzonesOverlappingZonesAlgorithm.Value = value;
NotifyPropertyChanged();
}
}
}

public bool DisplayChangeMoveWindows
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -937,4 +937,16 @@
<data name="ColorPicker_Editor.Text" xml:space="preserve">
<value>Editor</value>
</data>
<data name="FancyZones_OverlappingZonesLargest.Content" xml:space="preserve">
<value>Activate the largest zone by area</value>
</data>
<data name="FancyZones_OverlappingZonesPositional.Content" xml:space="preserve">
<value>Split the overlapped area into multiple activation targets</value>
</data>
<data name="FancyZones_OverlappingZonesSmallest.Content" xml:space="preserve">
<value>Activate the smallest zone by area</value>
</data>
<data name="FancyZones_OverlappingZonesLabel.Text" xml:space="preserve">
<value>When multiple zones overlap:</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@

<!-- MaxWidth of the content panel, similar to W10 Settings -->
<x:Double x:Key="MaxContentWidth">460</x:Double>

<!-- Maximum Width of a combo box inside the content panel -->
<x:Double x:Key="MaxComboBoxWidth">444</x:Double>
</ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,20 @@
Margin="{StaticResource XSmallTopMargin}"
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"/>

<TextBlock x:Uid="FancyZones_OverlappingZonesLabel"
Margin="{StaticResource SmallTopMargin}"
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>

<ComboBox Name="FancyZones_OverlappingZonesComboBox"
x:Uid="FancyZones_OverlappingZonesComboBox"
SelectedIndex="{x:Bind Path=ViewModel.OverlappingZonesAlgorithmIndex, Mode=TwoWay}"
VerticalAlignment="Center"
Width="{StaticResource MaxComboBoxWidth}"
Margin="{StaticResource SmallTopMargin}">
<ComboBoxItem x:Uid="FancyZones_OverlappingZonesSmallest" />
<ComboBoxItem x:Uid="FancyZones_OverlappingZonesLargest" />
<ComboBoxItem x:Uid="FancyZones_OverlappingZonesPositional" />
</ComboBox>

<TextBlock x:Uid="FancyZones_WindowBehavior_GroupSettings"
Style="{StaticResource SettingsGroupTitleStyle}"
Expand Down

0 comments on commit f839a40

Please sign in to comment.