mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 10:16:24 +02:00
Merge branch 'master' of https://github.com/microsoft/PowerToys into microsoft-master
This commit is contained in:
13
src/common/ManagedCommon/StartupPosition.cs
Normal file
13
src/common/ManagedCommon/StartupPosition.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace ManagedCommon
|
||||
{
|
||||
public enum StartupPosition
|
||||
{
|
||||
Cursor,
|
||||
PrimaryMonitor,
|
||||
Focus,
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@ namespace Microsoft.PowerToys.Telemetry.Events
|
||||
{
|
||||
public bool UTCReplace_AppSessionGuid => true;
|
||||
|
||||
public string EventName { get; set; }
|
||||
|
||||
private string _version;
|
||||
|
||||
public string Version
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Microsoft.PowerToys.Telemetry
|
||||
where T : EventBase, IEvent
|
||||
{
|
||||
this.Write<T>(
|
||||
null,
|
||||
telemetryEvent.EventName,
|
||||
new EventSourceOptions()
|
||||
{
|
||||
Keywords = ProjectKeywordMeasure,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
namespace PTSettingsHelper
|
||||
{
|
||||
constexpr inline const wchar_t* settings_filename = L"\\settings.json";
|
||||
constexpr inline const wchar_t* log_settings_filename = L"log_settings.json";
|
||||
constexpr inline const wchar_t* oobe_filename = L"oobe_settings.json";
|
||||
|
||||
std::wstring get_root_save_folder_location()
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
namespace PTSettingsHelper
|
||||
{
|
||||
constexpr inline const wchar_t* log_settings_filename = L"log_settings.json";
|
||||
|
||||
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
|
||||
std::wstring get_root_save_folder_location();
|
||||
|
||||
|
||||
@@ -52,10 +52,13 @@
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -135,10 +135,24 @@ public
|
||||
public:
|
||||
literal int VK_WIN_BOTH = CommonSharedConstants::VK_WIN_BOTH;
|
||||
|
||||
static String ^ AppDataPath() {
|
||||
auto localPath = Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData);
|
||||
auto powerToysPath = gcnew String(CommonSharedConstants::APPDATA_PATH);
|
||||
return System::IO::Path::Combine(localPath, powerToysPath);
|
||||
}
|
||||
|
||||
static String ^ PowerLauncherSharedEvent() {
|
||||
return gcnew String(CommonSharedConstants::POWER_LAUNCHER_SHARED_EVENT);
|
||||
}
|
||||
|
||||
static String ^ RunSendSettingsTelemetryEvent() {
|
||||
return gcnew String(CommonSharedConstants::RUN_SEND_SETTINGS_TELEMETRY_EVENT);
|
||||
}
|
||||
|
||||
static String ^ ColorPickerSendSettingsTelemetryEvent() {
|
||||
return gcnew String(CommonSharedConstants::COLOR_PICKER_SEND_SETTINGS_TELEMETRY_EVENT);
|
||||
}
|
||||
|
||||
static String ^ ShowColorPickerSharedEvent() {
|
||||
return gcnew String(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT);
|
||||
}
|
||||
|
||||
@@ -10,9 +10,15 @@ namespace CommonSharedConstants
|
||||
// Fake key code to represent VK_WIN.
|
||||
inline const int VK_WIN_BOTH = 0x104;
|
||||
|
||||
const wchar_t APPDATA_PATH[] = L"Microsoft\\PowerToys";
|
||||
|
||||
// Path to the event used by PowerLauncher
|
||||
const wchar_t POWER_LAUNCHER_SHARED_EVENT[] = L"Local\\PowerToysRunInvokeEvent-30f26ad7-d36d-4c0e-ab02-68bb5ff3c4ab";
|
||||
|
||||
const wchar_t RUN_SEND_SETTINGS_TELEMETRY_EVENT[] = L"Local\\PowerToysRunInvokeEvent-638ec522-0018-4b96-837d-6bd88e06f0d6";
|
||||
|
||||
const wchar_t COLOR_PICKER_SEND_SETTINGS_TELEMETRY_EVENT[] = L"Local\\ColorPickerSettingsTelemetryEvent-6c7071d8-4014-46ec-b687-913bd8a422f1";
|
||||
|
||||
// Path to the event used to show Color Picker
|
||||
const wchar_t SHOW_COLOR_PICKER_SHARED_EVENT[] = L"Local\\ShowColorPickerEvent-8c46be2a-3e05-4186-b56b-4ae986ef2525";
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ level_enum getLogLevel(std::wstring_view logSettingsPath)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<spdlog::logger> Logger::logger;
|
||||
std::shared_ptr<spdlog::logger> Logger::logger = spdlog::null_logger_mt("null");
|
||||
|
||||
bool Logger::wasLogFailedShown()
|
||||
{
|
||||
|
||||
@@ -4,16 +4,18 @@
|
||||
struct LogSettings
|
||||
{
|
||||
// The following strings are not localizable
|
||||
inline const static std::wstring defaultLogLevel = L"warn";
|
||||
inline const static std::wstring defaultLogLevel = L"trace";
|
||||
inline const static std::wstring logLevelOption = L"logLevel";
|
||||
inline const static std::string runnerLoggerName = "runner";
|
||||
inline const static std::wstring logPath = L"Logs\\";
|
||||
inline const static std::wstring runnerLogPath = L"RunnerLogs\\runner-log.txt";
|
||||
inline const static std::string actionRunnerLoggerName = "action-runner";
|
||||
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.txt";
|
||||
inline const static std::string launcherLoggerName = "launcher";
|
||||
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
|
||||
inline const static std::string fancyZonesLoggerName = "fancyzones";
|
||||
inline const static std::wstring fancyZonesLogPath = L"FancyZonesLogs\\fancyzones-log.txt";
|
||||
inline const static std::wstring fancyZonesLogPath = L"fancyzones-log.txt";
|
||||
inline const static std::wstring fancyZonesOldLogPath = L"FancyZonesLogs\\"; // needed to clean up old logs
|
||||
inline const static std::string shortcutGuideLoggerName = "shortcut-guide";
|
||||
inline const static std::wstring shortcutGuideLogPath = L"ShortcutGuideLogs\\shortcut-guide-log.txt";
|
||||
inline const static std::string keyboardManagerLoggerName = "keyboard-manager";
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
namespace updating
|
||||
{
|
||||
constexpr size_t REQUIRED_MINIMAL_PATCH = 11;
|
||||
constexpr size_t REQUIRED_MINIMAL_PATCH = 13;
|
||||
|
||||
bool dotnet_is_installed()
|
||||
{
|
||||
@@ -46,7 +46,7 @@ namespace updating
|
||||
|
||||
std::optional<fs::path> download_dotnet()
|
||||
{
|
||||
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/3f1cc4f7-0c1a-48ca-9551-a8447fa55892/ed9809822448f55b649858920afb35cb/windowsdesktop-runtime-3.1.11-win-x64.exe";
|
||||
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/aa717f57-3ae5-48fa-a3ab-0018338d0726/fb37276b1575772461701339110e7a54/windowsdesktop-runtime-3.1.13-win-x64.exe";
|
||||
const wchar_t DOTNET_DESKTOP_FILENAME[] = L"windowsdesktop-runtime.exe";
|
||||
|
||||
auto dotnet_download_path = fs::temp_directory_path() / DOTNET_DESKTOP_FILENAME;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "installer.h"
|
||||
#include <common/version/version.h>
|
||||
#include <common/notifications/notifications.h>
|
||||
#include <common/utils/os-detect.h>
|
||||
#include "utils/winapi_error.h"
|
||||
|
||||
namespace // Strings in this namespace should not be localized
|
||||
@@ -192,4 +193,8 @@ namespace updating
|
||||
co_return false;
|
||||
}
|
||||
|
||||
bool is_old_windows_version()
|
||||
{
|
||||
return !Is19H1OrHigher();
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,6 @@ namespace updating
|
||||
|
||||
std::optional<VersionHelper> get_installed_powertoys_version();
|
||||
std::future<bool> uninstall_previous_msix_version_async();
|
||||
|
||||
bool is_old_windows_version();
|
||||
}
|
||||
@@ -7,9 +7,10 @@
|
||||
#include "notifications.h"
|
||||
#include "updating.h"
|
||||
|
||||
#include <common/utils/json.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/notifications/notifications.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/json.h>
|
||||
#include <common/utils/os-detect.h>
|
||||
|
||||
namespace // Strings in this namespace should not be localized
|
||||
{
|
||||
@@ -68,12 +69,17 @@ namespace updating
|
||||
{
|
||||
co_return nonstd::make_unexpected(strings.GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
http::HttpClient client;
|
||||
json::JsonObject release_object;
|
||||
const VersionHelper current_version(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||
VersionHelper github_version = current_version;
|
||||
|
||||
// On a <1903 system, block updates to 0.36+
|
||||
const bool blockNonPatchReleases = current_version.major == 0 && current_version.minor == 35 && !Is19H1OrHigher();
|
||||
|
||||
if (prerelease)
|
||||
{
|
||||
const auto body = co_await client.request(Uri{ ALL_RELEASES_ENDPOINT });
|
||||
@@ -102,6 +108,11 @@ namespace updating
|
||||
}
|
||||
}
|
||||
|
||||
if (blockNonPatchReleases && github_version >= VersionHelper{ 0, 36, 0 })
|
||||
{
|
||||
co_return version_up_to_date{};
|
||||
}
|
||||
|
||||
if (github_version <= current_version)
|
||||
{
|
||||
co_return version_up_to_date{};
|
||||
|
||||
55
src/common/utils/logger_helper.h
Normal file
55
src/common/utils/logger_helper.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <common/version/version.h>
|
||||
|
||||
namespace LoggerHelpers
|
||||
{
|
||||
inline std::filesystem::path get_log_folder_path(std::wstring_view appPath)
|
||||
{
|
||||
std::filesystem::path logFolderPath(appPath);
|
||||
logFolderPath.append(LogSettings::logPath);
|
||||
logFolderPath.append(get_product_version());
|
||||
return logFolderPath;
|
||||
}
|
||||
|
||||
inline bool delete_old_log_folder(const std::filesystem::path& logFolderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::remove_all(logFolderPath);
|
||||
return true;
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& e)
|
||||
{
|
||||
Logger::error("Failed to delete old log folder: {}", e.what());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool delete_other_versions_log_folders(std::wstring_view appPath, const std::filesystem::path& currentVersionLogFolder)
|
||||
{
|
||||
bool result = true;
|
||||
std::filesystem::path logFolderPath(appPath);
|
||||
logFolderPath.append(LogSettings::logPath);
|
||||
|
||||
for (const auto& dir : std::filesystem::directory_iterator(logFolderPath))
|
||||
{
|
||||
if (dir != currentVersionLogFolder)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::remove_all(dir);
|
||||
}
|
||||
catch (std::filesystem::filesystem_error& e)
|
||||
{
|
||||
Logger::error("Failed to delete previous version log folder: {}", e.what());
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <winrt/Windows.Foundation.Metadata.h>
|
||||
|
||||
// The following three helper functions determine if the user has a build version higher than or equal to 19h1, as that is a requirement for xaml islands
|
||||
// The following three helper functions determine if the user has a build version higher than or equal to 19h1 (aka 1903), as that is a requirement for xaml islands
|
||||
// Source : Microsoft-ui-xaml github
|
||||
// Link: https://github.com/microsoft/microsoft-ui-xaml/blob/c045cde57c5c754683d674634a0baccda34d58c4/dev/dll/SharedHelpers.cpp
|
||||
template<uint16_t APIVersion>
|
||||
|
||||
@@ -39,3 +39,14 @@ std::wstring VersionHelper::toWstring() const
|
||||
result += std::to_wstring(revision);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string VersionHelper::toString() const
|
||||
{
|
||||
std::string result{ "v" };
|
||||
result += std::to_string(major);
|
||||
result += '.';
|
||||
result += std::to_string(minor);
|
||||
result += '.';
|
||||
result += std::to_string(revision);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -15,4 +15,5 @@ struct VersionHelper
|
||||
size_t revision;
|
||||
|
||||
std::wstring toWstring() const;
|
||||
std::string toString() const;
|
||||
};
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
@@ -69,6 +72,7 @@
|
||||
<None Include="Resources.resx" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<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')" />
|
||||
</ImportGroup>
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include "trace.h"
|
||||
#include "Generated Files/resource.h"
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <common/utils/os-detect.h>
|
||||
#include <common/utils/resources.h>
|
||||
|
||||
#include <colorPicker/ColorPicker/ColorPickerConstants.h>
|
||||
#include <common/interop/shared_constants.h>
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
@@ -28,6 +30,17 @@ BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_WIN[] = L"win";
|
||||
const wchar_t JSON_KEY_ALT[] = L"alt";
|
||||
const wchar_t JSON_KEY_CTRL[] = L"ctrl";
|
||||
const wchar_t JSON_KEY_SHIFT[] = L"shift";
|
||||
const wchar_t JSON_KEY_CODE[] = L"code";
|
||||
const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"ActivationShortcut";
|
||||
}
|
||||
|
||||
struct ModuleSettings
|
||||
{
|
||||
} g_settings;
|
||||
@@ -47,11 +60,103 @@ private:
|
||||
// Time to wait for process to close after sending WM_CLOSE signal
|
||||
static const int MAX_WAIT_MILLISEC = 10000;
|
||||
|
||||
HANDLE send_telemetry_event;
|
||||
|
||||
Hotkey m_hotkey;
|
||||
|
||||
// Handle to event used to invoke ColorPicker
|
||||
HANDLE m_hInvokeEvent;
|
||||
|
||||
void parse_hotkey(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT);
|
||||
m_hotkey.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||
m_hotkey.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||
m_hotkey.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||
m_hotkey.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||
m_hotkey.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Failed to initialize ColorPicker start shortcut");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("ColorPicker settings are empty");
|
||||
}
|
||||
|
||||
if (!m_hotkey.key)
|
||||
{
|
||||
Logger::info("ColorPicker is going to use default shortcut");
|
||||
m_hotkey.win = true;
|
||||
m_hotkey.alt = false;
|
||||
m_hotkey.shift = true;
|
||||
m_hotkey.ctrl = false;
|
||||
m_hotkey.key = 'C';
|
||||
}
|
||||
}
|
||||
|
||||
bool is_process_running()
|
||||
{
|
||||
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
|
||||
}
|
||||
|
||||
void launch_process()
|
||||
{
|
||||
Logger::trace(L"Launching ColorPicker process");
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
|
||||
std::wstring executable_args = L"";
|
||||
executable_args.append(std::to_wstring(powertoys_pid));
|
||||
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\ColorPicker\\ColorPickerUI.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = executable_args.data();
|
||||
if (!ShellExecuteExW(&sei))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
std::wstring message = L"ColorPicker failed to start with error = ";
|
||||
message += std::to_wstring(error);
|
||||
Logger::error(message);
|
||||
}
|
||||
|
||||
m_hProcess = sei.hProcess;
|
||||
}
|
||||
|
||||
// Load the settings file.
|
||||
void init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
|
||||
|
||||
parse_hotkey(settings);
|
||||
}
|
||||
catch (std::exception ex)
|
||||
{
|
||||
Logger::warn(L"An exception occurred while loading the settings file");
|
||||
// Error while loading from the settings file. Let default values stay as they are.
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
ColorPicker()
|
||||
{
|
||||
app_name = GET_RESOURCE_STRING(IDS_COLORPICKER_NAME);
|
||||
app_key = ColorPickerConstants::ModuleKey;
|
||||
send_telemetry_event = CreateDefaultEvent(CommonSharedConstants::COLOR_PICKER_SEND_SETTINGS_TELEMETRY_EVENT);
|
||||
m_hInvokeEvent = CreateDefaultEvent(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT);
|
||||
init_settings();
|
||||
}
|
||||
|
||||
~ColorPicker()
|
||||
@@ -105,6 +210,7 @@ public:
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_hotkey(values);
|
||||
// If you don't need to do any custom processing of the settings, proceed
|
||||
// to persists the values calling:
|
||||
values.save_to_settings_file();
|
||||
@@ -119,23 +225,12 @@ public:
|
||||
|
||||
virtual void enable()
|
||||
{
|
||||
ResetEvent(send_telemetry_event);
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
// use only with new settings?
|
||||
if (UseNewSettings())
|
||||
{
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
|
||||
std::wstring executable_args = L"";
|
||||
executable_args.append(std::to_wstring(powertoys_pid));
|
||||
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||
sei.lpFile = L"modules\\ColorPicker\\ColorPickerUI.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
sei.lpParameters = executable_args.data();
|
||||
ShellExecuteExW(&sei);
|
||||
|
||||
m_hProcess = sei.hProcess;
|
||||
|
||||
launch_process();
|
||||
m_enabled = true;
|
||||
}
|
||||
};
|
||||
@@ -144,16 +239,57 @@ public:
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
ResetEvent(send_telemetry_event);
|
||||
ResetEvent(m_hInvokeEvent);
|
||||
TerminateProcess(m_hProcess, 1);
|
||||
}
|
||||
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
virtual bool on_hotkey(size_t hotkeyId) override
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"ColorPicker hotkey pressed");
|
||||
if (!is_process_running())
|
||||
{
|
||||
launch_process();
|
||||
}
|
||||
|
||||
SetEvent(m_hInvokeEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override
|
||||
{
|
||||
if (m_hotkey.key)
|
||||
{
|
||||
if (hotkeys && buffer_size >= 1)
|
||||
{
|
||||
hotkeys[0] = m_hotkey;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
virtual void send_settings_telemetry() override
|
||||
{
|
||||
SetEvent(send_telemetry_event);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace ColorPickerUI
|
||||
{
|
||||
private Mutex _instanceMutex;
|
||||
private static string[] _args;
|
||||
private int _powerToysPid;
|
||||
private int _powerToysRunnerPid;
|
||||
private bool disposedValue;
|
||||
private ThemeManager _themeManager;
|
||||
|
||||
@@ -27,23 +27,27 @@ namespace ColorPickerUI
|
||||
_args = e?.Args;
|
||||
|
||||
// allow only one instance of color picker
|
||||
_instanceMutex = new Mutex(true, @"Global\ColorPicker", out bool createdNew);
|
||||
_instanceMutex = new Mutex(true, @"Local\PowerToys_ColorPicker_InstanceMutex", out bool createdNew);
|
||||
if (!createdNew)
|
||||
{
|
||||
_instanceMutex = null;
|
||||
Application.Current.Shutdown();
|
||||
Environment.Exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_args?.Length > 0)
|
||||
{
|
||||
_ = int.TryParse(_args[0], out _powerToysPid);
|
||||
}
|
||||
_ = int.TryParse(_args[0], out _powerToysRunnerPid);
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(_powerToysPid, () =>
|
||||
RunnerHelper.WaitForPowerToysRunner(_powerToysRunnerPid, () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.Exit(0);
|
||||
});
|
||||
_powerToysRunnerPid = -1;
|
||||
}
|
||||
|
||||
_themeManager = new ThemeManager(this);
|
||||
base.OnStartup(e);
|
||||
@@ -83,5 +87,10 @@ namespace ColorPickerUI
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public bool IsRunningDetachedFromPowerToys()
|
||||
{
|
||||
return _powerToysRunnerPid == -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,8 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
using ColorPicker.Helpers;
|
||||
|
||||
namespace ColorPicker
|
||||
{
|
||||
@@ -23,16 +12,19 @@ namespace ColorPicker
|
||||
/// </summary>
|
||||
public partial class ColorEditorWindow : Window
|
||||
{
|
||||
public ColorEditorWindow()
|
||||
private readonly AppStateHandler _appStateHandler;
|
||||
|
||||
public ColorEditorWindow(AppStateHandler appStateHandler)
|
||||
{
|
||||
InitializeComponent();
|
||||
_appStateHandler = appStateHandler;
|
||||
Closing += ColorEditorWindow_Closing;
|
||||
}
|
||||
|
||||
private void ColorEditorWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
e.Cancel = true;
|
||||
this.Hide();
|
||||
_appStateHandler.EndUserSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace ColorPicker.Controls
|
||||
private void CopyToClipboardButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ClipboardHelper.CopyToClipboard(ColorTextRepresentationTextBlock.Text);
|
||||
SessionEventHelper.Event.EditorColorCopiedToClipboard = true;
|
||||
if (!_copyIndicatorVisible)
|
||||
{
|
||||
AppearCopiedIndicator();
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 1"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"/>
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}"/>
|
||||
<Button x:Name="colorVariation2Button"
|
||||
Grid.Column="1"
|
||||
ui:ControlHelper.CornerRadius="0"
|
||||
@@ -40,7 +41,8 @@
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 2"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"/>
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}"/>
|
||||
<Button x:Name="colorVariation3Button"
|
||||
Grid.Column="3"
|
||||
TabIndex="7"
|
||||
@@ -48,7 +50,8 @@
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 3"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"/>
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}"/>
|
||||
<Button x:Name="colorVariation4Button"
|
||||
Grid.Column="4"
|
||||
TabIndex="8"
|
||||
@@ -56,7 +59,8 @@
|
||||
Background="LightPink"
|
||||
Click="ColorVariationButton_Click"
|
||||
AutomationProperties.Name="Color shade 5"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"/>
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Select_color}"/>
|
||||
<Button x:Name="CurrentColorButton"
|
||||
HorizontalAlignment="Left"
|
||||
Grid.Column="0"
|
||||
@@ -72,7 +76,8 @@
|
||||
AutomationProperties.HelpText="{x:Static p:Resources.Selected_color_helptext}"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Selected_color_tooltip}"
|
||||
Click="CurrentColorButton_Click"
|
||||
Style="{DynamicResource ColorShadeButtonStyle}"/>
|
||||
Style="{DynamicResource ColorShadeButtonStyle}">
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!--Details panel-->
|
||||
@@ -202,71 +207,73 @@
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<Grid HorizontalAlignment="Stretch" Margin="12,16,12,8">
|
||||
<Grid HorizontalAlignment="Stretch"
|
||||
Margin="12,16,12,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="68"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="86" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="36" />
|
||||
<RowDefinition Height="36" />
|
||||
<RowDefinition Height="36" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="R"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox x:Name="RTextBox"
|
||||
Margin="0,0,0,0"
|
||||
Grid.Column="1"
|
||||
Height="32"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Red_value}"
|
||||
TextChanged="RGBTextBoxes_TextChanged"
|
||||
TextWrapping="Wrap"/>
|
||||
VerticalAlignment="Center" />
|
||||
<ui:NumberBox x:Name="RNumberBox"
|
||||
Grid.Column="1"
|
||||
Height="32"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Red_value}"
|
||||
ValueChanged="RGBNumberBox_ValueChanged"
|
||||
Minimum="0"
|
||||
Maximum="255" />
|
||||
|
||||
<TextBlock Text="G"
|
||||
FontWeight="SemiBold"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"/>
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
<TextBox x:Name="GTextBox"
|
||||
Width="68"
|
||||
Height="32"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Green_value}"
|
||||
TextChanged="RGBTextBoxes_TextChanged"
|
||||
TextWrapping="Wrap"/>
|
||||
<ui:NumberBox x:Name="GNumberBox"
|
||||
Height="32"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Green_value}"
|
||||
ValueChanged="RGBNumberBox_ValueChanged"
|
||||
Minimum="0"
|
||||
Maximum="255" />
|
||||
|
||||
<TextBlock Text="B"
|
||||
FontWeight="SemiBold"
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Center"/>
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
<TextBox x:Name="BTextBox"
|
||||
Width="68"
|
||||
Height="32"
|
||||
Grid.Column="1"
|
||||
Grid.Row="2"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Blue_value}"
|
||||
TextChanged="RGBTextBoxes_TextChanged"
|
||||
TextWrapping="Wrap"/>
|
||||
<ui:NumberBox x:Name="BNumberBox"
|
||||
Height="32"
|
||||
Grid.Column="1"
|
||||
Grid.Row="2"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Blue_value}"
|
||||
ValueChanged="RGBNumberBox_ValueChanged"
|
||||
Minimum="0"
|
||||
Maximum="255" />
|
||||
|
||||
<TextBlock Text="HEX"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox x:Name="HexCode"
|
||||
HorizontalAlignment="Stretch"
|
||||
Margin="8,0,0,0"
|
||||
Height="32"
|
||||
Grid.Column="3"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Hex_value}"
|
||||
GotKeyboardFocus="HexCode_GotKeyboardFocus"
|
||||
TextChanged="HexCode_TextChanged"
|
||||
TextWrapping="Wrap"/>
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
<WrapPanel HorizontalAlignment="Right"
|
||||
Margin="0,0,0,0"
|
||||
|
||||
@@ -56,20 +56,24 @@ namespace ColorPicker.Controls
|
||||
|
||||
private static void SelectedColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = (ColorPickerControl)d;
|
||||
var newColor = (Color)e.NewValue;
|
||||
((ColorPickerControl)d)._originalColor = ((ColorPickerControl)d)._currentColor = newColor;
|
||||
var newColorBackground = new SolidColorBrush(newColor);
|
||||
((ColorPickerControl)d).CurrentColorButton.Background = newColorBackground;
|
||||
|
||||
((ColorPickerControl)d)._ignoreHexChanges = true;
|
||||
((ColorPickerControl)d)._ignoreRGBChanges = true;
|
||||
((ColorPickerControl)d).HexCode.Text = ColorToHex(newColor);
|
||||
((ColorPickerControl)d).RTextBox.Text = newColor.R.ToString(CultureInfo.InvariantCulture);
|
||||
((ColorPickerControl)d).GTextBox.Text = newColor.G.ToString(CultureInfo.InvariantCulture);
|
||||
((ColorPickerControl)d).BTextBox.Text = newColor.B.ToString(CultureInfo.InvariantCulture);
|
||||
((ColorPickerControl)d).SetColorFromTextBoxes(System.Drawing.Color.FromArgb(newColor.R, newColor.G, newColor.B));
|
||||
((ColorPickerControl)d)._ignoreRGBChanges = false;
|
||||
((ColorPickerControl)d)._ignoreHexChanges = false;
|
||||
control._originalColor = control._currentColor = newColor;
|
||||
var newColorBackground = new SolidColorBrush(newColor);
|
||||
control.CurrentColorButton.Background = newColorBackground;
|
||||
|
||||
control._ignoreHexChanges = true;
|
||||
control._ignoreRGBChanges = true;
|
||||
|
||||
control.HexCode.Text = ColorToHex(newColor);
|
||||
control.RNumberBox.Text = newColor.R.ToString(CultureInfo.InvariantCulture);
|
||||
control.GNumberBox.Text = newColor.G.ToString(CultureInfo.InvariantCulture);
|
||||
control.BNumberBox.Text = newColor.B.ToString(CultureInfo.InvariantCulture);
|
||||
control.SetColorFromTextBoxes(System.Drawing.Color.FromArgb(newColor.R, newColor.G, newColor.B));
|
||||
|
||||
control._ignoreRGBChanges = false;
|
||||
control._ignoreHexChanges = false;
|
||||
|
||||
var hsv = ColorHelper.ConvertToHSVColor(System.Drawing.Color.FromArgb(newColor.R, newColor.G, newColor.B));
|
||||
|
||||
@@ -107,12 +111,13 @@ namespace ColorPicker.Controls
|
||||
}
|
||||
|
||||
var s = hsv.saturation;
|
||||
var control = (ColorPickerControl)d;
|
||||
|
||||
((ColorPickerControl)d).colorVariation1Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Min(hsv.hue + (hueCoefficient * 8), 360), s, Math.Min(hsv.value + 0.3, 1)));
|
||||
((ColorPickerControl)d).colorVariation2Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Min(hsv.hue + (hueCoefficient * 4), 360), s, Math.Min(hsv.value + 0.15, 1)));
|
||||
control.colorVariation1Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Min(hsv.hue + (hueCoefficient * 8), 360), s, Math.Min(hsv.value + 0.3, 1)));
|
||||
control.colorVariation2Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Min(hsv.hue + (hueCoefficient * 4), 360), s, Math.Min(hsv.value + 0.15, 1)));
|
||||
|
||||
((ColorPickerControl)d).colorVariation3Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Max(hsv.hue - (hueCoefficient2 * 4), 0), s, Math.Max(hsv.value - 0.2, 0)));
|
||||
((ColorPickerControl)d).colorVariation4Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Max(hsv.hue - (hueCoefficient2 * 8), 0), s, Math.Max(hsv.value - 0.3, 0)));
|
||||
control.colorVariation3Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Max(hsv.hue - (hueCoefficient2 * 4), 0), s, Math.Max(hsv.value - 0.2, 0)));
|
||||
control.colorVariation4Button.Background = new SolidColorBrush(HSVColor.RGBFromHSV(Math.Max(hsv.hue - (hueCoefficient2 * 8), 0), s, Math.Max(hsv.value - 0.3, 0)));
|
||||
}
|
||||
|
||||
private void UpdateValueColorGradient(double posX)
|
||||
@@ -161,9 +166,9 @@ namespace ColorPicker.Controls
|
||||
|
||||
if (!_ignoreRGBChanges)
|
||||
{
|
||||
RTextBox.Text = currentColor.R.ToString(CultureInfo.InvariantCulture);
|
||||
GTextBox.Text = currentColor.G.ToString(CultureInfo.InvariantCulture);
|
||||
BTextBox.Text = currentColor.B.ToString(CultureInfo.InvariantCulture);
|
||||
RNumberBox.Text = currentColor.R.ToString(CultureInfo.InvariantCulture);
|
||||
GNumberBox.Text = currentColor.G.ToString(CultureInfo.InvariantCulture);
|
||||
BNumberBox.Text = currentColor.B.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
_currentColor = currentColor;
|
||||
@@ -200,6 +205,7 @@ namespace ColorPicker.Controls
|
||||
detailsStackPanel.BeginAnimation(StackPanel.OpacityProperty, opacityAppear);
|
||||
detailsGrid.BeginAnimation(Grid.HeightProperty, resize);
|
||||
CurrentColorButton.IsEnabled = false;
|
||||
SessionEventHelper.Event.EditorAdjustColorOpened = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,8 +240,8 @@ namespace ColorPicker.Controls
|
||||
private void OKButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
HideDetails();
|
||||
|
||||
SelectedColorChangedCommand.Execute(_currentColor);
|
||||
SessionEventHelper.Event.EditorColorAdjusted = true;
|
||||
}
|
||||
|
||||
private void CancelButton_Click(object sender, RoutedEventArgs e)
|
||||
@@ -253,6 +259,7 @@ namespace ColorPicker.Controls
|
||||
{
|
||||
var selectedColor = ((SolidColorBrush)((Button)sender).Background).Color;
|
||||
SelectedColorChangedCommand.Execute(selectedColor);
|
||||
SessionEventHelper.Event.EditorSimilarColorPicked = true;
|
||||
}
|
||||
|
||||
private void ValueGradientGrid_MouseMove(object sender, MouseEventArgs e)
|
||||
@@ -357,19 +364,15 @@ namespace ColorPicker.Controls
|
||||
}
|
||||
}
|
||||
|
||||
private void RGBTextBoxes_TextChanged(object sender, TextChangedEventArgs e)
|
||||
#pragma warning disable CA1801 // Review unused parameters
|
||||
private void RGBNumberBox_ValueChanged(ModernWpf.Controls.NumberBox sender, ModernWpf.Controls.NumberBoxValueChangedEventArgs args)
|
||||
#pragma warning restore CA1801 // Review unused parameters
|
||||
{
|
||||
var validNumber = int.TryParse((sender as TextBox).Text, out int result);
|
||||
if (!validNumber || result < 0 || result > 255)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_ignoreRGBChanges)
|
||||
{
|
||||
var r = byte.Parse(RTextBox.Text, CultureInfo.InvariantCulture);
|
||||
var g = byte.Parse(GTextBox.Text, CultureInfo.InvariantCulture);
|
||||
var b = byte.Parse(BTextBox.Text, CultureInfo.InvariantCulture);
|
||||
var r = byte.Parse(RNumberBox.Text, CultureInfo.InvariantCulture);
|
||||
var g = byte.Parse(GNumberBox.Text, CultureInfo.InvariantCulture);
|
||||
var b = byte.Parse(BNumberBox.Text, CultureInfo.InvariantCulture);
|
||||
_ignoreRGBChanges = true;
|
||||
SetColorFromTextBoxes(System.Drawing.Color.FromArgb(r, g, b));
|
||||
_ignoreRGBChanges = false;
|
||||
@@ -397,5 +400,10 @@ namespace ColorPicker.Controls
|
||||
{
|
||||
return "#" + BitConverter.ToString(new byte[] { color.R, color.G, color.B }).Replace("-", string.Empty, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
private void HexCode_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
|
||||
{
|
||||
(sender as TextBox).SelectAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Windows;
|
||||
using ColorPicker.Settings;
|
||||
using ColorPicker.ViewModelContracts;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
@@ -13,15 +15,17 @@ namespace ColorPicker.Helpers
|
||||
public class AppStateHandler
|
||||
{
|
||||
private readonly IColorEditorViewModel _colorEditorViewModel;
|
||||
private readonly IUserSettings _userSettings;
|
||||
private ColorEditorWindow _colorEditorWindow;
|
||||
private bool _colorPickerShown;
|
||||
private object _colorPickerVisibilityLock = new object();
|
||||
|
||||
[ImportingConstructor]
|
||||
public AppStateHandler(IColorEditorViewModel colorEditorViewModel)
|
||||
public AppStateHandler(IColorEditorViewModel colorEditorViewModel, IUserSettings userSettings)
|
||||
{
|
||||
Application.Current.MainWindow.Closed += MainWindow_Closed;
|
||||
_colorEditorViewModel = colorEditorViewModel;
|
||||
_userSettings = userSettings;
|
||||
}
|
||||
|
||||
public event EventHandler AppShown;
|
||||
@@ -30,45 +34,61 @@ namespace ColorPicker.Helpers
|
||||
|
||||
public event EventHandler AppClosed;
|
||||
|
||||
public void ShowColorPicker()
|
||||
public void StartUserSession()
|
||||
{
|
||||
lock (_colorPickerVisibilityLock)
|
||||
{
|
||||
if (!_colorPickerShown)
|
||||
if (!_colorPickerShown && !IsColorPickerEditorVisible())
|
||||
{
|
||||
AppShown?.Invoke(this, EventArgs.Empty);
|
||||
Application.Current.MainWindow.Opacity = 0;
|
||||
Application.Current.MainWindow.Visibility = Visibility.Visible;
|
||||
_colorPickerShown = true;
|
||||
SessionEventHelper.Start(_userSettings.ActivationAction.Value);
|
||||
}
|
||||
|
||||
if (_userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenEditor)
|
||||
{
|
||||
ShowColorPickerEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowColorPicker();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HideColorPicker()
|
||||
public void EndUserSession()
|
||||
{
|
||||
lock (_colorPickerVisibilityLock)
|
||||
{
|
||||
if (_colorPickerShown)
|
||||
if (IsColorPickerEditorVisible() || _colorPickerShown)
|
||||
{
|
||||
Application.Current.MainWindow.Opacity = 0;
|
||||
Application.Current.MainWindow.Visibility = Visibility.Collapsed;
|
||||
AppHidden?.Invoke(this, EventArgs.Empty);
|
||||
_colorPickerShown = false;
|
||||
if (IsColorPickerEditorVisible())
|
||||
{
|
||||
HideColorPickerEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
HideColorPicker();
|
||||
}
|
||||
|
||||
SessionEventHelper.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowColorPickerEditor()
|
||||
public void OnColorPickerMouseDown()
|
||||
{
|
||||
if (_colorEditorWindow == null)
|
||||
if (_userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenColorPickerAndThenEditor || _userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenEditor)
|
||||
{
|
||||
_colorEditorWindow = new ColorEditorWindow();
|
||||
_colorEditorWindow.Content = _colorEditorViewModel;
|
||||
_colorEditorViewModel.OpenColorPickerRequested += ColorEditorViewModel_OpenColorPickerRequested;
|
||||
}
|
||||
lock (_colorPickerVisibilityLock)
|
||||
{
|
||||
HideColorPicker();
|
||||
}
|
||||
|
||||
_colorEditorViewModel.Initialize();
|
||||
_colorEditorWindow.Show();
|
||||
ShowColorPickerEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
EndUserSession();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTopMost()
|
||||
@@ -77,6 +97,65 @@ namespace ColorPicker.Helpers
|
||||
Application.Current.MainWindow.Topmost = true;
|
||||
}
|
||||
|
||||
private void ShowColorPicker()
|
||||
{
|
||||
if (!_colorPickerShown)
|
||||
{
|
||||
AppShown?.Invoke(this, EventArgs.Empty);
|
||||
Application.Current.MainWindow.Opacity = 0;
|
||||
Application.Current.MainWindow.Visibility = Visibility.Visible;
|
||||
_colorPickerShown = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void HideColorPicker()
|
||||
{
|
||||
if (_colorPickerShown)
|
||||
{
|
||||
Application.Current.MainWindow.Opacity = 0;
|
||||
Application.Current.MainWindow.Visibility = Visibility.Collapsed;
|
||||
AppHidden?.Invoke(this, EventArgs.Empty);
|
||||
_colorPickerShown = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowColorPickerEditor()
|
||||
{
|
||||
if (_colorEditorWindow == null)
|
||||
{
|
||||
_colorEditorWindow = new ColorEditorWindow(this);
|
||||
_colorEditorWindow.Content = _colorEditorViewModel;
|
||||
_colorEditorViewModel.OpenColorPickerRequested += ColorEditorViewModel_OpenColorPickerRequested;
|
||||
_colorEditorViewModel.OpenColorPickerRequested += (object sender, EventArgs e) =>
|
||||
{
|
||||
SessionEventHelper.Event.EditorColorPickerOpened = true;
|
||||
};
|
||||
}
|
||||
|
||||
_colorEditorViewModel.Initialize();
|
||||
_colorEditorWindow.Show();
|
||||
SessionEventHelper.Event.EditorOpened = true;
|
||||
}
|
||||
|
||||
private void HideColorPickerEditor()
|
||||
{
|
||||
if (_colorEditorWindow != null)
|
||||
{
|
||||
_colorEditorWindow.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsColorPickerEditorVisible()
|
||||
{
|
||||
if (_colorEditorWindow != null)
|
||||
{
|
||||
// Check if we are visible and on top. Using focus producing unreliable results the first time the picker is opened.
|
||||
return _colorEditorWindow.Topmost && _colorEditorWindow.IsVisible;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void MainWindow_Closed(object sender, EventArgs e)
|
||||
{
|
||||
AppClosed?.Invoke(this, EventArgs.Empty);
|
||||
@@ -84,7 +163,11 @@ namespace ColorPicker.Helpers
|
||||
|
||||
private void ColorEditorViewModel_OpenColorPickerRequested(object sender, EventArgs e)
|
||||
{
|
||||
ShowColorPicker();
|
||||
lock (_colorPickerVisibilityLock)
|
||||
{
|
||||
ShowColorPicker();
|
||||
}
|
||||
|
||||
_colorEditorWindow.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,16 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using interop;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
public static class Logger
|
||||
{
|
||||
private static readonly IFileSystem _fileSystem = new FileSystem();
|
||||
private static readonly string ApplicationLogPath = _fileSystem.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ColorPicker");
|
||||
private static readonly string ApplicationLogPath = Path.Combine(Constants.AppDataPath(), "ColorPicker\\Logs");
|
||||
|
||||
static Logger()
|
||||
{
|
||||
|
||||
@@ -3,25 +3,13 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using interop;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
[Export(typeof(NativeEventWaiter))]
|
||||
public class NativeEventWaiter
|
||||
public static class NativeEventWaiter
|
||||
{
|
||||
private AppStateHandler _appStateHandler;
|
||||
|
||||
[ImportingConstructor]
|
||||
public NativeEventWaiter(AppStateHandler appStateHandler)
|
||||
{
|
||||
_appStateHandler = appStateHandler;
|
||||
WaitForEventLoop(Constants.ShowColorPickerSharedEvent(), _appStateHandler.ShowColorPicker);
|
||||
}
|
||||
|
||||
public static void WaitForEventLoop(string eventName, Action callback)
|
||||
{
|
||||
new Thread(() =>
|
||||
@@ -31,7 +19,7 @@ namespace ColorPicker.Helpers
|
||||
{
|
||||
if (eventHandle.WaitOne())
|
||||
{
|
||||
Logger.LogInfo("Successfully waited for SHOW_COLOR_PICKER_EVENT");
|
||||
Logger.LogInfo($"Successfully waited for {eventName}");
|
||||
Application.Current.Dispatcher.Invoke(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using ColorPicker.Telemetry;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
public static class SessionEventHelper
|
||||
{
|
||||
public static ColorPickerSession Event { get; private set; }
|
||||
|
||||
public static void Start(ColorPickerActivationAction startedAs)
|
||||
{
|
||||
Event = new ColorPickerSession();
|
||||
Event.StartedAs = startedAs.ToString();
|
||||
_startTime = DateTime.Now;
|
||||
}
|
||||
|
||||
public static void End()
|
||||
{
|
||||
if (_startTime == null)
|
||||
{
|
||||
Logger.LogError("Failed to send ColorPickerSessionEvent");
|
||||
return;
|
||||
}
|
||||
|
||||
var duration = DateTime.Now - _startTime.Value;
|
||||
Event.Duration = duration.Seconds + (duration.Milliseconds == 0 ? 0 : 1);
|
||||
_startTime = null;
|
||||
PowerToysTelemetry.Log.WriteEvent(Event);
|
||||
}
|
||||
|
||||
private static DateTime? _startTime;
|
||||
}
|
||||
}
|
||||
@@ -179,7 +179,7 @@ namespace ColorPicker.Helpers
|
||||
{
|
||||
_zoomWindow.Left = _lastLeft + 1;
|
||||
_zoomWindow.Top = _lastTop + 1;
|
||||
PowerToysTelemetry.Log.WriteEvent(new ColorPickerZoomOpenedEvent());
|
||||
SessionEventHelper.Event.ZoomUsed = true;
|
||||
}
|
||||
|
||||
_throttledActionInvoker.ScheduleAction(
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
using ColorPicker.Helpers;
|
||||
using ColorPicker.Settings;
|
||||
@@ -22,7 +21,7 @@ namespace ColorPicker.Keyboard
|
||||
{
|
||||
private readonly AppStateHandler _appStateHandler;
|
||||
private readonly IUserSettings _userSettings;
|
||||
private List<string> _previouslyPressedKeys;
|
||||
private List<string> _previouslyPressedKeys = new List<string>();
|
||||
|
||||
private List<string> _activationKeys = new List<string>();
|
||||
private GlobalKeyboardHook _keyboardHook;
|
||||
@@ -73,47 +72,43 @@ namespace ColorPicker.Keyboard
|
||||
// ESC pressed
|
||||
if (virtualCode == KeyInterop.VirtualKeyFromKey(Key.Escape))
|
||||
{
|
||||
_appStateHandler.HideColorPicker();
|
||||
PowerToysTelemetry.Log.WriteEvent(new ColorPickerCancelledEvent());
|
||||
_appStateHandler.EndUserSession();
|
||||
return;
|
||||
}
|
||||
|
||||
var name = Helper.GetKeyName((uint)virtualCode);
|
||||
|
||||
// If the last key pressed is a modifier key, then currentlyPressedKeys cannot possibly match with _activationKeys
|
||||
// because _activationKeys contains exactly 1 non-modifier key. Hence, there's no need to check if `name` is a
|
||||
// modifier key or to do any additional processing on it.
|
||||
if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown || e.KeyboardState == GlobalKeyboardHook.KeyboardState.SysKeyDown)
|
||||
if ((System.Windows.Application.Current as ColorPickerUI.App).IsRunningDetachedFromPowerToys())
|
||||
{
|
||||
// Check pressed modifier keys.
|
||||
AddModifierKeys(currentlyPressedKeys);
|
||||
var name = Helper.GetKeyName((uint)virtualCode);
|
||||
|
||||
currentlyPressedKeys.Add(name);
|
||||
}
|
||||
|
||||
currentlyPressedKeys.Sort();
|
||||
|
||||
if (currentlyPressedKeys.Count == 0 && _previouslyPressedKeys.Count != 0)
|
||||
{
|
||||
// no keys pressed, we can enable activation shortcut again
|
||||
_activationShortcutPressed = false;
|
||||
}
|
||||
|
||||
_previouslyPressedKeys = currentlyPressedKeys;
|
||||
|
||||
if (ArraysAreSame(currentlyPressedKeys, _activationKeys))
|
||||
{
|
||||
// avoid triggering this action multiple times as this will be called nonstop while keys are pressed
|
||||
if (!_activationShortcutPressed)
|
||||
// If the last key pressed is a modifier key, then currentlyPressedKeys cannot possibly match with _activationKeys
|
||||
// because _activationKeys contains exactly 1 non-modifier key. Hence, there's no need to check if `name` is a
|
||||
// modifier key or to do any additional processing on it.
|
||||
if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown || e.KeyboardState == GlobalKeyboardHook.KeyboardState.SysKeyDown)
|
||||
{
|
||||
_activationShortcutPressed = true;
|
||||
if (_userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenEditor)
|
||||
// Check pressed modifier keys.
|
||||
AddModifierKeys(currentlyPressedKeys);
|
||||
|
||||
currentlyPressedKeys.Add(name);
|
||||
}
|
||||
|
||||
currentlyPressedKeys.Sort();
|
||||
|
||||
if (currentlyPressedKeys.Count == 0 && _previouslyPressedKeys.Count != 0)
|
||||
{
|
||||
// no keys pressed, we can enable activation shortcut again
|
||||
_activationShortcutPressed = false;
|
||||
}
|
||||
|
||||
_previouslyPressedKeys = currentlyPressedKeys;
|
||||
|
||||
if (ArraysAreSame(currentlyPressedKeys, _activationKeys))
|
||||
{
|
||||
// avoid triggering this action multiple times as this will be called nonstop while keys are pressed
|
||||
if (!_activationShortcutPressed)
|
||||
{
|
||||
_appStateHandler.ShowColorPickerEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
_appStateHandler.ShowColorPicker();
|
||||
_activationShortcutPressed = true;
|
||||
|
||||
_appStateHandler.StartUserSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ namespace ColorPicker.Mouse
|
||||
{
|
||||
MouseDevice mouseDev = InputManager.Current.PrimaryMouseDevice;
|
||||
MouseWheel.Invoke(null, new MouseWheelEventArgs(mouseDev, Environment.TickCount, (int)mouseHookStruct.mouseData >> 16));
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,15 @@ namespace ColorPicker.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Select color.
|
||||
/// </summary>
|
||||
public static string Select_color {
|
||||
get {
|
||||
return ResourceManager.GetString("Select_color", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Selected color.
|
||||
/// </summary>
|
||||
|
||||
@@ -361,4 +361,7 @@
|
||||
<value>Plum</value>
|
||||
<comment>Plum color</comment>
|
||||
</data>
|
||||
<data name="Select_color" xml:space="preserve">
|
||||
<value>Select color</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -105,6 +105,7 @@
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Focusable="False"
|
||||
Opacity="0"
|
||||
RecognizesAccessKey="True"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</Border>
|
||||
@@ -113,12 +114,12 @@
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Background" Property="Opacity" Value="0.8" />
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
|
||||
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
|
||||
<Setter TargetName="ContentPresenter" Property="Opacity" Value="1" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="Background" Property="Opacity" Value="0.9" />
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
|
||||
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
|
||||
<Setter TargetName="ContentPresenter" Property="Opacity" Value="1" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
@@ -25,5 +25,7 @@ namespace ColorPicker.Settings
|
||||
ObservableCollection<string> VisibleColorFormats { get; }
|
||||
|
||||
SettingItem<bool> ShowColorName { get; }
|
||||
|
||||
void SendSettingsTelemetry();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using ColorPicker.Common;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
namespace ColorPicker.Settings
|
||||
{
|
||||
@@ -160,5 +161,27 @@ namespace ColorPicker.Settings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendSettingsTelemetry()
|
||||
{
|
||||
Logger.LogInfo("Sending settings telemetry");
|
||||
var settings = _settingsUtils.GetSettingsOrDefault<ColorPickerSettings>(ColorPickerModuleName);
|
||||
var properties = settings?.Properties;
|
||||
if (properties == null)
|
||||
{
|
||||
Logger.LogError("Failed to send settings telemetry");
|
||||
return;
|
||||
}
|
||||
|
||||
var telemetrySettings = new Telemetry.ColorPickerSettings(properties.VisibleColorFormats)
|
||||
{
|
||||
ActivationShortcut = properties.ActivationShortcut.ToString(),
|
||||
ActivationBehaviour = properties.ActivationAction.ToString(),
|
||||
ColorFormatForClipboard = properties.CopiedColorRepresentation.ToString(),
|
||||
ShowColorName = properties.ShowColorName,
|
||||
};
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(telemetrySettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace ColorPicker.Telemetry
|
||||
{
|
||||
[EventData]
|
||||
public class ColorPickerSession : EventBase, IEvent
|
||||
{
|
||||
public ColorPickerSession()
|
||||
{
|
||||
EventName = "ColorPicker_Session";
|
||||
}
|
||||
|
||||
public string StartedAs { get; set; }
|
||||
|
||||
public bool ZoomUsed { get; set; }
|
||||
|
||||
public bool EditorOpened { get; set; }
|
||||
|
||||
public bool EditorColorPickerOpened { get; set; }
|
||||
|
||||
public bool EditorAdjustColorOpened { get; set; }
|
||||
|
||||
public bool EditorColorAdjusted { get; set; }
|
||||
|
||||
public bool EditorSimilarColorPicked { get; set; }
|
||||
|
||||
public bool EditorHistoryColorPicked { get; set; }
|
||||
|
||||
public bool EditorHistoryColorRemoved { get; set; }
|
||||
|
||||
public bool EditorColorCopiedToClipboard { get; set; }
|
||||
|
||||
public int Duration { get; set; }
|
||||
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace ColorPicker.Telemetry
|
||||
{
|
||||
[EventData]
|
||||
public class ColorPickerSettings : EventBase, IEvent
|
||||
{
|
||||
public ColorPickerSettings(IDictionary<string, bool> editorFormats)
|
||||
{
|
||||
EditorFormats = editorFormats;
|
||||
EventName = "ColorPicker_Settings";
|
||||
}
|
||||
|
||||
public string ActivationShortcut { get; set; }
|
||||
|
||||
public string ActivationBehaviour { get; set; }
|
||||
|
||||
public string ColorFormatForClipboard { get; set; }
|
||||
|
||||
public bool ShowColorName { get; set; }
|
||||
|
||||
public IDictionary<string, bool> EditorFormats { get; }
|
||||
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace ColorPicker.Telemetry
|
||||
{
|
||||
[EventData]
|
||||
public class ColorPickerShowEvent : EventBase, IEvent
|
||||
{
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace ColorPicker.Telemetry
|
||||
{
|
||||
[EventData]
|
||||
public class ColorPickerZoomOpenedEvent : EventBase, IEvent
|
||||
{
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,7 @@ namespace ColorPicker.ViewModels
|
||||
var indexToSelect = SelectedColorIndex == ColorsHistory.Count - 1 ? ColorsHistory.Count - 2 : SelectedColorIndex;
|
||||
ColorsHistory.RemoveAt(SelectedColorIndex);
|
||||
SelectedColorIndex = indexToSelect;
|
||||
SessionEventHelper.Event.EditorHistoryColorRemoved = true;
|
||||
}
|
||||
|
||||
private void SetupAllColorRepresentations()
|
||||
|
||||
@@ -15,6 +15,7 @@ using ColorPicker.Mouse;
|
||||
using ColorPicker.Settings;
|
||||
using ColorPicker.Telemetry;
|
||||
using ColorPicker.ViewModelContracts;
|
||||
using interop;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
@@ -26,7 +27,6 @@ namespace ColorPicker.ViewModels
|
||||
private readonly ZoomWindowHelper _zoomWindowHelper;
|
||||
private readonly AppStateHandler _appStateHandler;
|
||||
private readonly IUserSettings _userSettings;
|
||||
private readonly NativeEventWaiter _nativeEventWaiter;
|
||||
|
||||
/// <summary>
|
||||
/// Backing field for <see cref="OtherColor"/>
|
||||
@@ -49,13 +49,13 @@ namespace ColorPicker.ViewModels
|
||||
ZoomWindowHelper zoomWindowHelper,
|
||||
AppStateHandler appStateHandler,
|
||||
KeyboardMonitor keyboardMonitor,
|
||||
NativeEventWaiter nativeEventWaiter,
|
||||
IUserSettings userSettings)
|
||||
{
|
||||
_zoomWindowHelper = zoomWindowHelper;
|
||||
_appStateHandler = appStateHandler;
|
||||
_userSettings = userSettings;
|
||||
_nativeEventWaiter = nativeEventWaiter;
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ShowColorPickerSharedEvent(), _appStateHandler.StartUserSession);
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ColorPickerSendSettingsTelemetryEvent(), _userSettings.SendSettingsTelemetry);
|
||||
|
||||
if (mouseInfoProvider != null)
|
||||
{
|
||||
@@ -140,14 +140,7 @@ namespace ColorPicker.ViewModels
|
||||
_userSettings.ColorHistory.RemoveAt(_userSettings.ColorHistory.Count - 1);
|
||||
}
|
||||
|
||||
_appStateHandler.HideColorPicker();
|
||||
|
||||
if (_userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenColorPickerAndThenEditor || _userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenEditor)
|
||||
{
|
||||
_appStateHandler.ShowColorPickerEditor();
|
||||
}
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new ColorPickerShowEvent());
|
||||
_appStateHandler.OnColorPickerMouseDown();
|
||||
}
|
||||
|
||||
private string GetColorString()
|
||||
|
||||
@@ -20,13 +20,16 @@
|
||||
|
||||
<!-- Side bar -->
|
||||
<Grid Background="{DynamicResource SecondaryBackgroundBrush}">
|
||||
<ui:ListView Margin="0,48,0,0"
|
||||
<ui:ListView x:Name="HistoryColors"
|
||||
Margin="0,48,0,0"
|
||||
Grid.Row="1"
|
||||
Padding="0"
|
||||
TabIndex="3"
|
||||
ItemsSource="{Binding ColorsHistory}"
|
||||
SelectedIndex="{Binding SelectedColorIndex}"
|
||||
ItemContainerStyle="{DynamicResource ColorHistoryListViewStyle}">
|
||||
ItemContainerStyle="{DynamicResource ColorHistoryListViewStyle}"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="HistoryColors_ItemClick">
|
||||
<ui:ListView.ContextMenu>
|
||||
<ContextMenu Visibility="{Binding ColorsHistory.Count, Converter={StaticResource numberToVisibilityConverter}}">
|
||||
<MenuItem Header="{x:Static p:Resources.Remove}"
|
||||
@@ -75,7 +78,7 @@
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,1,0,0" />
|
||||
|
||||
|
||||
<!-- Enable once we have settings linking available -->
|
||||
<!--<Button Width="46"
|
||||
Height="32"
|
||||
@@ -87,7 +90,7 @@
|
||||
Margin="0,0,46,0"
|
||||
ToolTipService.ToolTip="{x:Static p:Resources.Open_settings}"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Open_settings}" />-->
|
||||
|
||||
|
||||
<Button Width="64"
|
||||
Height="32"
|
||||
TabIndex="1"
|
||||
|
||||
@@ -2,20 +2,8 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using ColorPicker.Helpers;
|
||||
|
||||
namespace ColorPicker.Views
|
||||
{
|
||||
@@ -26,5 +14,12 @@ namespace ColorPicker.Views
|
||||
{
|
||||
public ColorEditorView() =>
|
||||
InitializeComponent();
|
||||
|
||||
private void HistoryColors_ItemClick(object sender, ModernWpf.Controls.ItemClickEventArgs e)
|
||||
{
|
||||
// Note: it does not handle clicking on the same color.
|
||||
// More appropriate event would be SelectionChanged but we can not distinguish between user action and program action inside of it.
|
||||
SessionEventHelper.Event.EditorHistoryColorPicked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.0.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <lib/FancyZonesWinHookEventIDs.h>
|
||||
#include <lib/FancyZonesData.cpp>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/window.h>
|
||||
@@ -156,9 +157,19 @@ public:
|
||||
{
|
||||
app_name = GET_RESOURCE_STRING(IDS_FANCYZONES);
|
||||
app_key = NonLocalizable::FancyZonesStr;
|
||||
std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(app_key));
|
||||
const auto appFolder = PTSettingsHelper::get_module_save_folder_location(app_key);
|
||||
const std::filesystem::path logFolder = LoggerHelpers::get_log_folder_path(appFolder);
|
||||
|
||||
std::filesystem::path logFilePath(logFolder);
|
||||
logFilePath.append(LogSettings::fancyZonesLogPath);
|
||||
Logger::init(LogSettings::fancyZonesLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
||||
|
||||
std::filesystem::path oldLogFolder(appFolder);
|
||||
oldLogFolder.append(LogSettings::fancyZonesOldLogPath);
|
||||
LoggerHelpers::delete_old_log_folder(oldLogFolder);
|
||||
|
||||
LoggerHelpers::delete_other_versions_log_folders(appFolder, logFolder);
|
||||
|
||||
m_settings = MakeFancyZonesSettings(reinterpret_cast<HINSTANCE>(&__ImageBase), FancyZonesModule::get_name(), FancyZonesModule::get_key());
|
||||
FancyZonesDataInstance().LoadFancyZonesData();
|
||||
s_instance = this;
|
||||
|
||||
@@ -135,15 +135,7 @@ namespace FancyZonesEditor
|
||||
sb.AppendLine(ParsingErrorDataTag);
|
||||
sb.AppendLine(parseResult.MalformedData);
|
||||
|
||||
string message = parseResult.Message + Environment.NewLine + Environment.NewLine + FancyZonesEditor.Properties.Resources.Error_Parsing_Zones_Settings_User_Choice;
|
||||
if (MessageBox.Show(message, FancyZonesEditor.Properties.Resources.Error_Parsing_Zones_Settings_Title, MessageBoxButton.YesNo) == MessageBoxResult.No)
|
||||
{
|
||||
// TODO: log error
|
||||
ShowExceptionReportMessageBox(sb.ToString());
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
ShowExceptionReportMessageBox(sb.ToString());
|
||||
MessageBox.Show(parseResult.Message, FancyZonesEditor.Properties.Resources.Error_Parsing_Zones_Settings_Title, MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
MainWindowSettingsModel settings = ((App)Current).MainWindowSettings;
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||
<Border x:Name="ThumbBorder" Opacity="0" BorderBrush="{DynamicResource SystemControlBackgroundAccentBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
|
||||
<Border x:Name="ThumbBorder"
|
||||
Opacity="0"
|
||||
CornerRadius="0"
|
||||
BorderBrush="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates" >
|
||||
<VisualStateGroup.Transitions>
|
||||
@@ -64,7 +69,9 @@
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsDefaulted" Value="true">
|
||||
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource SystemControlBackgroundAccentBrush}"/>
|
||||
<Setter Property="BorderBrush"
|
||||
TargetName="border"
|
||||
Value="{DynamicResource SystemControlBackgroundAccentBrush}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Opacity" TargetName="contentPresenter" Value="0.6"/>
|
||||
@@ -79,10 +86,9 @@
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Border BorderBrush="{DynamicResource LayoutPreviewZoneBorderBrush}"
|
||||
<Border BorderBrush="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||
Background="{DynamicResource CanvasZoneBackgroundBrush}"
|
||||
CornerRadius="4"
|
||||
Effect="{StaticResource ZoneDropShadow}"
|
||||
CornerRadius="0"
|
||||
BorderThickness="1">
|
||||
<Grid x:Name="Frame">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -129,15 +135,15 @@
|
||||
|
||||
<Thumb x:Name="Caption" Cursor="SizeAll" Background="Transparent" BorderThickness="3" Padding="4" Grid.Column="0" Grid.ColumnSpan="5" Margin="-1" Grid.Row="0" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="Caption_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
|
||||
<Thumb x:Name="NResize" Cursor="SizeNS" BorderThickness="0,3,0,0" Grid.ColumnSpan="5" DragDelta="UniversalDragDelta" DragStarted="NResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SResize" Cursor="SizeNS" BorderThickness="0,0,0,3" Grid.Row="4" Grid.ColumnSpan="5" DragDelta="UniversalDragDelta" DragStarted="SResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="WResize" Cursor="SizeWE" BorderThickness="3,0,0,0" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="WResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="EResize" Cursor="SizeWE" BorderThickness="0,0,3,0" Grid.Column="4" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="EResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="NResize" Cursor="SizeNS" BorderThickness="0,2,0,0" Grid.ColumnSpan="5" DragDelta="UniversalDragDelta" DragStarted="NResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SResize" Cursor="SizeNS" BorderThickness="0,0,0,2" Grid.Row="4" Grid.ColumnSpan="5" DragDelta="UniversalDragDelta" DragStarted="SResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="WResize" Cursor="SizeWE" BorderThickness="2,0,0,0" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="WResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="EResize" Cursor="SizeWE" BorderThickness="0,0,2,0" Grid.Column="4" Grid.RowSpan="5" DragDelta="UniversalDragDelta" DragStarted="EResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
|
||||
<Thumb x:Name="NWResize" Cursor="SizeNWSE" BorderThickness="3,3,0,0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NWResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="NEResize" Cursor="SizeNESW" BorderThickness="0,3,3,0" Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NEResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SWResize" Cursor="SizeNESW" BorderThickness="3,0,0,3" Grid.Row="3" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SWResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SEResize" Cursor="SizeNWSE" BorderThickness="0,0,3,3" Grid.Row="3" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SEResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="NWResize" Cursor="SizeNWSE" BorderThickness="2,2,0,0" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NWResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="NEResize" Cursor="SizeNESW" BorderThickness="0,2,2,0" Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="NEResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SWResize" Cursor="SizeNESW" BorderThickness="2,0,0,2" Grid.Row="3" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SWResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
<Thumb x:Name="SEResize" Cursor="SizeNWSE" BorderThickness="0,0,2,2" Grid.Row="3" Grid.Column="3" Grid.RowSpan="2" Grid.ColumnSpan="2" DragDelta="UniversalDragDelta" DragStarted="SEResize_DragStarted" Style="{DynamicResource CanvasZoneThumbStyle}"/>
|
||||
|
||||
<Button Content=""
|
||||
BorderThickness="0"
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.IO.Abstractions" Version="12.2.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="4.7.2" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="images\FancyZonesEditor.ico" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,604 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using FancyZonesEditor.Models;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
public class GridDragHandles
|
||||
{
|
||||
public GridDragHandles(UIElementCollection resizers, Action<object, DragDeltaEventArgs> dragDelta, Action<object, DragCompletedEventArgs> dragCompleted)
|
||||
{
|
||||
_resizers = resizers;
|
||||
_dragDelta = dragDelta;
|
||||
_dragCompleted = dragCompleted;
|
||||
}
|
||||
|
||||
public void InitDragHandles(GridLayoutModel model)
|
||||
{
|
||||
if (_resizers.Count == 0)
|
||||
{
|
||||
int[,] indices = model.CellChildMap;
|
||||
|
||||
// horizontal resizers
|
||||
for (int row = 0; row < model.Rows - 1; row++)
|
||||
{
|
||||
for (int col = 0; col < model.Columns; col++)
|
||||
{
|
||||
if (indices[row, col] != indices[row + 1, col])
|
||||
{
|
||||
int endCol = col + 1;
|
||||
while (endCol < model.Columns && indices[row, endCol] != indices[row + 1, endCol])
|
||||
{
|
||||
endCol++;
|
||||
}
|
||||
|
||||
AddDragHandle(Orientation.Horizontal, row, row + 1, col, endCol, row);
|
||||
col = endCol - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vertical resizers
|
||||
for (int col = 0; col < model.Columns - 1; col++)
|
||||
{
|
||||
for (int row = 0; row < model.Rows; row++)
|
||||
{
|
||||
if (indices[row, col] != indices[row, col + 1])
|
||||
{
|
||||
int endRow = row + 1;
|
||||
while (endRow < model.Rows && indices[endRow, col] != indices[endRow, col + 1])
|
||||
{
|
||||
endRow++;
|
||||
}
|
||||
|
||||
AddDragHandle(Orientation.Vertical, row, endRow, col, col + 1, col + model.Rows - 1);
|
||||
row = endRow - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddDragHandle(Orientation orientation, int foundRow, int foundCol, GridLayoutModel model)
|
||||
{
|
||||
int[,] indices = model.CellChildMap;
|
||||
|
||||
int endRow = foundRow + 1;
|
||||
while (endRow < model.Rows && indices[endRow, foundCol] == indices[endRow - 1, foundCol])
|
||||
{
|
||||
endRow++;
|
||||
}
|
||||
|
||||
int endCol = foundCol + 1;
|
||||
while (endCol < model.Columns && indices[foundRow, endCol] == indices[foundRow, endCol - 1])
|
||||
{
|
||||
endCol++;
|
||||
}
|
||||
|
||||
int index = (orientation == Orientation.Horizontal) ? foundRow : foundCol + model.Rows - 1;
|
||||
AddDragHandle(orientation, foundRow, endRow, foundCol, endCol, index);
|
||||
}
|
||||
|
||||
public void AddDragHandle(Orientation orientation, int rowStart, int rowEnd, int colStart, int colEnd, int index)
|
||||
{
|
||||
GridResizer resizer = new GridResizer
|
||||
{
|
||||
Orientation = orientation,
|
||||
StartRow = rowStart,
|
||||
EndRow = rowEnd,
|
||||
StartCol = colStart,
|
||||
EndCol = colEnd,
|
||||
};
|
||||
|
||||
resizer.DragDelta += (obj, eventArgs) => _dragDelta(obj, eventArgs);
|
||||
resizer.DragCompleted += (obj, eventArgs) => _dragCompleted(obj, eventArgs);
|
||||
|
||||
if (index > _resizers.Count)
|
||||
{
|
||||
index = _resizers.Count;
|
||||
}
|
||||
|
||||
_resizers.Insert(index, resizer);
|
||||
}
|
||||
|
||||
public void UpdateForExistingVerticalSplit(GridLayoutModel model, int foundRow, int splitCol)
|
||||
{
|
||||
Func<GridResizer, bool> cmpr = (GridResizer resizer) =>
|
||||
{
|
||||
return resizer.Orientation == Orientation.Vertical && resizer.StartCol == splitCol;
|
||||
};
|
||||
|
||||
Func<GridResizer, bool> endCmpr = (GridResizer resizer) =>
|
||||
{
|
||||
return resizer.EndRow == foundRow;
|
||||
};
|
||||
|
||||
Func<GridResizer, bool> startCmpr = (GridResizer resizer) =>
|
||||
{
|
||||
return resizer.StartRow == foundRow + 1;
|
||||
};
|
||||
|
||||
if (!UpdateDragHandlerForExistingSplit(Orientation.Vertical, cmpr, endCmpr, startCmpr))
|
||||
{
|
||||
AddDragHandle(Orientation.Vertical, foundRow, splitCol, model);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateForExistingHorizontalSplit(GridLayoutModel model, int splitRow, int foundCol)
|
||||
{
|
||||
Func<GridResizer, bool> cmpr = (GridResizer resizer) =>
|
||||
{
|
||||
return resizer.Orientation == Orientation.Horizontal && resizer.StartRow == splitRow;
|
||||
};
|
||||
|
||||
Func<GridResizer, bool> endCmpr = (GridResizer resizer) =>
|
||||
{
|
||||
return resizer.EndCol == foundCol;
|
||||
};
|
||||
|
||||
Func<GridResizer, bool> startCmpr = (GridResizer resizer) =>
|
||||
{
|
||||
return resizer.StartCol == foundCol + 1;
|
||||
};
|
||||
|
||||
if (!UpdateDragHandlerForExistingSplit(Orientation.Horizontal, cmpr, endCmpr, startCmpr))
|
||||
{
|
||||
AddDragHandle(Orientation.Horizontal, splitRow, foundCol, model);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has to be called on split before adding new drag handle
|
||||
*/
|
||||
public void UpdateAfterVerticalSplit(int foundCol)
|
||||
{
|
||||
foreach (GridResizer r in _resizers)
|
||||
{
|
||||
if (r.StartCol > foundCol || (r.StartCol == foundCol && r.Orientation == Orientation.Vertical))
|
||||
{
|
||||
r.StartCol++;
|
||||
}
|
||||
|
||||
if (r.EndCol > foundCol)
|
||||
{
|
||||
r.EndCol++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has to be called on split before adding new drag handle
|
||||
*/
|
||||
public void UpdateAfterHorizontalSplit(int foundRow)
|
||||
{
|
||||
foreach (GridResizer r in _resizers)
|
||||
{
|
||||
if (r.StartRow > foundRow || (r.StartRow == foundRow && r.Orientation == Orientation.Horizontal))
|
||||
{
|
||||
r.StartRow++;
|
||||
}
|
||||
|
||||
if (r.EndRow > foundRow)
|
||||
{
|
||||
r.EndRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateAfterSwap(GridResizer resizer, double delta)
|
||||
{
|
||||
Orientation orientation = resizer.Orientation;
|
||||
bool isHorizontal = orientation == Orientation.Horizontal;
|
||||
bool isDeltaNegative = delta < 0;
|
||||
List<GridResizer> swappedResizers = new List<GridResizer>();
|
||||
|
||||
if (isDeltaNegative)
|
||||
{
|
||||
DecreaseResizerValues(resizer, orientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
IncreaseResizerValues(resizer, orientation);
|
||||
}
|
||||
|
||||
// same orientation resizers update
|
||||
foreach (GridResizer r in _resizers)
|
||||
{
|
||||
if (r.Orientation == orientation)
|
||||
{
|
||||
if ((isHorizontal && r.StartRow == resizer.StartRow && r.StartCol != resizer.StartCol) ||
|
||||
(!isHorizontal && r.StartCol == resizer.StartCol && r.StartRow != resizer.StartRow))
|
||||
{
|
||||
if (isDeltaNegative)
|
||||
{
|
||||
IncreaseResizerValues(r, orientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
DecreaseResizerValues(r, orientation);
|
||||
}
|
||||
|
||||
swappedResizers.Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// different orientation resizers update
|
||||
foreach (GridResizer r in _resizers)
|
||||
{
|
||||
if (r.Orientation != resizer.Orientation)
|
||||
{
|
||||
if (isHorizontal)
|
||||
{
|
||||
// vertical resizers corresponding to dragged resizer
|
||||
if (r.StartCol >= resizer.StartCol && r.EndCol < resizer.EndCol)
|
||||
{
|
||||
if (r.StartRow == resizer.StartRow + 2 && isDeltaNegative)
|
||||
{
|
||||
r.StartRow--;
|
||||
}
|
||||
|
||||
if (r.EndRow == resizer.EndRow + 1 && isDeltaNegative)
|
||||
{
|
||||
r.EndRow--;
|
||||
}
|
||||
|
||||
if (r.StartRow == resizer.StartRow && !isDeltaNegative)
|
||||
{
|
||||
r.StartRow++;
|
||||
}
|
||||
|
||||
if (r.EndRow == resizer.EndRow - 1 && !isDeltaNegative)
|
||||
{
|
||||
r.EndRow++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// vertical resizers corresponding to swapped resizers
|
||||
foreach (GridResizer sr in swappedResizers)
|
||||
{
|
||||
if (r.StartCol >= sr.StartCol && r.EndCol <= sr.EndCol)
|
||||
{
|
||||
if (r.StartRow == resizer.StartRow + 1 && isDeltaNegative)
|
||||
{
|
||||
r.StartRow++;
|
||||
}
|
||||
|
||||
if (r.EndRow == resizer.EndRow && isDeltaNegative)
|
||||
{
|
||||
r.EndRow++;
|
||||
}
|
||||
|
||||
if (r.StartRow == resizer.StartRow + 1 && !isDeltaNegative)
|
||||
{
|
||||
r.StartRow--;
|
||||
}
|
||||
|
||||
if (r.EndRow == resizer.EndRow && !isDeltaNegative)
|
||||
{
|
||||
r.EndRow--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// horizontal resizers corresponding to dragged resizer
|
||||
if (r.StartRow >= resizer.StartRow && r.EndRow < resizer.EndRow)
|
||||
{
|
||||
if (r.StartCol == resizer.StartCol + 3 && isDeltaNegative)
|
||||
{
|
||||
r.StartCol--;
|
||||
}
|
||||
|
||||
if (r.EndCol == resizer.EndCol + 1 && isDeltaNegative)
|
||||
{
|
||||
r.EndCol--;
|
||||
}
|
||||
|
||||
if (r.StartCol == resizer.StartCol && !isDeltaNegative)
|
||||
{
|
||||
r.StartCol++;
|
||||
}
|
||||
|
||||
if (r.EndCol == resizer.EndCol - 1 && !isDeltaNegative)
|
||||
{
|
||||
r.EndCol++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// horizontal resizers corresponding to swapped resizers
|
||||
foreach (GridResizer sr in swappedResizers)
|
||||
{
|
||||
if (r.StartRow >= sr.StartRow && r.EndRow <= sr.EndRow)
|
||||
{
|
||||
if (r.StartCol == resizer.StartCol + 1 && isDeltaNegative)
|
||||
{
|
||||
r.StartCol++;
|
||||
}
|
||||
|
||||
if (r.EndCol == resizer.EndCol && isDeltaNegative)
|
||||
{
|
||||
r.EndCol++;
|
||||
}
|
||||
|
||||
if (r.StartCol == resizer.StartCol + 1 && !isDeltaNegative)
|
||||
{
|
||||
r.StartCol--;
|
||||
}
|
||||
|
||||
if (r.EndCol == resizer.EndCol && !isDeltaNegative)
|
||||
{
|
||||
r.EndCol--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateAfterDetach(GridResizer resizer, double delta)
|
||||
{
|
||||
bool isDeltaNegative = delta < 0;
|
||||
Orientation orientation = resizer.Orientation;
|
||||
|
||||
foreach (GridResizer r in _resizers)
|
||||
{
|
||||
bool notEqual = r.StartRow != resizer.StartRow || r.EndRow != resizer.EndRow || r.StartCol != resizer.StartCol || r.EndCol != resizer.EndCol;
|
||||
if (r.Orientation == orientation && notEqual)
|
||||
{
|
||||
if (orientation == Orientation.Horizontal)
|
||||
{
|
||||
if (r.StartRow > resizer.StartRow || (r.StartRow == resizer.StartRow && isDeltaNegative))
|
||||
{
|
||||
r.StartRow++;
|
||||
}
|
||||
|
||||
if (r.EndRow > resizer.EndRow || (r.EndRow == resizer.EndRow && isDeltaNegative))
|
||||
{
|
||||
r.EndRow++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r.StartCol > resizer.StartCol || (r.StartCol == resizer.StartCol && isDeltaNegative))
|
||||
{
|
||||
r.StartCol++;
|
||||
}
|
||||
|
||||
if (r.EndCol > resizer.EndCol || (r.EndCol == resizer.EndCol && isDeltaNegative))
|
||||
{
|
||||
r.EndCol++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDeltaNegative)
|
||||
{
|
||||
IncreaseResizerValues(resizer, orientation);
|
||||
}
|
||||
|
||||
foreach (GridResizer r in _resizers)
|
||||
{
|
||||
if (r.Orientation != orientation)
|
||||
{
|
||||
if (orientation == Orientation.Vertical)
|
||||
{
|
||||
if (isDeltaNegative)
|
||||
{
|
||||
bool isRowNonAdjacent = r.EndRow < resizer.StartRow || r.StartRow > resizer.EndRow;
|
||||
|
||||
if (r.StartCol > resizer.StartCol + 1 || (r.StartCol == resizer.StartCol + 1 && isRowNonAdjacent))
|
||||
{
|
||||
r.StartCol++;
|
||||
}
|
||||
|
||||
if (r.EndCol > resizer.EndCol || (r.EndCol == resizer.EndCol && isRowNonAdjacent))
|
||||
{
|
||||
r.EndCol++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r.StartCol > resizer.StartCol || (r.StartCol == resizer.StartCol && r.StartRow >= resizer.StartRow && r.EndRow <= resizer.EndRow))
|
||||
{
|
||||
r.StartCol++;
|
||||
}
|
||||
|
||||
if (r.EndCol > resizer.EndCol - 1 || (r.EndCol == resizer.EndCol - 1 && r.StartRow >= resizer.StartRow && r.EndRow <= resizer.EndRow))
|
||||
{
|
||||
r.EndCol++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDeltaNegative)
|
||||
{
|
||||
bool isColNonAdjacent = r.EndCol < resizer.StartCol || r.StartCol > resizer.EndCol;
|
||||
|
||||
if (r.StartRow > resizer.StartRow + 1 || (r.StartRow == resizer.StartRow + 1 && isColNonAdjacent))
|
||||
{
|
||||
r.StartRow++;
|
||||
}
|
||||
|
||||
if (r.EndRow > resizer.EndRow || (r.EndRow == resizer.EndRow && isColNonAdjacent))
|
||||
{
|
||||
r.EndRow++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r.StartRow > resizer.StartRow || (r.StartRow == resizer.StartRow && r.StartCol >= resizer.StartCol && r.EndCol <= resizer.EndCol))
|
||||
{
|
||||
r.StartRow++;
|
||||
}
|
||||
|
||||
if (r.EndRow > resizer.EndRow - 1 || (r.EndRow == resizer.EndRow - 1 && r.StartCol >= resizer.StartCol && r.EndCol <= resizer.EndCol))
|
||||
{
|
||||
r.EndRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveDragHandles()
|
||||
{
|
||||
_resizers.Clear();
|
||||
}
|
||||
|
||||
public bool HasSnappedNonAdjacentResizers(GridResizer resizer)
|
||||
{
|
||||
/**
|
||||
* Resizers between zones 0,1 and 4,5 are snapped to each other and not adjacent.
|
||||
* ------------------------------
|
||||
* | 0 | 1 |
|
||||
* ------------------------------
|
||||
* | 2 | 3 |
|
||||
* ------------------------------
|
||||
* | 4 | 5 |
|
||||
* ------------------------------
|
||||
*
|
||||
* Resizers between zones 0,1 and 2,3 are snapped to each other and adjacent.
|
||||
* ------------------------------
|
||||
* | 0 | 1 |
|
||||
* ------------------------------
|
||||
* | 2 | 3 |
|
||||
* ------------------------------
|
||||
* | 4 | 5 |
|
||||
* ------------------------------
|
||||
*
|
||||
* Vertical resizers should have same StartColumn and different StartRow.
|
||||
* Horizontal resizers should have same StartRow and different StartColumn.
|
||||
* Difference between rows or columns should be more than 1.
|
||||
*/
|
||||
foreach (GridResizer r in _resizers)
|
||||
{
|
||||
if (r.Orientation == resizer.Orientation)
|
||||
{
|
||||
bool isHorizontalSnapped = resizer.Orientation == Orientation.Horizontal && r.StartRow == resizer.StartRow && (Math.Abs(resizer.StartCol - r.StartCol) > 1);
|
||||
bool isVerticalSnapped = resizer.Orientation == Orientation.Vertical && r.StartCol == resizer.StartCol && (Math.Abs(resizer.StartRow - r.StartRow) > 1);
|
||||
if (isHorizontalSnapped || isVerticalSnapped)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void IncreaseResizerValues(GridResizer resizer, Orientation orientation)
|
||||
{
|
||||
if (orientation == Orientation.Vertical)
|
||||
{
|
||||
resizer.StartCol++;
|
||||
resizer.EndCol++;
|
||||
}
|
||||
else
|
||||
{
|
||||
resizer.StartRow++;
|
||||
resizer.EndRow++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecreaseResizerValues(GridResizer resizer, Orientation orientation)
|
||||
{
|
||||
if (orientation == Orientation.Vertical)
|
||||
{
|
||||
resizer.StartCol--;
|
||||
resizer.EndCol--;
|
||||
}
|
||||
else
|
||||
{
|
||||
resizer.StartRow--;
|
||||
resizer.EndRow--;
|
||||
}
|
||||
}
|
||||
|
||||
private bool UpdateDragHandlerForExistingSplit(Orientation orientation, Func<GridResizer, bool> cmpr, Func<GridResizer, bool> endCmpr, Func<GridResizer, bool> startCmpr)
|
||||
{
|
||||
bool updCurrentResizers = false;
|
||||
GridResizer leftNeighbour = null;
|
||||
GridResizer rightNeighbour = null;
|
||||
|
||||
for (int i = 0; i < _resizers.Count && (leftNeighbour == null || rightNeighbour == null); i++)
|
||||
{
|
||||
GridResizer resizer = (GridResizer)_resizers[i];
|
||||
if (cmpr(resizer))
|
||||
{
|
||||
if (leftNeighbour == null && endCmpr(resizer))
|
||||
{
|
||||
leftNeighbour = resizer;
|
||||
updCurrentResizers = true;
|
||||
}
|
||||
|
||||
if (rightNeighbour == null && startCmpr(resizer))
|
||||
{
|
||||
rightNeighbour = resizer;
|
||||
updCurrentResizers = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updCurrentResizers)
|
||||
{
|
||||
if (leftNeighbour != null && rightNeighbour != null)
|
||||
{
|
||||
if (orientation == Orientation.Vertical)
|
||||
{
|
||||
leftNeighbour.EndRow = rightNeighbour.EndRow;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftNeighbour.EndCol = rightNeighbour.EndCol;
|
||||
}
|
||||
|
||||
_resizers.Remove(rightNeighbour);
|
||||
}
|
||||
else if (leftNeighbour != null)
|
||||
{
|
||||
if (orientation == Orientation.Vertical)
|
||||
{
|
||||
leftNeighbour.EndRow++;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftNeighbour.EndCol++;
|
||||
}
|
||||
}
|
||||
else if (rightNeighbour != null)
|
||||
{
|
||||
if (orientation == Orientation.Vertical)
|
||||
{
|
||||
rightNeighbour.StartRow--;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightNeighbour.StartCol--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return updCurrentResizers;
|
||||
}
|
||||
|
||||
private readonly UIElementCollection _resizers;
|
||||
private readonly Action<object, DragDeltaEventArgs> _dragDelta;
|
||||
private readonly Action<object, DragCompletedEventArgs> _dragCompleted;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
@@ -20,6 +21,9 @@ namespace FancyZonesEditor
|
||||
private const string PropertyRowsChangedID = "Rows";
|
||||
private const string PropertyColumnsChangedID = "Columns";
|
||||
private const string ObjectDependencyID = "Model";
|
||||
private const string PropertyIsShiftKeyPressedID = "IsShiftKeyPressed";
|
||||
|
||||
private const int MinZoneSize = 100;
|
||||
|
||||
public static readonly DependencyProperty ModelProperty = DependencyProperty.Register(ObjectDependencyID, typeof(GridLayoutModel), typeof(GridEditor), new PropertyMetadata(null, OnGridDimensionsChanged));
|
||||
|
||||
@@ -27,13 +31,15 @@ namespace FancyZonesEditor
|
||||
|
||||
private int gridEditorUniqueId;
|
||||
|
||||
private GridData _data;
|
||||
|
||||
public GridEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += GridEditor_Loaded;
|
||||
Unloaded += GridEditor_Unloaded;
|
||||
((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
gridEditorUniqueId = ++gridEditorUniqueIdCounter;
|
||||
((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
}
|
||||
|
||||
private void GridEditor_Loaded(object sender, RoutedEventArgs e)
|
||||
@@ -45,21 +51,127 @@ namespace FancyZonesEditor
|
||||
}
|
||||
|
||||
_data = new GridData(model);
|
||||
_dragHandles = new GridDragHandles(AdornerLayer.Children, Resizer_DragDelta, Resizer_DragCompleted);
|
||||
_dragHandles.InitDragHandles(model);
|
||||
|
||||
Model = model;
|
||||
Model.PropertyChanged += OnGridDimensionsChanged;
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
int zoneCount = _data.ZoneCount;
|
||||
for (int i = 0; i < zoneCount; i++)
|
||||
private void PlaceResizer(GridResizer resizerThumb)
|
||||
{
|
||||
var leftZone = Preview.Children[resizerThumb.LeftReferenceZone];
|
||||
var rightZone = Preview.Children[resizerThumb.RightReferenceZone];
|
||||
var topZone = Preview.Children[resizerThumb.TopReferenceZone];
|
||||
var bottomZone = Preview.Children[resizerThumb.BottomReferenceZone];
|
||||
|
||||
double left = Canvas.GetLeft(leftZone);
|
||||
double right = Canvas.GetLeft(rightZone) + (rightZone as GridZone).MinWidth;
|
||||
|
||||
double top = Canvas.GetTop(topZone);
|
||||
double bottom = Canvas.GetTop(bottomZone) + (bottomZone as GridZone).MinHeight;
|
||||
|
||||
double x = (left + right) / 2.0;
|
||||
double y = (top + bottom) / 2.0;
|
||||
|
||||
Canvas.SetLeft(resizerThumb, x - 24);
|
||||
Canvas.SetTop(resizerThumb, y - 24);
|
||||
}
|
||||
|
||||
private void SetZonePanelSize(GridZone panel, GridData.Zone zone)
|
||||
{
|
||||
Size actualSize = WorkAreaSize();
|
||||
double spacing = Model.ShowSpacing ? Model.Spacing : 0;
|
||||
|
||||
double topSpacing = zone.Top == 0 ? spacing : spacing / 2;
|
||||
double bottomSpacing = zone.Bottom == GridData.Multiplier ? spacing : spacing / 2;
|
||||
double leftSpacing = zone.Left == 0 ? spacing : spacing / 2;
|
||||
double rightSpacing = zone.Right == GridData.Multiplier ? spacing : spacing / 2;
|
||||
|
||||
Canvas.SetTop(panel, (actualSize.Height * zone.Top / GridData.Multiplier) + topSpacing);
|
||||
Canvas.SetLeft(panel, (actualSize.Width * zone.Left / GridData.Multiplier) + leftSpacing);
|
||||
panel.MinWidth = Math.Max(1, (actualSize.Width * (zone.Right - zone.Left) / GridData.Multiplier) - leftSpacing - rightSpacing);
|
||||
panel.MinHeight = Math.Max(1, (actualSize.Height * (zone.Bottom - zone.Top) / GridData.Multiplier) - topSpacing - bottomSpacing);
|
||||
}
|
||||
|
||||
private void SetupUI()
|
||||
{
|
||||
Size actualSize = WorkAreaSize();
|
||||
|
||||
if (actualSize.Width < 1 || _data == null || Model == null)
|
||||
{
|
||||
AddZone();
|
||||
return;
|
||||
}
|
||||
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
ArrangeGridRects(actualSize);
|
||||
int spacing = Model.ShowSpacing ? Model.Spacing : 0;
|
||||
|
||||
_data.MinZoneWidth = Convert.ToInt32(GridData.Multiplier / actualSize.Width * (MinZoneSize + (2 * spacing)));
|
||||
_data.MinZoneHeight = Convert.ToInt32(GridData.Multiplier / actualSize.Height * (MinZoneSize + (2 * spacing)));
|
||||
|
||||
Preview.Children.Clear();
|
||||
AdornerLayer.Children.Clear();
|
||||
|
||||
Preview.Width = actualSize.Width;
|
||||
Preview.Height = actualSize.Height;
|
||||
|
||||
MagneticSnap snapX = new MagneticSnap(GridData.PrefixSum(Model.ColumnPercents).GetRange(1, Model.ColumnPercents.Count - 1), actualSize.Width);
|
||||
MagneticSnap snapY = new MagneticSnap(GridData.PrefixSum(Model.RowPercents).GetRange(1, Model.RowPercents.Count - 1), actualSize.Height);
|
||||
|
||||
for (int zoneIndex = 0; zoneIndex < _data.Zones.Count(); zoneIndex++)
|
||||
{
|
||||
// this is needed for the lambda
|
||||
int zoneIndexCopy = zoneIndex;
|
||||
|
||||
var zone = _data.Zones[zoneIndex];
|
||||
var zonePanel = new GridZone(spacing, snapX, snapY, (orientation, offset) => _data.CanSplit(zoneIndexCopy, offset, orientation), zone);
|
||||
zonePanel.UpdateShiftState(((App)Application.Current).MainWindowSettings.IsShiftKeyPressed);
|
||||
Preview.Children.Add(zonePanel);
|
||||
zonePanel.Split += OnSplit;
|
||||
zonePanel.MergeDrag += OnMergeDrag;
|
||||
zonePanel.MergeComplete += OnMergeComplete;
|
||||
SetZonePanelSize(zonePanel, zone);
|
||||
zonePanel.LabelID.Content = zoneIndex + 1;
|
||||
}
|
||||
|
||||
foreach (var resizer in _data.Resizers)
|
||||
{
|
||||
var resizerThumb = new GridResizer();
|
||||
resizerThumb.DragStarted += Resizer_DragStarted;
|
||||
resizerThumb.DragDelta += Resizer_DragDelta;
|
||||
resizerThumb.DragCompleted += Resizer_DragCompleted;
|
||||
resizerThumb.Orientation = resizer.Orientation;
|
||||
AdornerLayer.Children.Add(resizerThumb);
|
||||
|
||||
if (resizer.Orientation == Orientation.Horizontal)
|
||||
{
|
||||
resizerThumb.LeftReferenceZone = resizer.PositiveSideIndices[0];
|
||||
resizerThumb.RightReferenceZone = resizer.PositiveSideIndices.Last();
|
||||
resizerThumb.TopReferenceZone = resizer.PositiveSideIndices[0];
|
||||
resizerThumb.BottomReferenceZone = resizer.NegativeSideIndices[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
resizerThumb.LeftReferenceZone = resizer.PositiveSideIndices[0];
|
||||
resizerThumb.RightReferenceZone = resizer.NegativeSideIndices[0];
|
||||
resizerThumb.TopReferenceZone = resizer.PositiveSideIndices[0];
|
||||
resizerThumb.BottomReferenceZone = resizer.PositiveSideIndices.Last();
|
||||
}
|
||||
|
||||
PlaceResizer(resizerThumb);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSplit(object sender, SplitEventArgs args)
|
||||
{
|
||||
MergeCancelClick(null, null);
|
||||
|
||||
var zonePanel = sender as GridZone;
|
||||
int zoneIndex = Preview.Children.IndexOf(zonePanel);
|
||||
|
||||
if (_data.CanSplit(zoneIndex, args.Offset, args.Orientation))
|
||||
{
|
||||
_data.Split(zoneIndex, args.Offset, args.Orientation);
|
||||
SetupUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void GridEditor_Unloaded(object sender, RoutedEventArgs e)
|
||||
@@ -67,16 +179,10 @@ namespace FancyZonesEditor
|
||||
gridEditorUniqueId = -1;
|
||||
}
|
||||
|
||||
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
private Size WorkAreaSize()
|
||||
{
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
|
||||
// Only enter if this is the newest instance
|
||||
if (actualSize.Width > 0 && gridEditorUniqueId == gridEditorUniqueIdCounter)
|
||||
{
|
||||
ArrangeGridRects(actualSize);
|
||||
}
|
||||
return new Size(workingArea.Width, workingArea.Height);
|
||||
}
|
||||
|
||||
public GridLayoutModel Model
|
||||
@@ -90,258 +196,6 @@ namespace FancyZonesEditor
|
||||
get { return Preview; }
|
||||
}
|
||||
|
||||
private void OnFullSplit(object o, SplitEventArgs e)
|
||||
{
|
||||
UIElementCollection previewChildren = Preview.Children;
|
||||
UIElement splitee = (UIElement)o;
|
||||
|
||||
GridLayoutModel model = Model;
|
||||
int spliteeIndex = previewChildren.IndexOf(splitee);
|
||||
|
||||
int rows = model.Rows;
|
||||
int cols = model.Columns;
|
||||
_startRow = -1;
|
||||
_startCol = -1;
|
||||
|
||||
for (int row = rows - 1; row >= 0; row--)
|
||||
{
|
||||
for (int col = cols - 1; col >= 0; col--)
|
||||
{
|
||||
if (model.CellChildMap[row, col] == spliteeIndex)
|
||||
{
|
||||
_dragHandles.RemoveDragHandles();
|
||||
_startRow = _endRow = row;
|
||||
_startCol = _endCol = col;
|
||||
ExtendRangeToHaveEvenCellEdges();
|
||||
|
||||
for (row = _startRow; row <= _endRow; row++)
|
||||
{
|
||||
for (col = _startCol; col <= _endCol; col++)
|
||||
{
|
||||
if ((row != _startRow) || (col != _startCol))
|
||||
{
|
||||
model.CellChildMap[row, col] = AddZone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnGridDimensionsChanged();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtendRangeToHaveEvenCellEdges()
|
||||
{
|
||||
// As long as there is an edge of the 2D range such that some zone crosses its boundary, extend
|
||||
// that boundary. A single pass is not enough, a while loop is needed. This results in the unique
|
||||
// smallest rectangle containing the initial range such that no zone is "broken", meaning that
|
||||
// some part of it is inside the 2D range, and some part is outside.
|
||||
GridLayoutModel model = Model;
|
||||
bool possiblyBroken = true;
|
||||
|
||||
while (possiblyBroken)
|
||||
{
|
||||
possiblyBroken = false;
|
||||
|
||||
for (int col = _startCol; col <= _endCol; col++)
|
||||
{
|
||||
if (_startRow > 0 && model.CellChildMap[_startRow - 1, col] == model.CellChildMap[_startRow, col])
|
||||
{
|
||||
_startRow--;
|
||||
possiblyBroken = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_endRow < model.Rows - 1 && model.CellChildMap[_endRow + 1, col] == model.CellChildMap[_endRow, col])
|
||||
{
|
||||
_endRow++;
|
||||
possiblyBroken = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int row = _startRow; row <= _endRow; row++)
|
||||
{
|
||||
if (_startCol > 0 && model.CellChildMap[row, _startCol - 1] == model.CellChildMap[row, _startCol])
|
||||
{
|
||||
_startCol--;
|
||||
possiblyBroken = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_endCol < model.Columns - 1 && model.CellChildMap[row, _endCol + 1] == model.CellChildMap[row, _endCol])
|
||||
{
|
||||
_endCol++;
|
||||
possiblyBroken = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSplit(object o, SplitEventArgs e)
|
||||
{
|
||||
MergeCancelClick(null, null);
|
||||
|
||||
UIElementCollection previewChildren = Preview.Children;
|
||||
GridZone splitee = (GridZone)o;
|
||||
|
||||
int spliteeIndex = previewChildren.IndexOf(splitee);
|
||||
GridLayoutModel model = Model;
|
||||
|
||||
int rows = model.Rows;
|
||||
int cols = model.Columns;
|
||||
|
||||
Tuple<int, int> rowCol = _data.RowColByIndex(spliteeIndex);
|
||||
int foundRow = rowCol.Item1;
|
||||
int foundCol = rowCol.Item2;
|
||||
|
||||
int newChildIndex = AddZone();
|
||||
|
||||
double offset = e.Offset;
|
||||
double space = e.Space;
|
||||
|
||||
if (e.Orientation == Orientation.Vertical)
|
||||
{
|
||||
if (splitee.VerticalSnapPoints != null)
|
||||
{
|
||||
offset += Canvas.GetLeft(splitee);
|
||||
int count = splitee.VerticalSnapPoints.Length;
|
||||
bool foundExistingSplit = false;
|
||||
int splitCol = foundCol;
|
||||
|
||||
for (int i = 0; i <= count; i++)
|
||||
{
|
||||
if (foundExistingSplit)
|
||||
{
|
||||
int walkRow = foundRow;
|
||||
while ((walkRow < rows) && (_data.GetIndex(walkRow, foundCol + i) == spliteeIndex))
|
||||
{
|
||||
_data.SetIndex(walkRow++, foundCol + i, newChildIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (_data.ColumnBottom(foundCol + i) == offset)
|
||||
{
|
||||
foundExistingSplit = true;
|
||||
splitCol = foundCol + i;
|
||||
|
||||
// use existing division
|
||||
}
|
||||
}
|
||||
|
||||
if (foundExistingSplit)
|
||||
{
|
||||
_data.ReplaceIndicesToMaintainOrder(Preview.Children.Count);
|
||||
_dragHandles.UpdateForExistingVerticalSplit(model, foundRow, splitCol);
|
||||
OnGridDimensionsChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
while (_data.ColumnBottom(foundCol) < offset)
|
||||
{
|
||||
foundCol++;
|
||||
}
|
||||
|
||||
offset -= _data.ColumnTop(foundCol);
|
||||
}
|
||||
|
||||
_dragHandles.UpdateAfterVerticalSplit(foundCol);
|
||||
_data.SplitColumn(foundCol, spliteeIndex, newChildIndex, space, offset, App.Overlay.WorkArea.Width);
|
||||
_dragHandles.AddDragHandle(Orientation.Vertical, foundRow, foundCol, model);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Horizontal
|
||||
if (splitee.HorizontalSnapPoints != null)
|
||||
{
|
||||
offset += Canvas.GetTop(splitee);
|
||||
int count = splitee.HorizontalSnapPoints.Length;
|
||||
bool foundExistingSplit = false;
|
||||
int splitRow = foundRow;
|
||||
|
||||
for (int i = 0; i <= count; i++)
|
||||
{
|
||||
if (foundExistingSplit)
|
||||
{
|
||||
int walkCol = foundCol;
|
||||
while ((walkCol < cols) && (_data.GetIndex(foundRow + i, walkCol) == spliteeIndex))
|
||||
{
|
||||
_data.SetIndex(foundRow + i, walkCol++, newChildIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (_data.RowEnd(foundRow + i) == offset)
|
||||
{
|
||||
foundExistingSplit = true;
|
||||
splitRow = foundRow + i;
|
||||
|
||||
// use existing division
|
||||
}
|
||||
}
|
||||
|
||||
if (foundExistingSplit)
|
||||
{
|
||||
_data.ReplaceIndicesToMaintainOrder(Preview.Children.Count);
|
||||
_dragHandles.UpdateForExistingHorizontalSplit(model, splitRow, foundCol);
|
||||
OnGridDimensionsChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
while (_data.RowEnd(foundRow) < offset)
|
||||
{
|
||||
foundRow++;
|
||||
}
|
||||
|
||||
offset -= _data.RowStart(foundRow);
|
||||
}
|
||||
|
||||
_dragHandles.UpdateAfterHorizontalSplit(foundRow);
|
||||
_data.SplitRow(foundRow, spliteeIndex, newChildIndex, space, offset, App.Overlay.WorkArea.Height);
|
||||
_dragHandles.AddDragHandle(Orientation.Horizontal, foundRow, foundCol, model);
|
||||
}
|
||||
|
||||
var workArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workArea.Width, workArea.Height);
|
||||
ArrangeGridRects(actualSize);
|
||||
}
|
||||
|
||||
private void DeleteZone(int index)
|
||||
{
|
||||
Preview.Children.RemoveAt(index);
|
||||
}
|
||||
|
||||
private int AddZone()
|
||||
{
|
||||
GridZone zone;
|
||||
if (Model != null)
|
||||
{
|
||||
IList<int> freeZones = Model.FreeZones;
|
||||
|
||||
// first check free list
|
||||
if (freeZones.Count > 0)
|
||||
{
|
||||
int freeIndex = freeZones[0];
|
||||
freeZones.RemoveAt(0);
|
||||
zone = (GridZone)Preview.Children[freeIndex];
|
||||
zone.Visibility = Visibility.Visible;
|
||||
return freeIndex;
|
||||
}
|
||||
|
||||
zone = new GridZone(Model.ShowSpacing ? Model.Spacing : 0);
|
||||
zone.Split += OnSplit;
|
||||
zone.MergeDrag += OnMergeDrag;
|
||||
zone.MergeComplete += OnMergeComplete;
|
||||
zone.FullSplit += OnFullSplit;
|
||||
Preview.Children.Add(zone);
|
||||
return Preview.Children.Count - 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void OnGridDimensionsChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
// Only enter if this is the newest instance
|
||||
@@ -351,230 +205,201 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if ((e.PropertyName == PropertyIsShiftKeyPressedID) && gridEditorUniqueId == gridEditorUniqueIdCounter)
|
||||
{
|
||||
foreach (var child in Preview.Children)
|
||||
{
|
||||
var zone = child as GridZone;
|
||||
zone.UpdateShiftState(((App)Application.Current).MainWindowSettings.IsShiftKeyPressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnGridDimensionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((GridEditor)d).OnGridDimensionsChanged();
|
||||
((GridEditor)d).SetupUI();
|
||||
}
|
||||
|
||||
private void OnGridDimensionsChanged()
|
||||
{
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
if (actualSize.Width > 0)
|
||||
{
|
||||
ArrangeGridRects(actualSize);
|
||||
}
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
private void ArrangeGridRects(Size arrangeSize)
|
||||
private double _dragX = 0;
|
||||
private double _dragY = 0;
|
||||
|
||||
private void Resizer_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
||||
{
|
||||
var workArea = App.Overlay.WorkArea;
|
||||
Preview.Width = workArea.Width;
|
||||
Preview.Height = workArea.Height;
|
||||
|
||||
GridLayoutModel model = Model;
|
||||
if (model == null || _data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (model.Rows != model.RowPercents.Count || model.Columns != model.ColumnPercents.Count)
|
||||
{
|
||||
// Merge was not finished
|
||||
return;
|
||||
}
|
||||
|
||||
int spacing = model.ShowSpacing ? model.Spacing : 0;
|
||||
|
||||
_data.RecalculateZones(spacing, arrangeSize);
|
||||
_data.ArrangeZones(Preview.Children, spacing);
|
||||
_dragHandles.InitDragHandles(model);
|
||||
_data.ArrangeResizers(AdornerLayer.Children, spacing);
|
||||
_dragX = 0;
|
||||
_dragY = 0;
|
||||
}
|
||||
|
||||
private void Resizer_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
|
||||
{
|
||||
MergeCancelClick(null, null);
|
||||
|
||||
GridResizer resizer = (GridResizer)sender;
|
||||
_dragX += e.HorizontalChange;
|
||||
_dragY += e.VerticalChange;
|
||||
|
||||
double delta = (resizer.Orientation == Orientation.Vertical) ? e.HorizontalChange : e.VerticalChange;
|
||||
if (delta == 0)
|
||||
GridResizer resizer = (GridResizer)sender;
|
||||
int resizerIndex = AdornerLayer.Children.IndexOf(resizer);
|
||||
|
||||
Size actualSize = WorkAreaSize();
|
||||
|
||||
int delta;
|
||||
|
||||
if (resizer.Orientation == Orientation.Vertical)
|
||||
{
|
||||
return;
|
||||
delta = Convert.ToInt32(_dragX / actualSize.Width * GridData.Multiplier);
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = Convert.ToInt32(_dragY / actualSize.Height * GridData.Multiplier);
|
||||
}
|
||||
|
||||
GridData.ResizeInfo resizeInfo = _data.CalculateResizeInfo(resizer, delta);
|
||||
if (resizeInfo.IsResizeAllowed)
|
||||
if (_data.CanDrag(resizerIndex, delta))
|
||||
{
|
||||
if (_dragHandles.HasSnappedNonAdjacentResizers(resizer))
|
||||
// Just update the UI, don't tell _data
|
||||
if (resizer.Orientation == Orientation.Vertical)
|
||||
{
|
||||
double spacing = 0;
|
||||
GridLayoutModel model = Model;
|
||||
if (model.ShowSpacing)
|
||||
_data.Resizers[resizerIndex].PositiveSideIndices.ForEach((zoneIndex) =>
|
||||
{
|
||||
spacing = model.Spacing;
|
||||
}
|
||||
var zone = Preview.Children[zoneIndex];
|
||||
Canvas.SetLeft(zone, Canvas.GetLeft(zone) + e.HorizontalChange);
|
||||
(zone as GridZone).MinWidth -= e.HorizontalChange;
|
||||
});
|
||||
|
||||
_data.SplitOnDrag(resizer, delta, spacing);
|
||||
_dragHandles.UpdateAfterDetach(resizer, delta);
|
||||
_data.Resizers[resizerIndex].NegativeSideIndices.ForEach((zoneIndex) =>
|
||||
{
|
||||
var zone = Preview.Children[zoneIndex];
|
||||
Canvas.SetRight(zone, Canvas.GetRight(zone) + e.HorizontalChange);
|
||||
(zone as GridZone).MinWidth += e.HorizontalChange;
|
||||
});
|
||||
|
||||
Canvas.SetLeft(resizer, Canvas.GetLeft(resizer) + e.HorizontalChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
_data.DragResizer(resizer, resizeInfo);
|
||||
if (_data.SwapNegativePercents(resizer.Orientation, resizer.StartRow, resizer.EndRow, resizer.StartCol, resizer.EndCol))
|
||||
_data.Resizers[resizerIndex].PositiveSideIndices.ForEach((zoneIndex) =>
|
||||
{
|
||||
_dragHandles.UpdateAfterSwap(resizer, delta);
|
||||
var zone = Preview.Children[zoneIndex];
|
||||
Canvas.SetTop(zone, Canvas.GetTop(zone) + e.VerticalChange);
|
||||
(zone as GridZone).MinHeight -= e.VerticalChange;
|
||||
});
|
||||
|
||||
_data.Resizers[resizerIndex].NegativeSideIndices.ForEach((zoneIndex) =>
|
||||
{
|
||||
var zone = Preview.Children[zoneIndex];
|
||||
Canvas.SetBottom(zone, Canvas.GetBottom(zone) + e.VerticalChange);
|
||||
(zone as GridZone).MinHeight += e.VerticalChange;
|
||||
});
|
||||
|
||||
Canvas.SetTop(resizer, Canvas.GetTop(resizer) + e.VerticalChange);
|
||||
}
|
||||
|
||||
foreach (var child in AdornerLayer.Children)
|
||||
{
|
||||
GridResizer resizerThumb = child as GridResizer;
|
||||
if (resizerThumb != resizer)
|
||||
{
|
||||
PlaceResizer(resizerThumb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
ArrangeGridRects(actualSize);
|
||||
AdornerLayer.UpdateLayout();
|
||||
else
|
||||
{
|
||||
// Undo changes
|
||||
_dragX -= e.HorizontalChange;
|
||||
_dragY -= e.VerticalChange;
|
||||
}
|
||||
}
|
||||
|
||||
private void Resizer_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
|
||||
{
|
||||
GridResizer resizer = (GridResizer)sender;
|
||||
int index = _data.SwappedIndexAfterResize(resizer);
|
||||
if (index != -1)
|
||||
{
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
ArrangeGridRects(actualSize);
|
||||
}
|
||||
}
|
||||
int resizerIndex = AdornerLayer.Children.IndexOf(resizer);
|
||||
Size actualSize = WorkAreaSize();
|
||||
|
||||
private Point _startDragPos = new Point(-1, -1);
|
||||
double pixelDelta = resizer.Orientation == Orientation.Vertical ?
|
||||
_dragX / actualSize.Width * GridData.Multiplier :
|
||||
_dragY / actualSize.Height * GridData.Multiplier;
|
||||
|
||||
_data.Drag(resizerIndex, Convert.ToInt32(pixelDelta));
|
||||
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
private void OnMergeComplete(object o, MouseButtonEventArgs e)
|
||||
{
|
||||
Point mousePoint = e.GetPosition(Preview);
|
||||
_startDragPos = new Point(-1, -1);
|
||||
_inMergeDrag = false;
|
||||
|
||||
int mergedIndex = Model.CellChildMap[_startRow, _startCol];
|
||||
|
||||
for (int row = _startRow; row <= _endRow; row++)
|
||||
var selectedIndices = new List<int>();
|
||||
for (int zoneIndex = 0; zoneIndex < _data.Zones.Count; zoneIndex++)
|
||||
{
|
||||
for (int col = _startCol; col <= _endCol; col++)
|
||||
if ((Preview.Children[zoneIndex] as GridZone).IsSelected)
|
||||
{
|
||||
if (Model.CellChildMap[row, col] != mergedIndex)
|
||||
{
|
||||
// selection is more than one cell, merge is valid
|
||||
MergePanel.Visibility = Visibility.Visible;
|
||||
Canvas.SetTop(MergeButtons, mousePoint.Y);
|
||||
Canvas.SetLeft(MergeButtons, mousePoint.X);
|
||||
return;
|
||||
}
|
||||
selectedIndices.Add(zoneIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// merge is only one zone. cancel merge;
|
||||
ClearSelection();
|
||||
if (selectedIndices.Count <= 1)
|
||||
{
|
||||
ClearSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
Point mousePoint = e.GetPosition(Preview);
|
||||
MergePanel.Visibility = Visibility.Visible;
|
||||
Canvas.SetLeft(MergeButtons, mousePoint.X);
|
||||
Canvas.SetTop(MergeButtons, mousePoint.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _inMergeDrag;
|
||||
private Point _mergeDragStart;
|
||||
|
||||
private void OnMergeDrag(object o, MouseEventArgs e)
|
||||
{
|
||||
if (_startDragPos.X == -1)
|
||||
Point dragPosition = e.GetPosition(Preview);
|
||||
Size actualSize = WorkAreaSize();
|
||||
|
||||
if (!_inMergeDrag)
|
||||
{
|
||||
_startDragPos = e.GetPosition(Preview);
|
||||
_inMergeDrag = true;
|
||||
_mergeDragStart = dragPosition;
|
||||
}
|
||||
|
||||
GridLayoutModel model = Model;
|
||||
// Find the new zone, if any
|
||||
int dataLowX = Convert.ToInt32(Math.Min(_mergeDragStart.X, dragPosition.X) / actualSize.Width * GridData.Multiplier);
|
||||
int dataHighX = Convert.ToInt32(Math.Max(_mergeDragStart.X, dragPosition.X) / actualSize.Width * GridData.Multiplier);
|
||||
int dataLowY = Convert.ToInt32(Math.Min(_mergeDragStart.Y, dragPosition.Y) / actualSize.Height * GridData.Multiplier);
|
||||
int dataHighY = Convert.ToInt32(Math.Max(_mergeDragStart.Y, dragPosition.Y) / actualSize.Height * GridData.Multiplier);
|
||||
|
||||
if (_startDragPos.X != -1)
|
||||
var selectedIndices = new List<int>();
|
||||
|
||||
for (int zoneIndex = 0; zoneIndex < _data.Zones.Count(); zoneIndex++)
|
||||
{
|
||||
Point dragPos = e.GetPosition(Preview);
|
||||
_startRow = -1;
|
||||
_endRow = -1;
|
||||
_startCol = -1;
|
||||
_endCol = -1;
|
||||
var zoneData = _data.Zones[zoneIndex];
|
||||
|
||||
int rows = model.Rows;
|
||||
int cols = model.Columns;
|
||||
bool selected = Math.Max(zoneData.Left, dataLowX) <= Math.Min(zoneData.Right, dataHighX) &&
|
||||
Math.Max(zoneData.Top, dataLowY) <= Math.Min(zoneData.Bottom, dataHighY);
|
||||
|
||||
double minX, maxX;
|
||||
if (dragPos.X < _startDragPos.X)
|
||||
// Check whether the zone intersects the selected rectangle
|
||||
(Preview.Children[zoneIndex] as GridZone).IsSelected = selected;
|
||||
|
||||
if (selected)
|
||||
{
|
||||
minX = dragPos.X;
|
||||
maxX = _startDragPos.X;
|
||||
selectedIndices.Add(zoneIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
minX = _startDragPos.X;
|
||||
maxX = dragPos.X;
|
||||
}
|
||||
|
||||
double minY, maxY;
|
||||
if (dragPos.Y < _startDragPos.Y)
|
||||
{
|
||||
minY = dragPos.Y;
|
||||
maxY = _startDragPos.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
minY = _startDragPos.Y;
|
||||
maxY = dragPos.Y;
|
||||
}
|
||||
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
if (_startRow == -1)
|
||||
{
|
||||
if (_data.RowEnd(row) > minY)
|
||||
{
|
||||
_startRow = row;
|
||||
}
|
||||
}
|
||||
else if (_data.RowStart(row) > maxY)
|
||||
{
|
||||
_endRow = row - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_startRow >= 0) && (_endRow == -1))
|
||||
{
|
||||
_endRow = rows - 1;
|
||||
}
|
||||
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
if (_startCol == -1)
|
||||
{
|
||||
if (_data.ColumnBottom(col) > minX)
|
||||
{
|
||||
_startCol = col;
|
||||
}
|
||||
}
|
||||
else if (_data.ColumnTop(col) > maxX)
|
||||
{
|
||||
_endCol = col - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_startCol >= 0) && (_endCol == -1))
|
||||
{
|
||||
_endCol = cols - 1;
|
||||
}
|
||||
|
||||
ExtendRangeToHaveEvenCellEdges();
|
||||
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
((GridZone)Preview.Children[model.CellChildMap[row, col]]).IsSelected = (row >= _startRow) && (row <= _endRow) && (col >= _startCol) && (col <= _endCol);
|
||||
}
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
OnPreviewMouseMove(e);
|
||||
// Compute the closure
|
||||
_data.MergeClosureIndices(selectedIndices).ForEach((zoneIndex) =>
|
||||
{
|
||||
(Preview.Children[zoneIndex] as GridZone).IsSelected = true;
|
||||
});
|
||||
}
|
||||
|
||||
private void ClearSelection()
|
||||
@@ -583,22 +408,27 @@ namespace FancyZonesEditor
|
||||
{
|
||||
((GridZone)zone).IsSelected = false;
|
||||
}
|
||||
|
||||
_inMergeDrag = false;
|
||||
}
|
||||
|
||||
private void MergeClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MergePanel.Visibility = Visibility.Collapsed;
|
||||
|
||||
Action<int> deleteAction = (index) =>
|
||||
{
|
||||
DeleteZone(index);
|
||||
};
|
||||
_data.MergeZones(_startRow, _endRow, _startCol, _endCol, deleteAction, Preview.Children.Count);
|
||||
_dragHandles.RemoveDragHandles();
|
||||
_dragHandles.InitDragHandles(Model);
|
||||
var selectedIndices = new List<int>();
|
||||
|
||||
for (int zoneIndex = 0; zoneIndex < _data.Zones.Count(); zoneIndex++)
|
||||
{
|
||||
if ((Preview.Children[zoneIndex] as GridZone).IsSelected)
|
||||
{
|
||||
selectedIndices.Add(zoneIndex);
|
||||
}
|
||||
}
|
||||
|
||||
OnGridDimensionsChanged();
|
||||
ClearSelection();
|
||||
_data.DoMerge(selectedIndices);
|
||||
SetupUI();
|
||||
}
|
||||
|
||||
private void MergeCancelClick(object sender, RoutedEventArgs e)
|
||||
@@ -615,17 +445,9 @@ namespace FancyZonesEditor
|
||||
protected override Size ArrangeOverride(Size arrangeBounds)
|
||||
{
|
||||
Size returnSize = base.ArrangeOverride(arrangeBounds);
|
||||
ArrangeGridRects(arrangeBounds);
|
||||
SetupUI();
|
||||
|
||||
return returnSize;
|
||||
}
|
||||
|
||||
private GridData _data;
|
||||
private GridDragHandles _dragHandles;
|
||||
|
||||
private int _startRow = -1;
|
||||
private int _endRow = -1;
|
||||
private int _startCol = -1;
|
||||
private int _endCol = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,23 @@
|
||||
Margin="0,4,0,0" />
|
||||
</Grid>
|
||||
<StackPanel Margin="16">
|
||||
<TextBlock Text="{x:Static props:Resources.Note_Custom_Table}"
|
||||
Foreground="{DynamicResource SecondaryForegroundBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Margin="0,8,0,0"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<StackPanel Margin="0,8,0,0">
|
||||
<TextBlock
|
||||
TextWrapping="Wrap">
|
||||
<Run
|
||||
FontWeight="Bold"
|
||||
Text="{x:Static props:Resources.SplitterName}" />
|
||||
<Run Text="{x:Static props:Resources.SplitterDescription}" />
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Margin="0,8,0,0"
|
||||
TextWrapping="Wrap">
|
||||
<Run
|
||||
FontWeight="Bold"
|
||||
Text="{x:Static props:Resources.MergeName}" />
|
||||
<Run Text="{x:Static props:Resources.MergeDescription}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<Grid Margin="0,24,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace FancyZonesEditor
|
||||
{
|
||||
private static readonly RotateTransform _rotateTransform = new RotateTransform(90, 24, 24);
|
||||
|
||||
public int StartRow { get; set; }
|
||||
public int LeftReferenceZone { get; set; }
|
||||
|
||||
public int EndRow { get; set; }
|
||||
public int RightReferenceZone { get; set; }
|
||||
|
||||
public int StartCol { get; set; }
|
||||
public int TopReferenceZone { get; set; }
|
||||
|
||||
public int EndCol { get; set; }
|
||||
public int BottomReferenceZone { get; set; }
|
||||
|
||||
public LayoutModel Model { get; set; }
|
||||
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
Background="{DynamicResource GridZoneBackgroundBrush}"
|
||||
BorderBrush="{DynamicResource LayoutPreviewZoneBorderBrush}"
|
||||
BorderBrush="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||
BorderThickness="1"
|
||||
Opacity="1"
|
||||
ui:ControlHelper.CornerRadius="4"
|
||||
Effect="{StaticResource ZoneDropShadow}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid x:Name="Frame">
|
||||
|
||||
@@ -20,28 +20,29 @@ namespace FancyZonesEditor
|
||||
// Non-localizable strings
|
||||
private const string ObjectDependencyID = "IsSelected";
|
||||
private const string GridZoneBackgroundBrushID = "GridZoneBackgroundBrush";
|
||||
private const string PropertyIsShiftKeyPressedID = "IsShiftKeyPressed";
|
||||
private const string SecondaryForegroundBrushID = "SecondaryForegroundBrush";
|
||||
private const string AccentColorBrushID = "SystemControlBackgroundAccentBrush";
|
||||
|
||||
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(ObjectDependencyID, typeof(bool), typeof(GridZone), new PropertyMetadata(false, OnSelectionChanged));
|
||||
|
||||
public event SplitEventHandler Split;
|
||||
|
||||
public event SplitEventHandler FullSplit;
|
||||
|
||||
public event MouseEventHandler MergeDrag;
|
||||
|
||||
public event MouseButtonEventHandler MergeComplete;
|
||||
|
||||
public double[] VerticalSnapPoints { get; set; }
|
||||
|
||||
public double[] HorizontalSnapPoints { get; set; }
|
||||
|
||||
private readonly Rectangle _splitter;
|
||||
private bool _switchOrientation;
|
||||
private bool _switchOrientation = false;
|
||||
private Point _lastPos = new Point(-1, -1);
|
||||
private int _snappedPositionX;
|
||||
private int _snappedPositionY;
|
||||
private Point _mouseDownPos = new Point(-1, -1);
|
||||
private bool _inMergeDrag;
|
||||
private Orientation _splitOrientation;
|
||||
private MagneticSnap _snapX;
|
||||
private MagneticSnap _snapY;
|
||||
private Func<Orientation, int, bool> _canSplit;
|
||||
private bool _hovering;
|
||||
private GridData.Zone _zone;
|
||||
|
||||
private static void OnSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
@@ -50,7 +51,7 @@ namespace FancyZonesEditor
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
Background = IsSelected ? SystemParameters.WindowGlassBrush : App.Current.Resources[GridZoneBackgroundBrushID] as SolidColorBrush;
|
||||
Background = IsSelected ? Application.Current.Resources[AccentColorBrushID] as SolidColorBrush : Application.Current.Resources[GridZoneBackgroundBrushID] as SolidColorBrush;
|
||||
}
|
||||
|
||||
public bool IsSelected
|
||||
@@ -59,21 +60,24 @@ namespace FancyZonesEditor
|
||||
set { SetValue(IsSelectedProperty, value); }
|
||||
}
|
||||
|
||||
public GridZone(int spacing)
|
||||
public GridZone(int spacing, MagneticSnap snapX, MagneticSnap snapY, Func<Orientation, int, bool> canSplit, GridData.Zone zone)
|
||||
{
|
||||
InitializeComponent();
|
||||
OnSelectionChanged();
|
||||
_splitter = new Rectangle
|
||||
{
|
||||
Fill = SystemParameters.WindowGlassBrush,
|
||||
Fill = Application.Current.Resources[AccentColorBrushID] as SolidColorBrush,
|
||||
};
|
||||
Body.Children.Add(_splitter);
|
||||
|
||||
Spacing = spacing;
|
||||
SplitterThickness = Math.Max(spacing, 1);
|
||||
|
||||
((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
SizeChanged += GridZone_SizeChanged;
|
||||
|
||||
_snapX = snapX;
|
||||
_snapY = snapY;
|
||||
_canSplit = canSplit;
|
||||
_zone = zone;
|
||||
}
|
||||
|
||||
private void GridZone_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
@@ -82,91 +86,76 @@ namespace FancyZonesEditor
|
||||
HeightLabel.Text = Math.Round(ActualHeight).ToString();
|
||||
}
|
||||
|
||||
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
public void UpdateShiftState(bool shiftState)
|
||||
{
|
||||
if (e.PropertyName == PropertyIsShiftKeyPressedID)
|
||||
{
|
||||
_switchOrientation = ((App)Application.Current).MainWindowSettings.IsShiftKeyPressed;
|
||||
if (_lastPos.X != -1)
|
||||
{
|
||||
UpdateSplitter();
|
||||
}
|
||||
}
|
||||
}
|
||||
_switchOrientation = shiftState;
|
||||
|
||||
protected override Size ArrangeOverride(Size size)
|
||||
{
|
||||
_splitOrientation = (size.Width > size.Height) ? Orientation.Vertical : Orientation.Horizontal;
|
||||
return base.ArrangeOverride(size);
|
||||
if (_lastPos.X != -1)
|
||||
{
|
||||
UpdateSplitter();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsVerticalSplit
|
||||
{
|
||||
get
|
||||
{
|
||||
bool isVertical = _splitOrientation == Orientation.Vertical;
|
||||
if (_switchOrientation)
|
||||
{
|
||||
isVertical = !isVertical;
|
||||
}
|
||||
|
||||
return isVertical;
|
||||
}
|
||||
get => (ActualWidth > ActualHeight) ^ _switchOrientation;
|
||||
}
|
||||
|
||||
private int Spacing { get; set; }
|
||||
|
||||
private int SplitterThickness { get; set; }
|
||||
|
||||
private void UpdateSplitter()
|
||||
{
|
||||
if (!_hovering)
|
||||
{
|
||||
_splitter.Fill = Brushes.Transparent;
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled;
|
||||
|
||||
if (IsVerticalSplit)
|
||||
{
|
||||
double bodyWidth = Body.ActualWidth;
|
||||
double pos = _lastPos.X - (SplitterThickness / 2);
|
||||
if (pos < 0)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
else if (pos > (bodyWidth - SplitterThickness))
|
||||
{
|
||||
pos = bodyWidth - SplitterThickness;
|
||||
}
|
||||
double pos = _snapX.DataToPixelWithoutSnapping(_snappedPositionX) - Canvas.GetLeft(this) - (SplitterThickness / 2);
|
||||
pos = Math.Clamp(pos, 0, bodyWidth - SplitterThickness);
|
||||
|
||||
Canvas.SetLeft(_splitter, pos);
|
||||
Canvas.SetTop(_splitter, 0);
|
||||
_splitter.MinWidth = SplitterThickness;
|
||||
_splitter.MinHeight = Body.ActualHeight;
|
||||
|
||||
enabled = _canSplit(Orientation.Vertical, _snappedPositionX);
|
||||
}
|
||||
else
|
||||
{
|
||||
double bodyHeight = Body.ActualHeight;
|
||||
double pos = _lastPos.Y - (SplitterThickness / 2);
|
||||
if (pos < 0)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
else if (pos > (bodyHeight - SplitterThickness))
|
||||
{
|
||||
pos = bodyHeight - SplitterThickness;
|
||||
}
|
||||
double pos = _snapY.DataToPixelWithoutSnapping(_snappedPositionY) - Canvas.GetTop(this) - (SplitterThickness / 2);
|
||||
pos = Math.Clamp(pos, 0, bodyHeight - SplitterThickness);
|
||||
|
||||
Canvas.SetLeft(_splitter, 0);
|
||||
Canvas.SetTop(_splitter, pos);
|
||||
_splitter.MinWidth = Body.ActualWidth;
|
||||
_splitter.MinHeight = SplitterThickness;
|
||||
|
||||
enabled = _canSplit(Orientation.Horizontal, _snappedPositionY);
|
||||
}
|
||||
|
||||
Brush disabledBrush = Application.Current.Resources[SecondaryForegroundBrushID] as SolidColorBrush;
|
||||
Brush enabledBrush = Application.Current.Resources[AccentColorBrushID] as SolidColorBrush;
|
||||
_splitter.Fill = enabled ? enabledBrush : disabledBrush;
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
{
|
||||
_splitter.Fill = SystemParameters.WindowGlassBrush; // Active Accent color
|
||||
base.OnMouseEnter(e);
|
||||
_hovering = true;
|
||||
UpdateSplitter();
|
||||
_splitter.Fill = Application.Current.Resources[AccentColorBrushID] as SolidColorBrush;
|
||||
}
|
||||
|
||||
protected override void OnMouseLeave(MouseEventArgs e)
|
||||
{
|
||||
_splitter.Fill = Brushes.Transparent;
|
||||
_hovering = false;
|
||||
UpdateSplitter();
|
||||
base.OnMouseLeave(e);
|
||||
}
|
||||
|
||||
@@ -185,38 +174,8 @@ namespace FancyZonesEditor
|
||||
else
|
||||
{
|
||||
_lastPos = e.GetPosition(Body);
|
||||
|
||||
if (IsVerticalSplit)
|
||||
{
|
||||
if (VerticalSnapPoints != null)
|
||||
{
|
||||
int thickness = SplitterThickness;
|
||||
foreach (double snapPoint in VerticalSnapPoints)
|
||||
{
|
||||
if (Math.Abs(_lastPos.X - snapPoint) <= (thickness * 2))
|
||||
{
|
||||
_lastPos.X = snapPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// horizontal split
|
||||
if (HorizontalSnapPoints != null)
|
||||
{
|
||||
int thickness = SplitterThickness;
|
||||
foreach (double snapPoint in HorizontalSnapPoints)
|
||||
{
|
||||
if (Math.Abs(_lastPos.Y - snapPoint) <= (thickness * 2))
|
||||
{
|
||||
_lastPos.Y = snapPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_snappedPositionX = _snapX.PixelToDataWithSnapping(e.GetPosition(Parent as GridEditor).X, _zone.Left, _zone.Right);
|
||||
_snappedPositionY = _snapY.PixelToDataWithSnapping(e.GetPosition(Parent as GridEditor).Y, _zone.Top, _zone.Bottom);
|
||||
|
||||
if (_mouseDownPos.X == -1)
|
||||
{
|
||||
@@ -257,11 +216,11 @@ namespace FancyZonesEditor
|
||||
{
|
||||
if (IsVerticalSplit)
|
||||
{
|
||||
DoSplit(Orientation.Vertical, _lastPos.X - (thickness / 2));
|
||||
DoSplit(Orientation.Vertical, _snappedPositionX);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoSplit(Orientation.Horizontal, _lastPos.Y - (thickness / 2));
|
||||
DoSplit(Orientation.Horizontal, _snappedPositionY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,19 +239,9 @@ namespace FancyZonesEditor
|
||||
MergeComplete?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void DoSplit(Orientation orientation, double offset)
|
||||
private void DoSplit(Orientation orientation, int offset)
|
||||
{
|
||||
Split?.Invoke(this, new SplitEventArgs(orientation, offset, Spacing));
|
||||
}
|
||||
|
||||
private void FullSplit_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DoFullSplit();
|
||||
}
|
||||
|
||||
private void DoFullSplit()
|
||||
{
|
||||
FullSplit?.Invoke(this, new SplitEventArgs());
|
||||
Split?.Invoke(this, new SplitEventArgs(orientation, offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
@@ -27,7 +26,6 @@ namespace FancyZonesEditor
|
||||
|
||||
public static readonly DependencyProperty IsActualSizeProperty = DependencyProperty.Register(ObjectDependencyID, typeof(bool), typeof(LayoutPreview), new PropertyMetadata(false));
|
||||
private LayoutModel _model;
|
||||
private List<Int32Rect> _zones = new List<Int32Rect>();
|
||||
|
||||
public bool IsActualSize
|
||||
{
|
||||
@@ -82,11 +80,6 @@ namespace FancyZonesEditor
|
||||
RenderPreview();
|
||||
}
|
||||
|
||||
public Int32Rect[] GetZoneRects()
|
||||
{
|
||||
return _zones.ToArray();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_model = (LayoutModel)DataContext;
|
||||
@@ -105,8 +98,6 @@ namespace FancyZonesEditor
|
||||
Body.RowDefinitions.Clear();
|
||||
Body.ColumnDefinitions.Clear();
|
||||
|
||||
_zones.Clear();
|
||||
|
||||
if (_model is GridLayoutModel gridModel)
|
||||
{
|
||||
RenderGridPreview(gridModel);
|
||||
@@ -121,32 +112,12 @@ namespace FancyZonesEditor
|
||||
{
|
||||
int rows = grid.Rows;
|
||||
int cols = grid.Columns;
|
||||
double spacing = grid.ShowSpacing ? grid.Spacing : 0;
|
||||
|
||||
RowColInfo[] rowInfo = (from percent in grid.RowPercents
|
||||
select new RowColInfo(percent)).ToArray();
|
||||
|
||||
RowColInfo[] colInfo = (from percent in grid.ColumnPercents
|
||||
select new RowColInfo(percent)).ToArray();
|
||||
|
||||
int spacing = grid.ShowSpacing ? grid.Spacing : 0;
|
||||
var rowData = GridData.PrefixSum(grid.RowPercents);
|
||||
var columnData = GridData.PrefixSum(grid.ColumnPercents);
|
||||
|
||||
var workArea = App.Overlay.WorkArea;
|
||||
double width = workArea.Width - (spacing * (cols + 1));
|
||||
double height = workArea.Height - (spacing * (rows + 1));
|
||||
|
||||
double top = spacing;
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
double cellHeight = rowInfo[row].Recalculate(top, height);
|
||||
top += cellHeight + spacing;
|
||||
}
|
||||
|
||||
double left = spacing;
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
double cellWidth = colInfo[col].Recalculate(left, width);
|
||||
left += cellWidth + spacing;
|
||||
}
|
||||
|
||||
Viewbox viewbox = new Viewbox
|
||||
{
|
||||
@@ -170,10 +141,8 @@ namespace FancyZonesEditor
|
||||
{
|
||||
// this is not a continuation of a span
|
||||
Border rect = new Border();
|
||||
left = colInfo[col].Start;
|
||||
top = rowInfo[row].Start;
|
||||
Canvas.SetTop(rect, top);
|
||||
Canvas.SetLeft(rect, left);
|
||||
double left = columnData[col] * workArea.Width / GridData.Multiplier;
|
||||
double top = rowData[row] * workArea.Height / GridData.Multiplier;
|
||||
|
||||
int maxRow = row;
|
||||
while (((maxRow + 1) < rows) && (grid.CellChildMap[maxRow + 1, col] == childIndex))
|
||||
@@ -187,12 +156,21 @@ namespace FancyZonesEditor
|
||||
maxCol++;
|
||||
}
|
||||
|
||||
rect.Width = Math.Max(0, colInfo[maxCol].End - left);
|
||||
rect.Height = Math.Max(0, rowInfo[maxRow].End - top);
|
||||
double right = columnData[maxCol + 1] * workArea.Width / GridData.Multiplier;
|
||||
double bottom = rowData[maxRow + 1] * workArea.Height / GridData.Multiplier;
|
||||
|
||||
left += col == 0 ? spacing : spacing / 2;
|
||||
right -= maxCol == cols - 1 ? spacing : spacing / 2;
|
||||
top += row == 0 ? spacing : spacing / 2;
|
||||
bottom -= maxRow == rows - 1 ? spacing : spacing / 2;
|
||||
|
||||
Canvas.SetTop(rect, top);
|
||||
Canvas.SetLeft(rect, left);
|
||||
rect.Width = Math.Max(1, right - left);
|
||||
rect.Height = Math.Max(1, bottom - top);
|
||||
|
||||
rect.Style = (Style)FindResource("GridLayoutActualScalePreviewStyle");
|
||||
frame.Children.Add(rect);
|
||||
_zones.Add(new Int32Rect(
|
||||
(int)left, (int)top, (int)rect.Width, (int)rect.Height));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,7 +261,7 @@ namespace FancyZonesEditor
|
||||
private void RenderCanvasPreview(CanvasLayoutModel canvas)
|
||||
{
|
||||
var workArea = canvas.CanvasRect;
|
||||
if (workArea.Width == 0 || workArea.Height == 0 || App.Overlay.SpanZonesAcrossMonitors)
|
||||
if (workArea.Width == 0 || workArea.Height == 0)
|
||||
{
|
||||
workArea = App.Overlay.WorkArea;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
public class MagneticSnap
|
||||
{
|
||||
private List<int> _keyPoints;
|
||||
private double _workAreaSize;
|
||||
|
||||
private const int MagnetZoneMaxSize = GridData.Multiplier / 12;
|
||||
|
||||
public MagneticSnap(List<int> keyPoints, double workAreaSize)
|
||||
{
|
||||
_keyPoints = keyPoints;
|
||||
_workAreaSize = workAreaSize;
|
||||
}
|
||||
|
||||
public int PixelToDataWithSnapping(double pixel, int low, int high)
|
||||
{
|
||||
var keyPoints = _keyPoints.Where(x => low < x && x < high).ToList();
|
||||
var magnetZoneSizes = new List<int>();
|
||||
|
||||
for (int i = 0; i < keyPoints.Count; i++)
|
||||
{
|
||||
int previous = i == 0 ? low : keyPoints[i - 1];
|
||||
int next = i == keyPoints.Count - 1 ? high : keyPoints[i + 1];
|
||||
magnetZoneSizes.Add(Math.Min(keyPoints[i] - previous, Math.Min(next - keyPoints[i], MagnetZoneMaxSize)) / 2);
|
||||
}
|
||||
|
||||
int data = Convert.ToInt32(pixel / _workAreaSize * GridData.Multiplier);
|
||||
data = Math.Clamp(data, low, high);
|
||||
int result;
|
||||
int snapId = -1;
|
||||
|
||||
for (int i = 0; i < keyPoints.Count; ++i)
|
||||
{
|
||||
if (Math.Abs(data - keyPoints[i]) <= magnetZoneSizes[i])
|
||||
{
|
||||
snapId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (snapId == -1)
|
||||
{
|
||||
result = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
int deadZoneWidth = (magnetZoneSizes[snapId] + 1) / 2;
|
||||
if (Math.Abs(data - keyPoints[snapId]) <= deadZoneWidth)
|
||||
{
|
||||
result = keyPoints[snapId];
|
||||
}
|
||||
else if (data < keyPoints[snapId])
|
||||
{
|
||||
result = data + (data - (keyPoints[snapId] - magnetZoneSizes[snapId]));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = data - ((keyPoints[snapId] + magnetZoneSizes[snapId]) - data);
|
||||
}
|
||||
}
|
||||
|
||||
return Math.Clamp(result, low, high);
|
||||
}
|
||||
|
||||
public double DataToPixelWithoutSnapping(int data)
|
||||
{
|
||||
return _workAreaSize * data / GridData.Multiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,9 @@
|
||||
</StackPanel>
|
||||
</ToolTip>
|
||||
</Border.ToolTip>
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
|
||||
|
||||
|
||||
<TextBlock Name="IndexText"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Text="{Binding Index}"
|
||||
@@ -93,6 +96,17 @@
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource PrimaryForegroundBrush}" />
|
||||
<TextBlock Name="ResolutionText"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Text="{Binding Dimensions}"
|
||||
Grid.Row="0"
|
||||
Margin="0,0,0,0"
|
||||
FontSize="11"
|
||||
FontWeight="SemiBold"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource SecondaryForegroundBrush}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Selected}"
|
||||
@@ -100,6 +114,10 @@
|
||||
<Setter TargetName="IndexText"
|
||||
Property="Foreground"
|
||||
Value="{DynamicResource SystemControlBackgroundAccentBrush}" />
|
||||
<Setter TargetName="ResolutionText"
|
||||
Property="Foreground"
|
||||
Value="{DynamicResource SystemControlBackgroundAccentBrush}" />
|
||||
|
||||
<Setter TargetName="MonitorItem"
|
||||
Property="BorderBrush"
|
||||
Value="{DynamicResource SystemControlBackgroundAccentBrush}" />
|
||||
@@ -284,6 +302,7 @@
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<Button x:Name="NewLayoutButton"
|
||||
Click="NewLayoutButton_Click"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -328,7 +347,6 @@
|
||||
<local1:MonitorViewModel x:Name="monitorViewModel" />
|
||||
</ScrollViewer.DataContext>
|
||||
<Grid>
|
||||
|
||||
<ItemsControl x:Name="MainWindowItemControl"
|
||||
TabIndex="0"
|
||||
ItemTemplate="{StaticResource MonitorItemTemplate}"
|
||||
@@ -341,7 +359,6 @@
|
||||
Margin="8, 0, 8, 16" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
@@ -355,6 +372,7 @@
|
||||
PrimaryButtonClick="EditLayoutDialog_PrimaryButtonClick"
|
||||
SecondaryButtonClick="EditLayoutDialog_SecondaryButtonClick"
|
||||
Title="{x:Static props:Resources.Edit_Layout}"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
Opened="Dialog_Opened"
|
||||
Closed="Dialog_Closed">
|
||||
<Grid DataContext="{Binding SelectedModel}"
|
||||
@@ -419,55 +437,55 @@
|
||||
HorizontalAlignment="Center"
|
||||
Visibility="{Binding Path=Type, Converter={StaticResource LayoutTypeTemplateToVisibilityConverter}}">
|
||||
|
||||
<Button x:Name="decrementZones"
|
||||
Width="40"
|
||||
Height="40"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Decrement}"
|
||||
ToolTip="{x:Static props:Resources.Zone_Count_Decrement}"
|
||||
Foreground="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||
Style="{StaticResource IconOnlyButtonStyle}"
|
||||
Click="DecrementZones_Click">
|
||||
<Button.Content>
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBlock x:Name="zoneCount"
|
||||
Text="{Binding TemplateZoneCount}"
|
||||
FontWeight="SemiBold"
|
||||
FontSize="18"
|
||||
Width="32"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
Margin="0,-4,0,0"
|
||||
ToolTip="Number of zones"
|
||||
VerticalAlignment="Center" />
|
||||
<Button x:Name="decrementZones"
|
||||
Width="40"
|
||||
Height="40"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Decrement}"
|
||||
ToolTip="{x:Static props:Resources.Zone_Count_Decrement}"
|
||||
Foreground="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||
Style="{StaticResource IconOnlyButtonStyle}"
|
||||
Click="DecrementZones_Click">
|
||||
<Button.Content>
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button x:Name="incrementZones"
|
||||
Width="40"
|
||||
Height="40"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Increment}"
|
||||
ToolTip="{x:Static props:Resources.Zone_Count_Increment}"
|
||||
Foreground="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||
Style="{StaticResource IconOnlyButtonStyle}"
|
||||
Click="IncrementZones_Click">
|
||||
<Button.Content>
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<TextBlock x:Name="zoneCount"
|
||||
Text="{Binding TemplateZoneCount}"
|
||||
FontWeight="SemiBold"
|
||||
FontSize="18"
|
||||
Width="32"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
Margin="0,-4,0,0"
|
||||
ToolTip="Number of zones"
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
<Button x:Name="incrementZones"
|
||||
Width="40"
|
||||
Height="40"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Increment}"
|
||||
ToolTip="{x:Static props:Resources.Zone_Count_Increment}"
|
||||
Foreground="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||
Style="{StaticResource IconOnlyButtonStyle}"
|
||||
Click="IncrementZones_Click">
|
||||
<Button.Content>
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<TextBox Text="{Binding Name}"
|
||||
ui:ControlHelper.Header="{x:Static props:Resources.Name}"
|
||||
Margin="0,16,0,0"
|
||||
Margin="0,16,2,0"
|
||||
Visibility="{Binding IsCustom, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
HorizontalAlignment="Stretch" />
|
||||
|
||||
<CheckBox x:Name="spaceAroundSetting"
|
||||
Content="{x:Static props:Resources.Show_Space_Zones}"
|
||||
IsChecked="{Binding ShowSpacing}"
|
||||
Margin="0,16,0,0"
|
||||
Margin="0,16,12,0"
|
||||
Visibility="{Binding Converter={StaticResource LayoutModelTypeToVisibilityConverter}}" />
|
||||
|
||||
<ui:NumberBox Margin="0,6,0,0"
|
||||
@@ -483,7 +501,8 @@
|
||||
|
||||
<TextBlock Text="{x:Static props:Resources.Distance_adjacent_zones}"
|
||||
IsEnabled="{Binding ShowSpacing}"
|
||||
Margin="0,16,0,0"
|
||||
Margin="0,16,12,0"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource PrimaryForegroundBrush}"
|
||||
x:Name="sensitivityRadiusValue" />
|
||||
|
||||
@@ -495,6 +514,18 @@
|
||||
SpinButtonPlacementMode="Compact"
|
||||
HorizontalAlignment="Left"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=sensitivityRadiusValue}" />
|
||||
|
||||
<TextBlock Text="{x:Static props:Resources.QuickKey_Select}"
|
||||
Margin="0,16,12,0"
|
||||
Foreground="{DynamicResource PrimaryForegroundBrush}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{Binding Path=Type, Converter={StaticResource LayoutTypeCustomToVisibilityConverter}}"/>
|
||||
<ComboBox x:Name="quickKeySelectionComboBox"
|
||||
Margin="0,6,0,0"
|
||||
ItemsSource="{Binding QuickKeysAvailable}"
|
||||
SelectedItem="{Binding QuickKey}"
|
||||
Width="106"
|
||||
Visibility="{Binding Path=Type, Converter={StaticResource LayoutTypeCustomToVisibilityConverter}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ui:ContentDialog>
|
||||
|
||||
@@ -304,7 +304,8 @@ namespace FancyZonesEditor
|
||||
}
|
||||
else
|
||||
{
|
||||
CanvasLayoutModel canvasModel = new CanvasLayoutModel(LayoutNameText.Text, LayoutType.Custom);
|
||||
var area = App.Overlay.WorkArea;
|
||||
CanvasLayoutModel canvasModel = new CanvasLayoutModel(LayoutNameText.Text, LayoutType.Custom, (int)area.Width, (int)area.Height);
|
||||
canvasModel.AddZone();
|
||||
selectedLayoutModel = canvasModel;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@ namespace FancyZonesEditor.Models
|
||||
CanvasRect = new Rect(new Size(width, height));
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name, LayoutType type, int width, int height)
|
||||
: base(name, type)
|
||||
{
|
||||
CanvasRect = new Rect(new Size(width, height));
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name, LayoutType type)
|
||||
: base(name, type)
|
||||
{
|
||||
@@ -148,6 +154,7 @@ namespace FancyZonesEditor.Models
|
||||
}
|
||||
|
||||
layout.SensitivityRadius = SensitivityRadius;
|
||||
layout.CanvasRect = CanvasRect;
|
||||
return layout;
|
||||
}
|
||||
|
||||
@@ -161,6 +168,7 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
other._topLeft = _topLeft;
|
||||
other.SensitivityRadius = SensitivityRadius;
|
||||
other.CanvasRect = CanvasRect;
|
||||
other.UpdateLayout();
|
||||
}
|
||||
|
||||
|
||||
@@ -120,11 +120,6 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
private int _spacing = LayoutSettings.DefaultSpacing;
|
||||
|
||||
// FreeZones (not persisted) - used to keep track of child indices that are no longer in use in the CellChildMap,
|
||||
// making them candidates for re-use when it's needed to add another child
|
||||
// TODO: do I need FreeZones on the data model? - I think I do
|
||||
public IList<int> FreeZones { get; } = new List<int>();
|
||||
|
||||
public GridLayoutModel()
|
||||
: base()
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@@ -16,6 +17,8 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
_guid = Guid.NewGuid();
|
||||
Type = LayoutType.Custom;
|
||||
|
||||
MainWindowSettingsModel.QuickKeys.PropertyChanged += QuickSwitchKeys_PropertyChanged;
|
||||
}
|
||||
|
||||
protected LayoutModel(string name)
|
||||
@@ -48,6 +51,9 @@ namespace FancyZonesEditor.Models
|
||||
_isApplied = other._isApplied;
|
||||
_sensitivityRadius = other._sensitivityRadius;
|
||||
_zoneCount = other._zoneCount;
|
||||
_quickKey = other._quickKey;
|
||||
|
||||
MainWindowSettingsModel.QuickKeys.PropertyChanged += QuickSwitchKeys_PropertyChanged;
|
||||
}
|
||||
|
||||
// Name - the display name for this layout model - is also used as the key in the registry
|
||||
@@ -158,6 +164,55 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
private int _sensitivityRadius = LayoutSettings.DefaultSensitivityRadius;
|
||||
|
||||
public List<string> QuickKeysAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
foreach (var pair in MainWindowSettingsModel.QuickKeys.SelectedKeys)
|
||||
{
|
||||
if (pair.Value == string.Empty || pair.Value == Uuid)
|
||||
{
|
||||
result.Add(pair.Key);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public string QuickKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _quickKey == -1 ? Properties.Resources.Quick_Key_None : _quickKey.ToString();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
string none = Properties.Resources.Quick_Key_None;
|
||||
var intValue = value == none ? -1 : int.Parse(value);
|
||||
if (intValue != _quickKey)
|
||||
{
|
||||
string prev = _quickKey == -1 ? none : _quickKey.ToString();
|
||||
_quickKey = intValue;
|
||||
|
||||
if (intValue != -1)
|
||||
{
|
||||
MainWindowSettingsModel.QuickKeys.SelectKey(value, Uuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainWindowSettingsModel.QuickKeys.FreeKey(prev);
|
||||
}
|
||||
|
||||
FirePropertyChanged(nameof(QuickKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _quickKey = -1;
|
||||
|
||||
// TemplateZoneCount - number of zones selected in the picker window for template layouts
|
||||
public int TemplateZoneCount
|
||||
{
|
||||
@@ -200,6 +255,11 @@ namespace FancyZonesEditor.Models
|
||||
// Removes this Layout from the registry and the loaded CustomModels list
|
||||
public void Delete()
|
||||
{
|
||||
if (_quickKey != -1)
|
||||
{
|
||||
MainWindowSettingsModel.QuickKeys.FreeKey(QuickKey);
|
||||
}
|
||||
|
||||
var customModels = MainWindowSettingsModel.CustomModels;
|
||||
int i = customModels.IndexOf(this);
|
||||
if (i != -1)
|
||||
@@ -241,5 +301,17 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
PersistData();
|
||||
}
|
||||
|
||||
private void QuickSwitchKeys_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
foreach (var pair in MainWindowSettingsModel.QuickKeys.SelectedKeys)
|
||||
{
|
||||
if (pair.Value == Uuid)
|
||||
{
|
||||
QuickKey = pair.Key.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace FancyZonesEditor.Models
|
||||
{
|
||||
public enum LayoutType
|
||||
{
|
||||
Blank = -1,
|
||||
Blank = 0,
|
||||
Focus,
|
||||
Columns,
|
||||
Rows,
|
||||
|
||||
@@ -23,13 +23,6 @@ namespace FancyZonesEditor
|
||||
VirtualDesktopId,
|
||||
}
|
||||
|
||||
private readonly CanvasLayoutModel _blankModel;
|
||||
private readonly CanvasLayoutModel _focusModel;
|
||||
private readonly GridLayoutModel _rowsModel;
|
||||
private readonly GridLayoutModel _columnsModel;
|
||||
private readonly GridLayoutModel _gridModel;
|
||||
private readonly GridLayoutModel _priorityGridModel;
|
||||
|
||||
// Non-localizable strings
|
||||
public static readonly string RegistryPath = "SOFTWARE\\SuperFancyZones";
|
||||
public static readonly string FullRegistryPath = "HKEY_CURRENT_USER\\" + RegistryPath;
|
||||
@@ -53,40 +46,40 @@ namespace FancyZonesEditor
|
||||
public MainWindowSettingsModel()
|
||||
{
|
||||
// Initialize default layout models: Blank, Focus, Columns, Rows, Grid, and PriorityGrid
|
||||
_blankModel = new CanvasLayoutModel(Properties.Resources.Template_Layout_Blank, LayoutType.Blank)
|
||||
var blankModel = new CanvasLayoutModel(Properties.Resources.Template_Layout_Blank, LayoutType.Blank)
|
||||
{
|
||||
TemplateZoneCount = 0,
|
||||
SensitivityRadius = 0,
|
||||
};
|
||||
DefaultModels.Add(_blankModel);
|
||||
DefaultModels.Insert((int)LayoutType.Blank, blankModel);
|
||||
|
||||
_focusModel = new CanvasLayoutModel(Properties.Resources.Template_Layout_Focus, LayoutType.Focus);
|
||||
_focusModel.InitTemplateZones();
|
||||
DefaultModels.Add(_focusModel);
|
||||
var focusModel = new CanvasLayoutModel(Properties.Resources.Template_Layout_Focus, LayoutType.Focus);
|
||||
focusModel.InitTemplateZones();
|
||||
DefaultModels.Insert((int)LayoutType.Focus, focusModel);
|
||||
|
||||
_columnsModel = new GridLayoutModel(Properties.Resources.Template_Layout_Columns, LayoutType.Columns)
|
||||
var columnsModel = new GridLayoutModel(Properties.Resources.Template_Layout_Columns, LayoutType.Columns)
|
||||
{
|
||||
Rows = 1,
|
||||
RowPercents = new List<int>(1) { GridLayoutModel.GridMultiplier },
|
||||
};
|
||||
_columnsModel.InitTemplateZones();
|
||||
DefaultModels.Add(_columnsModel);
|
||||
columnsModel.InitTemplateZones();
|
||||
DefaultModels.Insert((int)LayoutType.Columns, columnsModel);
|
||||
|
||||
_rowsModel = new GridLayoutModel(Properties.Resources.Template_Layout_Rows, LayoutType.Rows)
|
||||
var rowsModel = new GridLayoutModel(Properties.Resources.Template_Layout_Rows, LayoutType.Rows)
|
||||
{
|
||||
Columns = 1,
|
||||
ColumnPercents = new List<int>(1) { GridLayoutModel.GridMultiplier },
|
||||
};
|
||||
_rowsModel.InitTemplateZones();
|
||||
DefaultModels.Add(_rowsModel);
|
||||
rowsModel.InitTemplateZones();
|
||||
DefaultModels.Insert((int)LayoutType.Rows, rowsModel);
|
||||
|
||||
_gridModel = new GridLayoutModel(Properties.Resources.Template_Layout_Grid, LayoutType.Grid);
|
||||
_gridModel.InitTemplateZones();
|
||||
DefaultModels.Add(_gridModel);
|
||||
var gridModel = new GridLayoutModel(Properties.Resources.Template_Layout_Grid, LayoutType.Grid);
|
||||
gridModel.InitTemplateZones();
|
||||
DefaultModels.Insert((int)LayoutType.Grid, gridModel);
|
||||
|
||||
_priorityGridModel = new GridLayoutModel(Properties.Resources.Template_Layout_Priority_Grid, LayoutType.PriorityGrid);
|
||||
_priorityGridModel.InitTemplateZones();
|
||||
DefaultModels.Add(_priorityGridModel);
|
||||
var priorityGridModel = new GridLayoutModel(Properties.Resources.Template_Layout_Priority_Grid, LayoutType.PriorityGrid);
|
||||
priorityGridModel.InitTemplateZones();
|
||||
DefaultModels.Insert((int)LayoutType.PriorityGrid, priorityGridModel);
|
||||
}
|
||||
|
||||
// IsShiftKeyPressed - is the shift key currently being held down
|
||||
@@ -133,7 +126,7 @@ namespace FancyZonesEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return _blankModel;
|
||||
return DefaultModels[(int)LayoutType.Blank];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +142,8 @@ namespace FancyZonesEditor
|
||||
|
||||
private static ObservableCollection<LayoutModel> _customModels = new ObservableCollection<LayoutModel>();
|
||||
|
||||
public static QuickKeysModel QuickKeys { get; } = new QuickKeysModel();
|
||||
|
||||
public LayoutModel SelectedModel
|
||||
{
|
||||
get
|
||||
@@ -202,7 +197,7 @@ namespace FancyZonesEditor
|
||||
{
|
||||
foreach (LayoutModel model in CustomModels)
|
||||
{
|
||||
if ("{" + model.Guid.ToString().ToUpperInvariant() + "}" == currentApplied.ZonesetUuid.ToUpperInvariant())
|
||||
if (model.Uuid == currentApplied.ZonesetUuid.ToUpperInvariant())
|
||||
{
|
||||
// found match
|
||||
foundModel = model;
|
||||
@@ -234,7 +229,7 @@ namespace FancyZonesEditor
|
||||
|
||||
if (foundModel == null)
|
||||
{
|
||||
foundModel = _priorityGridModel;
|
||||
foundModel = DefaultModels[(int)LayoutType.PriorityGrid];
|
||||
}
|
||||
|
||||
SetSelectedModel(foundModel);
|
||||
@@ -255,6 +250,7 @@ namespace FancyZonesEditor
|
||||
SelectedModel.IsSelected = model.IsSelected;
|
||||
SelectedModel.IsApplied = model.IsApplied;
|
||||
SelectedModel.Name = model.Name;
|
||||
SelectedModel.QuickKey = model.QuickKey;
|
||||
|
||||
if (model is GridLayoutModel grid)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
public class QuickKeysModel : INotifyPropertyChanged
|
||||
{
|
||||
public SortedDictionary<string, string> SelectedKeys { get; } = new SortedDictionary<string, string>()
|
||||
{
|
||||
{ Properties.Resources.Quick_Key_None, string.Empty },
|
||||
{ "0", string.Empty },
|
||||
{ "1", string.Empty },
|
||||
{ "2", string.Empty },
|
||||
{ "3", string.Empty },
|
||||
{ "4", string.Empty },
|
||||
{ "5", string.Empty },
|
||||
{ "6", string.Empty },
|
||||
{ "7", string.Empty },
|
||||
{ "8", string.Empty },
|
||||
{ "9", string.Empty },
|
||||
};
|
||||
|
||||
public QuickKeysModel()
|
||||
{
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public void FreeKey(string key)
|
||||
{
|
||||
if (SelectedKeys.ContainsKey(key))
|
||||
{
|
||||
SelectedKeys[key] = string.Empty;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool SelectKey(string key, string uuid)
|
||||
{
|
||||
if (!SelectedKeys.ContainsKey(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SelectedKeys[key] == uuid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// clean previous value
|
||||
foreach (var pair in SelectedKeys)
|
||||
{
|
||||
if (pair.Value == uuid)
|
||||
{
|
||||
SelectedKeys[pair.Key] = string.Empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SelectedKeys[key] = uuid;
|
||||
FirePropertyChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
var keys = SelectedKeys.Keys.ToList();
|
||||
foreach (var key in keys)
|
||||
{
|
||||
SelectedKeys[key] = string.Empty;
|
||||
}
|
||||
|
||||
FirePropertyChanged();
|
||||
}
|
||||
|
||||
protected virtual void FirePropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,46 +363,5 @@ namespace FancyZonesEditor
|
||||
Monitors.Add(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
public Int32Rect[] GetZoneRects()
|
||||
{
|
||||
if (_editor != null)
|
||||
{
|
||||
if (_editor is GridEditor gridEditor)
|
||||
{
|
||||
return ZoneRectsFromPanel(gridEditor.PreviewPanel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CanvasEditor
|
||||
return ZoneRectsFromPanel(((CanvasEditor)_editor).Preview);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// One of the predefined zones (neither grid or canvas editor used).
|
||||
return _layoutPreview.GetZoneRects();
|
||||
}
|
||||
}
|
||||
|
||||
private Int32Rect[] ZoneRectsFromPanel(Panel previewPanel)
|
||||
{
|
||||
// TODO: the ideal here is that the ArrangeRects logic is entirely inside the model, so we don't have to walk the UIElement children to get the rect info
|
||||
int count = previewPanel.Children.Count;
|
||||
Int32Rect[] zones = new Int32Rect[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
FrameworkElement child = (FrameworkElement)previewPanel.Children[i];
|
||||
Point topLeft = child.TransformToAncestor(previewPanel).Transform(default);
|
||||
|
||||
zones[i].X = (int)topLeft.X;
|
||||
zones[i].Y = (int)topLeft.Y;
|
||||
zones[i].Width = (int)child.ActualWidth;
|
||||
zones[i].Height = (int)child.ActualHeight;
|
||||
}
|
||||
|
||||
return zones;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,11 +376,11 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 'zones-settings.json' contains malformed data..
|
||||
/// Looks up a localized string similar to A layout that contained invalid data has been removed..
|
||||
/// </summary>
|
||||
public static string Error_Parsing_Zones_Settings_Malformed_Data {
|
||||
public static string Error_Parsing_Zones_Settings_Message {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Parsing_Zones_Settings_Malformed_Data", resourceCulture);
|
||||
return ResourceManager.GetString("Error_Parsing_Zones_Settings_Message", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,15 +393,6 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Would you like to continue? Malformed data will be lost..
|
||||
/// </summary>
|
||||
public static string Error_Parsing_Zones_Settings_User_Choice {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Parsing_Zones_Settings_User_Choice", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error persisting custom layout.
|
||||
/// </summary>
|
||||
@@ -501,6 +492,24 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Click and drag across zones..
|
||||
/// </summary>
|
||||
public static string MergeDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("MergeDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Merge/Delete:.
|
||||
/// </summary>
|
||||
public static string MergeName {
|
||||
get {
|
||||
return ResourceManager.GetString("MergeName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Monitor.
|
||||
/// </summary>
|
||||
@@ -528,16 +537,6 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Hold down Shift key to change orientation of splitter.
|
||||
///To merge zones, select the zones and click "merge"..
|
||||
/// </summary>
|
||||
public static string Note_Custom_Table {
|
||||
get {
|
||||
return ResourceManager.GetString("Note_Custom_Table", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Number of zones.
|
||||
/// </summary>
|
||||
@@ -547,6 +546,24 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to None.
|
||||
/// </summary>
|
||||
public static string Quick_Key_None {
|
||||
get {
|
||||
return ResourceManager.GetString("Quick_Key_None", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Select a key to quickly apply the layout (Win + Ctrl + Alt + key).
|
||||
/// </summary>
|
||||
public static string QuickKey_Select {
|
||||
get {
|
||||
return ResourceManager.GetString("QuickKey_Select", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reset layout.
|
||||
/// </summary>
|
||||
@@ -601,6 +618,24 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Hold Shift key for vertical split..
|
||||
/// </summary>
|
||||
public static string SplitterDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("SplitterDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Splitter:.
|
||||
/// </summary>
|
||||
public static string SplitterName {
|
||||
get {
|
||||
return ResourceManager.GetString("SplitterName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No layout.
|
||||
/// </summary>
|
||||
|
||||
@@ -159,10 +159,6 @@
|
||||
<data name="Name" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
</data>
|
||||
<data name="Note_Custom_Table" xml:space="preserve">
|
||||
<value>Hold down Shift key to change orientation of splitter.
|
||||
To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".</value>
|
||||
</data>
|
||||
<data name="Save_Apply" xml:space="preserve">
|
||||
<value>Save & apply</value>
|
||||
</data>
|
||||
@@ -307,14 +303,11 @@ To merge zones, hold down the left mouse button, drag the mouse to the zone to m
|
||||
<value>Delete zone</value>
|
||||
<comment>A tooltip on a button that allows the user to delete a zone</comment>
|
||||
</data>
|
||||
<data name="Error_Parsing_Zones_Settings_Malformed_Data" xml:space="preserve">
|
||||
<value>'zones-settings.json' contains malformed data.</value>
|
||||
</data>
|
||||
<data name="Error_Parsing_Zones_Settings_Title" xml:space="preserve">
|
||||
<value>Editor settings parsing error.</value>
|
||||
</data>
|
||||
<data name="Error_Parsing_Zones_Settings_User_Choice" xml:space="preserve">
|
||||
<value>Would you like to continue? Malformed data will be lost.</value>
|
||||
<data name="Error_Parsing_Zones_Settings_Message" xml:space="preserve">
|
||||
<value>A layout that contained invalid data has been removed.</value>
|
||||
</data>
|
||||
<data name="Apply_Layout" xml:space="preserve">
|
||||
<value>Apply layout</value>
|
||||
@@ -334,4 +327,26 @@ To merge zones, hold down the left mouse button, drag the mouse to the zone to m
|
||||
<data name="Default_Custom_Layout_Name" xml:space="preserve">
|
||||
<value>Custom layout</value>
|
||||
</data>
|
||||
<data name="MergeDescription" xml:space="preserve">
|
||||
<value>Click and drag across zones.</value>
|
||||
<comment>Click mouse, hold button down and drag across multiple zones in tool</comment>
|
||||
</data>
|
||||
<data name="MergeName" xml:space="preserve">
|
||||
<value>Merge/Delete:</value>
|
||||
<comment>Title for concept behind Merging two zones together or removing an zone</comment>
|
||||
</data>
|
||||
<data name="SplitterDescription" xml:space="preserve">
|
||||
<value>Hold Shift key for vertical split.</value>
|
||||
<comment>A segmenter visual for splitting one item into two. This would be the vertical line. Shift key is referring to key on keyboard</comment>
|
||||
</data>
|
||||
<data name="SplitterName" xml:space="preserve">
|
||||
<value>Splitter:</value>
|
||||
<comment>Title for concept: A segmenter visual for splitting one item into two. This would be the vertical line</comment>
|
||||
</data>
|
||||
<data name="QuickKey_Select" xml:space="preserve">
|
||||
<value>Select a key to quickly apply the layout (Win + Ctrl + Alt + key)</value>
|
||||
</data>
|
||||
<data name="Quick_Key_None" xml:space="preserve">
|
||||
<value>None</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,66 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
public class RowColInfo
|
||||
{
|
||||
private const int _multiplier = 10000;
|
||||
|
||||
public double Extent { get; set; }
|
||||
|
||||
public double Start { get; set; }
|
||||
|
||||
public double End { get; set; }
|
||||
|
||||
public int Percent { get; set; }
|
||||
|
||||
public RowColInfo(int percent)
|
||||
{
|
||||
Percent = percent;
|
||||
}
|
||||
|
||||
public RowColInfo(RowColInfo other)
|
||||
{
|
||||
Percent = other.Percent;
|
||||
Extent = other.Extent;
|
||||
Start = other.Start;
|
||||
End = other.End;
|
||||
}
|
||||
|
||||
public RowColInfo(int index, int count)
|
||||
{
|
||||
Percent = (_multiplier / count) + ((index == 0) ? (_multiplier % count) : 0);
|
||||
}
|
||||
|
||||
public double Recalculate(double start, double totalExtent)
|
||||
{
|
||||
Start = start;
|
||||
Extent = totalExtent * Percent / _multiplier;
|
||||
End = Start + Extent;
|
||||
return Extent;
|
||||
}
|
||||
|
||||
public void RecalculatePercent(double newTotalExtent)
|
||||
{
|
||||
Percent = (int)(Extent * _multiplier / newTotalExtent);
|
||||
}
|
||||
|
||||
public RowColInfo[] Split(double offset, double space)
|
||||
{
|
||||
RowColInfo[] info = new RowColInfo[2];
|
||||
|
||||
double totalExtent = Extent * _multiplier / Percent;
|
||||
totalExtent -= space;
|
||||
|
||||
int percent0 = (int)(offset * _multiplier / totalExtent);
|
||||
int percent1 = (int)((Extent - space - offset) * _multiplier / totalExtent);
|
||||
|
||||
info[0] = new RowColInfo(percent0);
|
||||
info[1] = new RowColInfo(percent1);
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,18 +13,15 @@ namespace FancyZonesEditor
|
||||
{
|
||||
}
|
||||
|
||||
public SplitEventArgs(Orientation orientation, double offset, double thickness)
|
||||
public SplitEventArgs(Orientation orientation, int offset)
|
||||
{
|
||||
Orientation = orientation;
|
||||
Offset = offset;
|
||||
Space = thickness;
|
||||
}
|
||||
|
||||
public Orientation Orientation { get; }
|
||||
|
||||
public double Offset { get; }
|
||||
|
||||
public double Space { get; }
|
||||
public int Offset { get; }
|
||||
}
|
||||
|
||||
public delegate void SplitEventHandler(object sender, SplitEventArgs args);
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
|
||||
<Style x:Key="GridLayoutActualScalePreviewStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource LayoutPreviewActualScaleZoneBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource LayoutPreviewZoneBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlBackgroundAccentBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="Effect" Value="{StaticResource ZoneDropShadow}" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CanvasLayoutSmallScalePreviewStyle" TargetType="Border">
|
||||
@@ -29,9 +28,8 @@
|
||||
|
||||
<Style x:Key="CanvasLayoutActualScalePreviewStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource LayoutPreviewActualScaleZoneBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource LayoutPreviewZoneBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlBackgroundAccentBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="Effect" Value="{StaticResource ZoneDropShadow}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -15,15 +15,21 @@
|
||||
<SolidColorBrush x:Key="TertiaryBackgroundBrush" Color="#FF202020" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FFFFFFFF" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF9a9a9a" />
|
||||
<SolidColorBrush x:Key="BackdropBrush" Color="#E55B5B5B" />
|
||||
<SolidColorBrush x:Key="BackdropBrush" Color="#40F0F0F0" />
|
||||
<SolidColorBrush x:Key="TitleBarSecondaryForegroundBrush" Color="#FF9a9a9a" />
|
||||
|
||||
<!-- Used for layouts and monitors -->
|
||||
<SolidColorBrush x:Key="LayoutItemBackgroundBrush" Color="#FF3A3A3A" />
|
||||
<SolidColorBrush x:Key="LayoutItemBackgroundPointerOverBrush" Color="#FF333333" />
|
||||
|
||||
<!-- Used for the fullscreen preview (ActualScale) and for the thumbnail preview (SmallScale) -->
|
||||
<SolidColorBrush x:Key="LayoutPreviewBackgroundBrush" Color="#331B1B1B" />
|
||||
<!-- Currently unused -->
|
||||
<SolidColorBrush x:Key="LayoutPreviewZoneBorderBrush" Color="#FF555454" />
|
||||
|
||||
<SolidColorBrush x:Key="LayoutPreviewActualScaleZoneBackgroundBrush" Color="#E5202020" />
|
||||
<SolidColorBrush x:Key="LayoutPreviewActualScaleZoneBackgroundBrush" Color="#B0202020" />
|
||||
<SolidColorBrush x:Key="LayoutPreviewSmallScaleZoneBackgroundBrush" Color="#FF202020" />
|
||||
<SolidColorBrush x:Key="CanvasZoneBackgroundBrush" Color="#E5202020" />
|
||||
<SolidColorBrush x:Key="GridZoneBackgroundBrush" Color="#E5202020" />
|
||||
|
||||
<SolidColorBrush x:Key="CanvasZoneBackgroundBrush" Color="#B0202020" />
|
||||
<SolidColorBrush x:Key="GridZoneBackgroundBrush" Color="#B0202020" />
|
||||
</ResourceDictionary>
|
||||
@@ -14,16 +14,22 @@
|
||||
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FFeeeeee" />
|
||||
<SolidColorBrush x:Key="TertiaryBackgroundBrush" Color="#FFF3F3F3" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FF000000" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF949494" />
|
||||
<SolidColorBrush x:Key="BackdropBrush" Color="#E5949494" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF6A6A6A" />
|
||||
<SolidColorBrush x:Key="BackdropBrush" Color="#85F0F0F0" />
|
||||
<SolidColorBrush x:Key="TitleBarSecondaryForegroundBrush" Color="#FF949494" />
|
||||
|
||||
<!-- Used for layouts and monitors -->
|
||||
<SolidColorBrush x:Key="LayoutItemBackgroundBrush" Color="#FFffffff"/>
|
||||
<SolidColorBrush x:Key="LayoutItemBackgroundPointerOverBrush" Color="#FFf2f2f2" />
|
||||
|
||||
<!-- Used for the fullscreen preview (ActualScale) and for the thumbnail preview (SmallScale) -->
|
||||
<SolidColorBrush x:Key="LayoutPreviewBackgroundBrush" Color="#19949494" />
|
||||
<!-- Currently unused -->
|
||||
<SolidColorBrush x:Key="LayoutPreviewZoneBorderBrush" Color="#FFC3BEBE" />
|
||||
|
||||
<SolidColorBrush x:Key="LayoutPreviewActualScaleZoneBackgroundBrush" Color="#E5F3F3F3" />
|
||||
<SolidColorBrush x:Key="LayoutPreviewActualScaleZoneBackgroundBrush" Color="#C5F8F8F8" />
|
||||
<SolidColorBrush x:Key="LayoutPreviewSmallScaleZoneBackgroundBrush" Color="#FFDCDCDC" />
|
||||
<SolidColorBrush x:Key="CanvasZoneBackgroundBrush" Color="#E5F3F3F3" />
|
||||
<SolidColorBrush x:Key="GridZoneBackgroundBrush" Color="#E5F3F3F3" />
|
||||
|
||||
<SolidColorBrush x:Key="CanvasZoneBackgroundBrush" Color="#C5F8F8F8" />
|
||||
<SolidColorBrush x:Key="GridZoneBackgroundBrush" Color="#C5F8F8F8" />
|
||||
</ResourceDictionary>
|
||||
@@ -57,6 +57,7 @@ namespace FancyZonesEditor.Utils
|
||||
MonitorTop,
|
||||
}
|
||||
|
||||
// parsing cmd args
|
||||
private struct NativeMonitorData
|
||||
{
|
||||
public string MonitorId { get; set; }
|
||||
@@ -87,6 +88,7 @@ namespace FancyZonesEditor.Utils
|
||||
}
|
||||
}
|
||||
|
||||
// zones-settings: devices
|
||||
private struct DeviceWrapper
|
||||
{
|
||||
public struct ActiveZoneSetWrapper
|
||||
@@ -109,6 +111,7 @@ namespace FancyZonesEditor.Utils
|
||||
public int EditorSensitivityRadius { get; set; }
|
||||
}
|
||||
|
||||
// zones-settings: custom-zone-sets
|
||||
private class CanvasInfoWrapper
|
||||
{
|
||||
public struct CanvasZoneWrapper
|
||||
@@ -131,6 +134,7 @@ namespace FancyZonesEditor.Utils
|
||||
public int SensitivityRadius { get; set; } = LayoutSettings.DefaultSensitivityRadius;
|
||||
}
|
||||
|
||||
// zones-settings: custom-zone-sets
|
||||
private class GridInfoWrapper
|
||||
{
|
||||
public int Rows { get; set; }
|
||||
@@ -150,6 +154,7 @@ namespace FancyZonesEditor.Utils
|
||||
public int SensitivityRadius { get; set; } = LayoutSettings.DefaultSensitivityRadius;
|
||||
}
|
||||
|
||||
// zones-settings: custom-zone-sets
|
||||
private struct CustomLayoutWrapper
|
||||
{
|
||||
public string Uuid { get; set; }
|
||||
@@ -161,6 +166,7 @@ namespace FancyZonesEditor.Utils
|
||||
public JsonElement Info { get; set; } // CanvasInfoWrapper or GridInfoWrapper
|
||||
}
|
||||
|
||||
// zones-settings: templates
|
||||
private struct TemplateLayoutWrapper
|
||||
{
|
||||
public string Type { get; set; }
|
||||
@@ -174,6 +180,15 @@ namespace FancyZonesEditor.Utils
|
||||
public int SensitivityRadius { get; set; }
|
||||
}
|
||||
|
||||
// zones-settings: quick-layout-keys-wrapper
|
||||
private struct QuickLayoutKeysWrapper
|
||||
{
|
||||
public int Key { get; set; }
|
||||
|
||||
public string Uuid { get; set; }
|
||||
}
|
||||
|
||||
// zones-settings
|
||||
private struct ZoneSettingsWrapper
|
||||
{
|
||||
public List<DeviceWrapper> Devices { get; set; }
|
||||
@@ -181,6 +196,8 @@ namespace FancyZonesEditor.Utils
|
||||
public List<CustomLayoutWrapper> CustomZoneSets { get; set; }
|
||||
|
||||
public List<TemplateLayoutWrapper> Templates { get; set; }
|
||||
|
||||
public List<QuickLayoutKeysWrapper> QuickLayoutKeys { get; set; }
|
||||
}
|
||||
|
||||
private struct EditorParams
|
||||
@@ -528,10 +545,11 @@ namespace FancyZonesEditor.Utils
|
||||
bool devicesParsingResult = SetDevices(zoneSettings.Devices);
|
||||
bool customZonesParsingResult = SetCustomLayouts(zoneSettings.CustomZoneSets);
|
||||
bool templatesParsingResult = SetTemplateLayouts(zoneSettings.Templates);
|
||||
bool quickLayoutSwitchKeysParsingResult = SetQuickLayoutSwitchKeys(zoneSettings.QuickLayoutKeys);
|
||||
|
||||
if (!devicesParsingResult || !customZonesParsingResult)
|
||||
{
|
||||
return new ParsingResult(false, Properties.Resources.Error_Parsing_Zones_Settings_Malformed_Data, settingsString);
|
||||
return new ParsingResult(false, FancyZonesEditor.Properties.Resources.Error_Parsing_Zones_Settings_Message, settingsString);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -549,6 +567,7 @@ namespace FancyZonesEditor.Utils
|
||||
zoneSettings.Devices = new List<DeviceWrapper>();
|
||||
zoneSettings.CustomZoneSets = new List<CustomLayoutWrapper>();
|
||||
zoneSettings.Templates = new List<TemplateLayoutWrapper>();
|
||||
zoneSettings.QuickLayoutKeys = new List<QuickLayoutKeysWrapper>();
|
||||
|
||||
// Serialize used devices
|
||||
foreach (var monitor in App.Overlay.Monitors)
|
||||
@@ -685,6 +704,27 @@ namespace FancyZonesEditor.Utils
|
||||
zoneSettings.Templates.Add(wrapper);
|
||||
}
|
||||
|
||||
// Serialize quick layout switch keys
|
||||
foreach (var pair in MainWindowSettingsModel.QuickKeys.SelectedKeys)
|
||||
{
|
||||
if (pair.Value != string.Empty)
|
||||
{
|
||||
try
|
||||
{
|
||||
QuickLayoutKeysWrapper wrapper = new QuickLayoutKeysWrapper
|
||||
{
|
||||
Key = int.Parse(pair.Key),
|
||||
Uuid = pair.Value,
|
||||
};
|
||||
|
||||
zoneSettings.QuickLayoutKeys.Add(wrapper);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(zoneSettings, _options);
|
||||
@@ -770,39 +810,25 @@ namespace FancyZonesEditor.Utils
|
||||
continue;
|
||||
}
|
||||
|
||||
LayoutModel layout;
|
||||
if (zoneSet.Type == CanvasLayoutModel.ModelTypeID)
|
||||
LayoutModel layout = null;
|
||||
try
|
||||
{
|
||||
var info = JsonSerializer.Deserialize<CanvasInfoWrapper>(zoneSet.Info.GetRawText(), _options);
|
||||
|
||||
var zones = new List<Int32Rect>();
|
||||
foreach (var zone in info.Zones)
|
||||
if (zoneSet.Type == CanvasLayoutModel.ModelTypeID)
|
||||
{
|
||||
zones.Add(new Int32Rect { X = (int)zone.X, Y = (int)zone.Y, Width = (int)zone.Width, Height = (int)zone.Height });
|
||||
layout = ParseCanvasInfo(zoneSet);
|
||||
}
|
||||
else if (zoneSet.Type == GridLayoutModel.ModelTypeID)
|
||||
{
|
||||
layout = ParseGridInfo(zoneSet);
|
||||
}
|
||||
|
||||
layout = new CanvasLayoutModel(zoneSet.Uuid, zoneSet.Name, LayoutType.Custom, zones, info.RefWidth, info.RefHeight);
|
||||
layout.SensitivityRadius = info.SensitivityRadius;
|
||||
}
|
||||
else if (zoneSet.Type == GridLayoutModel.ModelTypeID)
|
||||
catch (Exception)
|
||||
{
|
||||
var info = JsonSerializer.Deserialize<GridInfoWrapper>(zoneSet.Info.GetRawText(), _options);
|
||||
|
||||
var cells = new int[info.Rows, info.Columns];
|
||||
for (int row = 0; row < info.Rows; row++)
|
||||
{
|
||||
for (int column = 0; column < info.Columns; column++)
|
||||
{
|
||||
cells[row, column] = info.CellChildMap[row][column];
|
||||
}
|
||||
}
|
||||
|
||||
layout = new GridLayoutModel(zoneSet.Uuid, zoneSet.Name, LayoutType.Custom, info.Rows, info.Columns, info.RowsPercentage, info.ColumnsPercentage, cells);
|
||||
layout.SensitivityRadius = info.SensitivityRadius;
|
||||
(layout as GridLayoutModel).ShowSpacing = info.ShowSpacing;
|
||||
(layout as GridLayoutModel).Spacing = info.Spacing;
|
||||
result = false;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
if (layout == null)
|
||||
{
|
||||
result = false;
|
||||
continue;
|
||||
@@ -823,29 +849,105 @@ namespace FancyZonesEditor.Utils
|
||||
|
||||
foreach (var wrapper in templateLayouts)
|
||||
{
|
||||
var type = JsonTagToLayoutType(wrapper.Type);
|
||||
LayoutType type = JsonTagToLayoutType(wrapper.Type);
|
||||
LayoutModel layout = MainWindowSettingsModel.DefaultModels[(int)type];
|
||||
|
||||
foreach (var layout in MainWindowSettingsModel.DefaultModels)
|
||||
layout.SensitivityRadius = wrapper.SensitivityRadius;
|
||||
layout.TemplateZoneCount = wrapper.ZoneCount;
|
||||
|
||||
if (layout is GridLayoutModel grid)
|
||||
{
|
||||
if (layout.Type == type)
|
||||
{
|
||||
layout.SensitivityRadius = wrapper.SensitivityRadius;
|
||||
layout.TemplateZoneCount = wrapper.ZoneCount;
|
||||
|
||||
if (layout is GridLayoutModel grid)
|
||||
{
|
||||
grid.ShowSpacing = wrapper.ShowSpacing;
|
||||
grid.Spacing = wrapper.Spacing;
|
||||
}
|
||||
|
||||
layout.InitTemplateZones();
|
||||
}
|
||||
grid.ShowSpacing = wrapper.ShowSpacing;
|
||||
grid.Spacing = wrapper.Spacing;
|
||||
}
|
||||
|
||||
layout.InitTemplateZones();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SetQuickLayoutSwitchKeys(List<QuickLayoutKeysWrapper> quickSwitchKeys)
|
||||
{
|
||||
if (quickSwitchKeys == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MainWindowSettingsModel.QuickKeys.CleanUp();
|
||||
foreach (var wrapper in quickSwitchKeys)
|
||||
{
|
||||
MainWindowSettingsModel.QuickKeys.SelectKey(wrapper.Key.ToString(), wrapper.Uuid);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private CanvasLayoutModel ParseCanvasInfo(CustomLayoutWrapper wrapper)
|
||||
{
|
||||
var info = JsonSerializer.Deserialize<CanvasInfoWrapper>(wrapper.Info.GetRawText(), _options);
|
||||
|
||||
var zones = new List<Int32Rect>();
|
||||
foreach (var zone in info.Zones)
|
||||
{
|
||||
if (zone.Width < 0 || zone.Height < 0)
|
||||
{
|
||||
// Malformed data
|
||||
return null;
|
||||
}
|
||||
|
||||
zones.Add(new Int32Rect { X = zone.X, Y = zone.Y, Width = zone.Width, Height = zone.Height });
|
||||
}
|
||||
|
||||
var layout = new CanvasLayoutModel(wrapper.Uuid, wrapper.Name, LayoutType.Custom, zones, Math.Max(info.RefWidth, 0), Math.Max(info.RefHeight, 0));
|
||||
layout.SensitivityRadius = info.SensitivityRadius;
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
private GridLayoutModel ParseGridInfo(CustomLayoutWrapper wrapper)
|
||||
{
|
||||
var info = JsonSerializer.Deserialize<GridInfoWrapper>(wrapper.Info.GetRawText(), _options);
|
||||
|
||||
// Check if rows and columns are valid
|
||||
if (info.Rows <= 0 || info.Columns <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if percentage is valid. Otherwise, Editor could crash on layout rendering.
|
||||
foreach (int percent in info.RowsPercentage)
|
||||
{
|
||||
if (percent < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (int percent in info.ColumnsPercentage)
|
||||
{
|
||||
if (percent < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var cells = new int[info.Rows, info.Columns];
|
||||
for (int row = 0; row < info.Rows; row++)
|
||||
{
|
||||
for (int column = 0; column < info.Columns; column++)
|
||||
{
|
||||
cells[row, column] = info.CellChildMap[row][column];
|
||||
}
|
||||
}
|
||||
|
||||
var layout = new GridLayoutModel(wrapper.Uuid, wrapper.Name, LayoutType.Custom, info.Rows, info.Columns, info.RowsPercentage, info.ColumnsPercentage, cells);
|
||||
layout.SensitivityRadius = info.SensitivityRadius;
|
||||
layout.ShowSpacing = info.ShowSpacing;
|
||||
layout.Spacing = info.Spacing;
|
||||
return layout;
|
||||
}
|
||||
|
||||
private LayoutType JsonTagToLayoutType(string tag)
|
||||
{
|
||||
switch (tag)
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace FancyZonesEditor.ViewModels
|
||||
|
||||
double maxMultiplier = MaxPreviewDisplaySize / maxDimension;
|
||||
double minMultiplier = MinPreviewDisplaySize / minDimension;
|
||||
DesktopPreviewMultiplier = (minMultiplier + maxMultiplier) / 3.5;
|
||||
DesktopPreviewMultiplier = (minMultiplier + maxMultiplier) / 2.5;
|
||||
}
|
||||
|
||||
private void RaisePropertyChanged(string propertyName)
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Soubor zones-settings.json obsahuje chybná data.]]></Val>
|
||||
<Val><![CDATA[Rozložení, které obsahovalo neplatná data, se odebralo.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Chcete pokračovat? Chybná data se ztratí.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Klikněte a přetahujte mezi zónami.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Sloučit nebo odstranit:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Pokud chcete změnit orientaci rozdělovače, podržte klávesu Shift.]D;]A;Pokud chcete sloučit zóny, podržte levé tlačítko myši, přetáhněte myš na zónu, která se má sloučit, uvolněte tlačítko myši a klikněte na Sloučit zóny.]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Pokud chcete rychle použít rozložení, vyberte klávesu (Win + Ctrl+ Alt + klávesa).]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Žádná]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Pro svislé rozdělení podržte klávesu Shift.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Rozdělovač:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA["zones-settings.json" enthält nicht wohlgeformte Daten.]]></Val>
|
||||
<Val><![CDATA[Ein Layout, das ungültige Daten enthielt, wurde entfernt.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Möchten Sie den Vorgang fortsetzen? Nicht wohlgeformte Daten gehen verloren.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Klicken und ziehen Sie Elemente von einer Zone in eine andere.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Zusammenführen/Löschen:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Halten Sie die UMSCHALTTASTE gedrückt, um die Ausrichtung des Splitters zu ändern.]D;]A;Um Zonen zusammenzuführen, halten Sie die linke Maustaste gedrückt, ziehen Sie die Maustaste auf die zusammenzuführende Zone, lassen Sie die Maustaste los, und klicken Sie auf "Zonen zusammenführen".]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Wählen Sie eine Taste für den schnellen Layoutwechsel aus (WINDOWS+STRG+ALT+Taste).]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Keine]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Halten Sie für eine vertikale Teilung die Umschalttaste gedrückt.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Teilungselement:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -451,6 +451,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Permite hacer clic y arrastrar entre zonas.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Combinar o eliminar:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +505,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Mantenga presionada la tecla Mayús para cambiar la orientación del separador.]D;]A;Para combinar zonas, mantenga presionado el botón primario del mouse, arrastre el mouse a la zona que quiera combinar, suelte el botón del mouse y haga clic en "Merge zones".]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +514,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Seleccione una clave para aplicar rápidamente el diseño (Win + Ctrl + Alt + clave).]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Ninguno]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +589,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Mantenga presionada la tecla Mayús para dividir verticalmente.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Separador:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -451,6 +451,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Cliquez et faites glisser entre les zones.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Fusionner/supprimer :]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +505,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Maintenez la touche Maj enfoncée pour changer l'orientation du séparateur.]D;]A;Pour fusionner des zones, maintenez le bouton gauche de la souris enfoncé, faites glisser la souris sur la zone à fusionner, relâchez le bouton de la souris et cliquez sur « Fusionner les zones ».]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +514,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Sélectionner une touche pour appliquer rapidement la disposition (Win + Ctrl + Alt + touche)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Aucun]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +589,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Maintenez la touche Maj enfoncée pour la division verticale.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Séparateur :]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[A zones-settings.json szabálytalan adatokat tartalmaz.]]></Val>
|
||||
<Val><![CDATA[A rendszer eltávolított egy érvénytelen adatot tartalmazó elrendezést.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Folytatja? A szabálytalan adatok el fognak veszni.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Kattintson és húzza át a kurzort a zónákon.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Egyesítés/törlés:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Tartsa nyomva a Shift billentyűt a felosztó tájolásának módosításához.]D;]A;A zónák egyesítéséhez tartsa nyomva a bal egérgombot, húzza az egérmutatót az egyesíteni kívánt zónára, engedje el az egérgombot, majd kattintson a Zónák egyesítése elemre.]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Válasszon egy billentyűt az elrendezés gyors alkalmazásához (Win + Ctrl + Alt + billentyű)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Nincs]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Tartsa nyomva a Shift billentyűt a vertikális felosztáshoz.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Felosztó:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA['zones-settings.json' contiene dati non validi.]]></Val>
|
||||
<Val><![CDATA[Un layout contenente dati non validi è stato rimosso.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Continuare? I dati con formato non valido andranno persi.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Fare clic e trascinare tra le zone.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Unisci/Elimina:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Tenere premuto il tasto MAIUSC per modificare l'orientamento della barra di divisione.]D;]A;Per unire le zone, tenere premuto il pulsante sinistro del mouse, trascinare il mouse sulla zona da unire, rilasciare il pulsante del mouse e fare clic su "Unisci zone".]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Selezionare un tasto per applicare rapidamente il layout (WINDOWS + CTRL + ALT + tasto)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Nessuno]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Tenere premuto il tasto MAIUSC per la divisione verticale.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Barra di divisione:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA['zones-settings.json' に誤った形式のデータが含まれています。]]></Val>
|
||||
<Val><![CDATA[無効なデータを含むレイアウトが削除されました。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[続行しますか? 誤った形式のデータは失われます。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[クリックしてゾーン間でドラッグします。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[マージまたは削除:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[分割の方向を変更するには、Shift キーを押し続けます。]D;]A;ゾーンをマージするには、マウスの左ボタンを押しながらマージするゾーンにマウスをドラッグし、マウス ボタンを放して、[ゾーンのマージ]5D; をクリックします。]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[レイアウトをすばやく適用するためのキーを選択します (Win + Ctrl + Alt + キー)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[なし]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[垂直分割の場合は Shift キーを押したままにします。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[スプリッター:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA['zones-settings.json'에 잘못된 형식의 데이터가 있습니다.]]></Val>
|
||||
<Val><![CDATA[잘못된 데이터가 포함된 레이아웃이 제거되었습니다.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[계속하시겠습니까? 잘못된 형식의 데이터가 손실됩니다.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[클릭하여 영역을 가로질러 끕니다.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[병합/삭제:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[<Shift> 키를 길게 눌러 분할기의 방향을 변경합니다.]D;]A;영역을 병합하려면 왼쪽 마우스 단추를 누른 상태에서 병합할 영역으로 마우스를 끌고 마우스 단추를 놓은 후 "영역 병합"을 클릭합니다.]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[레이아웃을 빠르게 적용하려면 키 선택(Win + Ctrl + Alt + 키)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[없음]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[세로 분할을 수행하려면 <Shift> 키를 길게 누릅니다.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[분할기:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[zones-settings.json' bevat gegevens met ongeldige indeling.]]></Val>
|
||||
<Val><![CDATA[Een indeling die ongeldige gegevens bevat, is verwijderd.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Wilt u doorgaan? Gegevens met een ongeldige indeling gaan verloren.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Klik en sleep door zones heen.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Samenvoegen/verwijderen:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Houd SHIFT ingedrukt om de richting van de splitser te wijzigen.]D;]A;Als u zones wilt samenvoegen, houdt u de linkermuisknop ingedrukt, sleept u de muis naar de zone om samen te voegen, laat u de muisknop los en klikt u op Zones samenvoegen.]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Selecteer een toets om de indeling snel toe te passen (Win+Ctrl+Alt+toets)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Geen]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Houd de Shift-toets ingedrukt voor verticale splitsing.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Splitser:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Plik „zones-settings.json” zawiera źle sformułowane dane.]]></Val>
|
||||
<Val><![CDATA[Układ, który zawierał nieprawidłowe dane, został usunięty.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Chcesz kontynuować? Uszkodzone dane zostaną utracone.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Kliknij i przeciągnij między strefami.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Scalanie/usuwanie:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Przytrzymaj wciśnięty klawisz Shift, aby zmienić orientację rozdzielacza.]D;]A;Aby scalić strefy, przytrzymaj lewy przycisk myszy, przeciągnij mysz do strefy, z którą chcesz scalić, zwolnij przycisk myszy i kliknij pozycję „Scal strefy”.]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Wybierz klawisz, aby szybko zastosować układ (Win + Ctrl + Alt + klawisz)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Brak]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Naciśnij klawisz Shift, aby podzielić pionowo.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Rozdzielacz:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -451,6 +451,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Clique no item e arraste entre as zonas.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Mesclar/Excluir:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +505,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Mantenha pressionada a tecla Shift para alterar a orientação do divisor.]D;]A;Para mesclar zonas, mantenha pressionado o botão esquerdo do mouse, arraste o mouse até a zona a ser mesclada, solte o botão do mouse e clique em "Mesclar zonas".]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +514,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Selecione uma tecla para aplicar o layout rapidamente (Win + Ctrl + Alt + tecla)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Nenhuma]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +589,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Mantenha a tecla Shift pressionada para fazer uma divisão vertical.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Divisor:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -451,6 +451,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Clique e arraste pelas zonas.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Unir/Eliminar:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +505,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Mantenha a tecla Shift premida para alterar a orientação do divisor.]D;]A;Para intercalar zonas, mantenha premido o botão esquerdo do rato, arraste o rato até à zona a intercalar, solte o botão do rato e clique em "Intercalar zonas".]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +514,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Selecione uma tecla para aplicar rapidamente o esquema (Windows + Ctrl + Alt + tecla)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Nenhum]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +589,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Mantenha premida a tecla Shift para divisão vertical.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Divisor:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA["zones-settings.json" содержит неправильно сформированные данные.]]></Val>
|
||||
<Val><![CDATA[Макет, содержащий недопустимые данные, удален.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Вы хотите продолжить? Неправильно сформированные данные будут утеряны.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Щелкните и перетащите между зонами.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Объединение или удаление:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Удерживайте клавишу SHIFT, чтобы изменить ориентацию разделителя.]D;]A;Чтобы объединить зоны, удерживайте нажатой левую кнопку мыши и перетащите указатель в зону для объединения, после чего отпустите кнопку мыши и щелкните "Объединить зоны".]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Выберите клавишу для быстрого применения макета (WIN + CTRL + ALT + клавиша)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Нет]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Для разделения по вертикали удерживайте нажатой клавишу SHIFT.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Разделитель:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[zones-settings.json innehåller felaktigt utformade data.]]></Val>
|
||||
<Val><![CDATA[En layout som innehöll ogiltiga data har tagits bort.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Vill du fortsätta? Felaktigt utformade data kommer att gå förlorade.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Klicka och dra mellan zoner.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Sammanslå/ta bort:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Håll ned tangenten Skift om du vill ändra orienteringen för delare.]D;]A;Om du vill sammanslå zoner håller du ned vänster musknapp och drar musen till den zon som ska sammanslås. Sedan släpper du musknappen och klickar på "Sammanslå zoner".]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Välj en tangent för att snabbt tillämpa layouten (Win + Ctrl + Alt + tangent)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Ingen]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Håll ned Skift-tangenten för vertikal delning.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Delare:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -451,6 +451,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Tıklayın ve bölgeler arasında sürükleyin.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Birleştir/Sil:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +505,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Update" Orig="New">
|
||||
<Val><![CDATA[Ayırıcının yönünü değiştirmek için Shift tuşuna basılı tutun.]D;]A;Bölgeleri birleştirmek için bölgeleri seçin ve "Birleştir" seçeneğine tıklayın.]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +514,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Düzeni hızlıca uygulamak için bir tuş seçin (Win + Ctrl + Alt + tuş)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Yok]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +589,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Dikey bölme için Shift tuşunu basılı tutun.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Bölümlendirici:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA["zones-settings.json" 包含格式错误的数据。]]></Val>
|
||||
<Val><![CDATA[包含了无效数据的布局已被删除。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[是否要继续操作? 格式错误的数据将丢失。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[单击并跨区域拖动。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[合并/删除:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[按住 Shift 键可以改变拆分器的方向。]D;]A;若要合并区域,请按住鼠标左键,将鼠标拖到要合并的区域,释放鼠标按钮,然后单击“合并区域”。]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[选择一个键来快速应用布局(Windows 键 + Ctrl + Alt + 你选择的键)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[无]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[按住 Shift 键进行垂直拆分。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[拆分器:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
@@ -334,11 +334,11 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Malformed_Data" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_Message" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['zones-settings.json' contains malformed data.]]></Val>
|
||||
<Val><![CDATA[A layout that contained invalid data has been removed.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA['zones-settings.json' 包含格式錯誤的資料。]]></Val>
|
||||
<Val><![CDATA[已移除包含無效資料的配置。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
@@ -352,15 +352,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Parsing_Zones_Settings_User_Choice" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Would you like to continue? Malformed data will be lost.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[您要繼續嗎? 格式錯誤的資料將會遺失。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Error_Persisting_Custom_Layout" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Error persisting custom layout]]></Val>
|
||||
@@ -451,6 +442,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Click and drag across zones.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[按一下並在區域之間拖曳。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";MergeName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge/Delete:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[合併/刪除:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Merge_zones" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Merge zones]]></Val>
|
||||
@@ -487,18 +496,6 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Note_Custom_Table" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, hold down the left mouse button, drag the mouse to the zone to merge, release the mouse button and click "Merge zones".]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[按住 Shift 鍵可變更分隔器的方向。]D;]A;若要合併區域,請按住滑鼠左鍵,將滑鼠拖曳到要合併的區域,放開滑鼠左鍵然後按一下 [合併區域]5D;。]]></Val>
|
||||
</Tgt>
|
||||
<Prev Cat="Text">
|
||||
<Val><![CDATA[Hold down Shift key to change orientation of splitter.]D;]A;To merge zones, select the zones and click "merge".]]></Val>
|
||||
</Prev>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";NumberOfZones" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Number of zones]]></Val>
|
||||
@@ -508,6 +505,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";QuickKey_Select" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Select a key to quickly apply the layout (Win + Ctrl + Alt + key)]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[選取按鍵以快速套用版面配置 (Windows 鍵 + Ctrl + Alt + 按鍵)]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Quick_Key_None" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[None]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[無]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Reset_Layout" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Reset layout]]></Val>
|
||||
@@ -565,6 +580,24 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterDescription" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Hold Shift key for vertical split.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[按住 Shift 鍵可垂直分割。]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";SplitterName" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[Splitter:]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[分隔器:]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";Template_Layout_Blank" ItemType="0;.resx" PsrId="211" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA[No layout]]></Val>
|
||||
|
||||
53
src/modules/fancyzones/lib/CallTracer.cpp
Normal file
53
src/modules/fancyzones/lib/CallTracer.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "pch.h"
|
||||
#include "CallTracer.h"
|
||||
#include <thread>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Non-localizable
|
||||
const std::string entering = " Enter";
|
||||
const std::string exiting = " Exit";
|
||||
|
||||
std::mutex indentLevelMutex;
|
||||
std::map<std::thread::id, int> indentLevel;
|
||||
|
||||
std::string GetIndentation()
|
||||
{
|
||||
std::unique_lock lock(indentLevelMutex);
|
||||
int level = indentLevel[std::this_thread::get_id()];
|
||||
|
||||
if (level <= 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string(2 * min(level, 64) - 1, ' ') + " - ";
|
||||
}
|
||||
}
|
||||
|
||||
void Indent()
|
||||
{
|
||||
std::unique_lock lock(indentLevelMutex);
|
||||
indentLevel[std::this_thread::get_id()]++;
|
||||
}
|
||||
|
||||
void Unindent()
|
||||
{
|
||||
std::unique_lock lock(indentLevelMutex);
|
||||
indentLevel[std::this_thread::get_id()]--;
|
||||
}
|
||||
}
|
||||
|
||||
CallTracer::CallTracer(const char* functionName) :
|
||||
functionName(functionName)
|
||||
{
|
||||
Logger::trace((GetIndentation() + functionName + entering).c_str());
|
||||
Indent();
|
||||
}
|
||||
|
||||
CallTracer::~CallTracer()
|
||||
{
|
||||
Unindent();
|
||||
Logger::trace((GetIndentation() + functionName + exiting).c_str());
|
||||
}
|
||||
13
src/modules/fancyzones/lib/CallTracer.h
Normal file
13
src/modules/fancyzones/lib/CallTracer.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/logger/logger.h"
|
||||
|
||||
#define _TRACER_ CallTracer callTracer(__FUNCTION__)
|
||||
|
||||
class CallTracer
|
||||
{
|
||||
std::string functionName;
|
||||
public:
|
||||
CallTracer(const char* functionName);
|
||||
~CallTracer();
|
||||
};
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "VirtualDesktopUtils.h"
|
||||
#include "MonitorWorkAreaHandler.h"
|
||||
#include "util.h"
|
||||
#include "CallTracer.h"
|
||||
|
||||
#include <lib/SecondaryMouseButtonsHook.h>
|
||||
|
||||
@@ -33,6 +34,30 @@ enum class DisplayChangeType
|
||||
namespace
|
||||
{
|
||||
constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16;
|
||||
|
||||
struct require_read_lock
|
||||
{
|
||||
template<typename T>
|
||||
require_read_lock(const std::shared_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
require_read_lock(const std::unique_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
};
|
||||
|
||||
struct require_write_lock
|
||||
{
|
||||
template<typename T>
|
||||
require_write_lock(const std::unique_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Non-localizable strings
|
||||
@@ -89,6 +114,7 @@ public:
|
||||
|
||||
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_windowMoveHandler.MoveSizeEnd(window, ptScreen, m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId));
|
||||
}
|
||||
@@ -182,40 +208,16 @@ public:
|
||||
}
|
||||
|
||||
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
|
||||
void OnDisplayChange(DisplayChangeType changeType) noexcept;
|
||||
void AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) noexcept;
|
||||
void OnDisplayChange(DisplayChangeType changeType, require_write_lock) noexcept;
|
||||
void AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId, require_write_lock) noexcept;
|
||||
|
||||
protected:
|
||||
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
|
||||
|
||||
private:
|
||||
struct require_read_lock
|
||||
{
|
||||
template<typename T>
|
||||
require_read_lock(const std::shared_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
require_read_lock(const std::unique_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
};
|
||||
|
||||
struct require_write_lock
|
||||
{
|
||||
template<typename T>
|
||||
require_write_lock(const std::unique_lock<T>& lock)
|
||||
{
|
||||
lock;
|
||||
}
|
||||
};
|
||||
|
||||
void UpdateZoneWindows() noexcept;
|
||||
void UpdateWindowsPositions() noexcept;
|
||||
void CycleActiveZoneSet(DWORD vkCode) noexcept;
|
||||
void UpdateZoneWindows(require_write_lock) noexcept;
|
||||
void UpdateWindowsPositions(require_write_lock) noexcept;
|
||||
bool OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept;
|
||||
bool OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept;
|
||||
bool OnSnapHotkey(DWORD vkCode) noexcept;
|
||||
@@ -230,12 +232,15 @@ private:
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept;
|
||||
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<size_t>& zoneIndexSet) noexcept;
|
||||
|
||||
void OnEditorExitEvent() noexcept;
|
||||
void UpdateZoneSets() noexcept;
|
||||
void OnEditorExitEvent(require_write_lock) noexcept;
|
||||
void UpdateZoneSets(require_write_lock) noexcept;
|
||||
bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept;
|
||||
void ApplyQuickLayout(int key) noexcept;
|
||||
void FlashZones(require_write_lock) noexcept;
|
||||
|
||||
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
|
||||
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
|
||||
HMONITOR WorkAreaKeyFromWindow(HWND window) noexcept;
|
||||
|
||||
const HINSTANCE m_hinstance{};
|
||||
|
||||
@@ -264,6 +269,7 @@ private:
|
||||
static UINT WM_PRIV_FILE_UPDATE; // Scheduled when the a watched file is updated
|
||||
|
||||
static UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press
|
||||
static UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout
|
||||
|
||||
// Did we terminate the editor or was it closed cleanly?
|
||||
enum class EditorExitKind : byte
|
||||
@@ -281,6 +287,7 @@ UINT FancyZones::WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26
|
||||
UINT FancyZones::WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
|
||||
UINT FancyZones::WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}");
|
||||
UINT FancyZones::WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{763c03a3-03d9-4cde-8d71-f0358b0b4b52}");
|
||||
UINT FancyZones::WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}");
|
||||
|
||||
// IFancyZones
|
||||
IFACEMETHODIMP_(void)
|
||||
@@ -421,6 +428,7 @@ std::pair<winrt::com_ptr<IZoneWindow>, std::vector<size_t>> FancyZones::GetAppZo
|
||||
|
||||
void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<size_t>& zoneIndexSet) noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
auto& fancyZonesData = FancyZonesDataInstance();
|
||||
if (!fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window, zoneWindow->UniqueId()))
|
||||
{
|
||||
@@ -550,18 +558,6 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
bool const ctrl = GetAsyncKeyState(VK_CONTROL) & 0x8000;
|
||||
if ((win && !shift && !ctrl) || (win && ctrl && alt))
|
||||
{
|
||||
// Temporarily disable Win+Ctrl+Number functionality
|
||||
// if (ctrl)
|
||||
// {
|
||||
// if ((info->vkCode >= '0') && (info->vkCode <= '9'))
|
||||
// {
|
||||
// // Win+Ctrl+Number will cycle through ZoneSets
|
||||
// Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
|
||||
// CycleActiveZoneSet(info->vkCode);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
if ((info->vkCode == VK_RIGHT) || (info->vkCode == VK_LEFT) || (info->vkCode == VK_UP) || (info->vkCode == VK_DOWN))
|
||||
{
|
||||
if (ShouldProcessSnapHotkey(info->vkCode))
|
||||
@@ -573,14 +569,34 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
}
|
||||
}
|
||||
}
|
||||
// Temporarily disable Win+Ctrl+Number functionality
|
||||
//else if (m_inMoveSize && (info->vkCode >= '0') && (info->vkCode <= '9'))
|
||||
//{
|
||||
// // This allows you to cycle through ZoneSets while dragging a window
|
||||
// Trace::FancyZones::OnKeyDown(info->vkCode, win, false /*control*/, true /*inMoveSize*/);
|
||||
// CycleActiveZoneSet(info->vkCode);
|
||||
// return false;
|
||||
//}
|
||||
|
||||
if (m_settings->GetSettings()->quickLayoutSwitch)
|
||||
{
|
||||
int digitPressed = -1;
|
||||
if ('0' <= info->vkCode && info->vkCode <= '9')
|
||||
{
|
||||
digitPressed = info->vkCode - '0';
|
||||
}
|
||||
else if (VK_NUMPAD0 <= info->vkCode && info->vkCode <= VK_NUMPAD9)
|
||||
{
|
||||
digitPressed = info->vkCode - VK_NUMPAD0;
|
||||
}
|
||||
|
||||
bool dragging = m_windowMoveHandler.InMoveSize();
|
||||
bool changeLayoutWhileNotDragging = !dragging && !shift && win && ctrl && alt && digitPressed != -1;
|
||||
bool changeLayoutWhileDragging = dragging && digitPressed != -1;
|
||||
|
||||
if (changeLayoutWhileNotDragging || changeLayoutWhileDragging)
|
||||
{
|
||||
auto quickKeysMap = FancyZonesDataInstance().GetLayoutQuickKeys();
|
||||
if (std::any_of(quickKeysMap.begin(), quickKeysMap.end(), [=](auto item) { return item.second == digitPressed; }))
|
||||
{
|
||||
PostMessageW(m_window, WM_PRIV_QUICK_LAYOUT_KEY, 0, static_cast<LPARAM>(digitPressed));
|
||||
Trace::FancyZones::QuickLayoutSwitched(changeLayoutWhileNotDragging);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_windowMoveHandler.IsDragEnabled() && shift)
|
||||
{
|
||||
@@ -592,6 +608,7 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
// IFancyZonesCallback
|
||||
void FancyZones::ToggleEditor() noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
if (m_terminateEditorEvent)
|
||||
@@ -630,7 +647,7 @@ void FancyZones::ToggleEditor() noexcept
|
||||
wil::unique_cotaskmem_string virtualDesktopId;
|
||||
if (!SUCCEEDED(StringFromCLSID(m_currentDesktopId, &virtualDesktopId)))
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -660,7 +677,7 @@ void FancyZones::ToggleEditor() noexcept
|
||||
{
|
||||
params += FancyZonesUtils::GenerateUniqueIdAllMonitorsArea(virtualDesktopId.get()) + divider; /* Monitor id where the Editor should be opened */
|
||||
}
|
||||
|
||||
|
||||
// device id map
|
||||
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
|
||||
|
||||
@@ -751,13 +768,16 @@ void FancyZones::ToggleEditor() noexcept
|
||||
|
||||
void FancyZones::SettingsChanged() noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
std::unique_lock writeLock(m_lock);
|
||||
|
||||
// Update the hotkey
|
||||
UnregisterHotKey(m_window, 1);
|
||||
RegisterHotKey(m_window, 1, m_settings->GetSettings()->editorHotkey.get_modifiers(), m_settings->GetSettings()->editorHotkey.get_code());
|
||||
|
||||
// Needed if we toggled spanZonesAcrossMonitors
|
||||
m_workAreaHandler.Clear();
|
||||
OnDisplayChange(DisplayChangeType::Initialization);
|
||||
OnDisplayChange(DisplayChangeType::Initialization, writeLock);
|
||||
}
|
||||
|
||||
// IZoneWindowHost
|
||||
@@ -766,7 +786,8 @@ FancyZones::MoveWindowsOnActiveZoneSetChange() noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->zoneSetChange_moveWindows)
|
||||
{
|
||||
UpdateWindowsPositions();
|
||||
std::unique_lock writeLock(m_lock);
|
||||
UpdateWindowsPositions(writeLock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,8 +810,9 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
{
|
||||
// Changes in taskbar position resulted in different size of work area.
|
||||
// Invalidate cached work-areas so they can be recreated with latest information.
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_workAreaHandler.Clear();
|
||||
OnDisplayChange(DisplayChangeType::WorkArea);
|
||||
OnDisplayChange(DisplayChangeType::WorkArea, writeLock);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -798,8 +820,9 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
case WM_DISPLAYCHANGE:
|
||||
{
|
||||
// Display resolution changed. Invalidate cached work-areas so they can be recreated with latest information.
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_workAreaHandler.Clear();
|
||||
OnDisplayChange(DisplayChangeType::DisplayChange);
|
||||
OnDisplayChange(DisplayChangeType::DisplayChange, writeLock);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -814,11 +837,13 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
}
|
||||
else if (message == WM_PRIV_VD_INIT)
|
||||
{
|
||||
OnDisplayChange(DisplayChangeType::Initialization);
|
||||
std::unique_lock writeLock(m_lock);
|
||||
OnDisplayChange(DisplayChangeType::Initialization, writeLock);
|
||||
}
|
||||
else if (message == WM_PRIV_VD_SWITCH)
|
||||
{
|
||||
OnDisplayChange(DisplayChangeType::VirtualDesktop);
|
||||
std::unique_lock writeLock(m_lock);
|
||||
OnDisplayChange(DisplayChangeType::VirtualDesktop, writeLock);
|
||||
}
|
||||
else if (message == WM_PRIV_VD_UPDATE)
|
||||
{
|
||||
@@ -832,7 +857,8 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
{
|
||||
if (lparam == static_cast<LPARAM>(EditorExitKind::Exit))
|
||||
{
|
||||
OnEditorExitEvent();
|
||||
std::unique_lock writeLock(m_lock);
|
||||
OnEditorExitEvent(writeLock);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -869,7 +895,12 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
else if (message == WM_PRIV_FILE_UPDATE)
|
||||
{
|
||||
FancyZonesDataInstance().LoadFancyZonesData();
|
||||
UpdateZoneSets();
|
||||
std::unique_lock writeLock(m_lock);
|
||||
UpdateZoneSets(writeLock);
|
||||
}
|
||||
else if (message == WM_PRIV_QUICK_LAYOUT_KEY)
|
||||
{
|
||||
ApplyQuickLayout(static_cast<int>(lparam));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -881,8 +912,9 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
|
||||
void FancyZones::OnDisplayChange(DisplayChangeType changeType, require_write_lock lock) noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
if (changeType == DisplayChangeType::VirtualDesktop ||
|
||||
changeType == DisplayChangeType::Initialization)
|
||||
{
|
||||
@@ -907,21 +939,20 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
UpdateZoneWindows();
|
||||
UpdateZoneWindows(lock);
|
||||
|
||||
if ((changeType == DisplayChangeType::WorkArea) || (changeType == DisplayChangeType::DisplayChange))
|
||||
{
|
||||
if (m_settings->GetSettings()->displayChange_moveWindows)
|
||||
{
|
||||
UpdateWindowsPositions();
|
||||
UpdateWindowsPositions(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) noexcept
|
||||
void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId, require_write_lock) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
|
||||
_TRACER_;
|
||||
if (m_workAreaHandler.IsNewWorkArea(m_currentDesktopId, monitor))
|
||||
{
|
||||
wil::unique_cotaskmem_string virtualDesktopId;
|
||||
@@ -968,7 +999,7 @@ LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam,
|
||||
DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
void FancyZones::UpdateZoneWindows() noexcept
|
||||
void FancyZones::UpdateZoneWindows(require_write_lock lock) noexcept
|
||||
{
|
||||
// Mapping between display device name and device index (operating system identifies each display device with an index value).
|
||||
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
|
||||
@@ -976,6 +1007,7 @@ void FancyZones::UpdateZoneWindows() noexcept
|
||||
{
|
||||
FancyZones* fancyZones;
|
||||
std::unordered_map<std::wstring, DWORD>* displayDeviceIdx;
|
||||
require_write_lock lock;
|
||||
};
|
||||
|
||||
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL {
|
||||
@@ -987,23 +1019,23 @@ void FancyZones::UpdateZoneWindows() noexcept
|
||||
FancyZones* fancyZones = params->fancyZones;
|
||||
|
||||
std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(mi.szDevice, displayDeviceIdxMap);
|
||||
fancyZones->AddZoneWindow(monitor, deviceId);
|
||||
fancyZones->AddZoneWindow(monitor, deviceId, params->lock);
|
||||
}
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
{
|
||||
AddZoneWindow(nullptr, {});
|
||||
AddZoneWindow(nullptr, {}, lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
capture capture{ this, &displayDeviceIdxMap };
|
||||
capture capture{ this, &displayDeviceIdxMap, lock };
|
||||
EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(&capture));
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZones::UpdateWindowsPositions() noexcept
|
||||
void FancyZones::UpdateWindowsPositions(require_write_lock) noexcept
|
||||
{
|
||||
auto callback = [](HWND window, LPARAM data) -> BOOL {
|
||||
size_t bitmask = reinterpret_cast<size_t>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID));
|
||||
@@ -1020,7 +1052,6 @@ void FancyZones::UpdateWindowsPositions() noexcept
|
||||
}
|
||||
|
||||
auto strongThis = reinterpret_cast<FancyZones*>(data);
|
||||
std::unique_lock writeLock(strongThis->m_lock);
|
||||
auto zoneWindow = strongThis->m_workAreaHandler.GetWorkArea(window);
|
||||
if (zoneWindow)
|
||||
{
|
||||
@@ -1032,37 +1063,10 @@ void FancyZones::UpdateWindowsPositions() noexcept
|
||||
EnumWindows(callback, reinterpret_cast<LPARAM>(this));
|
||||
}
|
||||
|
||||
void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
|
||||
{
|
||||
auto window = GetForegroundWindow();
|
||||
if (FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
if (monitor)
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
|
||||
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
|
||||
if (zoneWindow)
|
||||
{
|
||||
zoneWindow->CycleActiveZoneSet(vkCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept
|
||||
{
|
||||
HMONITOR current;
|
||||
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
{
|
||||
current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
}
|
||||
_TRACER_;
|
||||
HMONITOR current = WorkAreaKeyFromWindow(window);
|
||||
|
||||
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
|
||||
if (current && monitorInfo.size() > 1 && m_settings->GetSettings()->moveWindowAcrossMonitors)
|
||||
@@ -1120,16 +1124,7 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce
|
||||
|
||||
bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept
|
||||
{
|
||||
HMONITOR current;
|
||||
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
{
|
||||
current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
}
|
||||
HMONITOR current = WorkAreaKeyFromWindow(window);
|
||||
|
||||
auto allMonitors = FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>();
|
||||
|
||||
@@ -1283,6 +1278,7 @@ bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle
|
||||
|
||||
void FancyZones::RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
std::unique_lock writeLock(m_lock);
|
||||
|
||||
m_workAreaHandler.RegisterUpdates(ids);
|
||||
@@ -1305,14 +1301,14 @@ bool FancyZones::IsSplashScreen(HWND window)
|
||||
return wcscmp(NonLocalizable::SplashClassName, className) == 0;
|
||||
}
|
||||
|
||||
void FancyZones::OnEditorExitEvent() noexcept
|
||||
void FancyZones::OnEditorExitEvent(require_write_lock lock) noexcept
|
||||
{
|
||||
// Collect information about changes in zone layout after editor exited.
|
||||
FancyZonesDataInstance().LoadFancyZonesData();
|
||||
UpdateZoneSets();
|
||||
UpdateZoneSets(lock);
|
||||
}
|
||||
|
||||
void FancyZones::UpdateZoneSets() noexcept
|
||||
void FancyZones::UpdateZoneSets(require_write_lock lock) noexcept
|
||||
{
|
||||
for (auto workArea : m_workAreaHandler.GetAllWorkAreas())
|
||||
{
|
||||
@@ -1320,7 +1316,7 @@ void FancyZones::UpdateZoneSets() noexcept
|
||||
}
|
||||
if (m_settings->GetSettings()->zoneSetChange_moveWindows)
|
||||
{
|
||||
UpdateWindowsPositions();
|
||||
UpdateWindowsPositions(lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1329,15 +1325,7 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
|
||||
auto window = GetForegroundWindow();
|
||||
if (m_settings->GetSettings()->overrideSnapHotkeys && FancyZonesUtils::IsCandidateForZoning(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
HMONITOR monitor;
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
{
|
||||
monitor = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
}
|
||||
HMONITOR monitor = WorkAreaKeyFromWindow(window);
|
||||
|
||||
auto zoneWindow = m_workAreaHandler.GetWorkArea(m_currentDesktopId, monitor);
|
||||
if (zoneWindow && zoneWindow->ActiveZoneSet() && zoneWindow->ActiveZoneSet()->LayoutType() != FancyZonesDataTypes::ZoneSetLayoutType::Blank)
|
||||
@@ -1355,6 +1343,47 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
|
||||
return false;
|
||||
}
|
||||
|
||||
void FancyZones::ApplyQuickLayout(int key) noexcept
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
|
||||
std::wstring uuid;
|
||||
for (auto [zoneUuid, hotkey] : FancyZonesDataInstance().GetLayoutQuickKeys())
|
||||
{
|
||||
if (hotkey == key)
|
||||
{
|
||||
uuid = zoneUuid;
|
||||
}
|
||||
}
|
||||
|
||||
auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(m_currentDesktopId);
|
||||
|
||||
// Find a custom zone set with this uuid and apply it
|
||||
auto customZoneSets = FancyZonesDataInstance().GetCustomZoneSetsMap();
|
||||
|
||||
if (!customZoneSets.contains(uuid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FancyZonesDataTypes::ZoneSetData data{ .uuid = uuid, .type = FancyZonesDataTypes::ZoneSetLayoutType::Custom };
|
||||
FancyZonesDataInstance().SetActiveZoneSet(workArea->UniqueId(), data);
|
||||
FancyZonesDataInstance().SaveZoneSettings();
|
||||
UpdateZoneSets(writeLock);
|
||||
FlashZones(writeLock);
|
||||
}
|
||||
|
||||
void FancyZones::FlashZones(require_write_lock) noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->flashZonesOnQuickSwitch && !m_windowMoveHandler.IsDragEnabled())
|
||||
{
|
||||
for (auto [monitor, workArea] : m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId))
|
||||
{
|
||||
workArea->FlashZones();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<HMONITOR> FancyZones::GetMonitorsSorted() noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
@@ -1368,6 +1397,7 @@ std::vector<HMONITOR> FancyZones::GetMonitorsSorted() noexcept
|
||||
|
||||
std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
|
||||
{
|
||||
_TRACER_;
|
||||
std::shared_lock readLock(m_lock);
|
||||
|
||||
std::vector<std::pair<HMONITOR, RECT>> monitorInfo;
|
||||
@@ -1385,6 +1415,18 @@ std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
|
||||
return monitorInfo;
|
||||
}
|
||||
|
||||
HMONITOR FancyZones::WorkAreaKeyFromWindow(HWND window) noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->spanZonesAcrossMonitors)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||
}
|
||||
}
|
||||
|
||||
winrt::com_ptr<IFancyZones> MakeFancyZones(HINSTANCE hinstance,
|
||||
const winrt::com_ptr<IFancyZonesSettings>& settings,
|
||||
std::function<void()> disableCallback) noexcept
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "JsonHelpers.h"
|
||||
#include "ZoneSet.h"
|
||||
#include "Settings.h"
|
||||
#include "CallTracer.h"
|
||||
|
||||
#include <common/utils/json.h>
|
||||
#include <fancyzones/lib/util.h>
|
||||
@@ -153,6 +154,24 @@ FancyZonesData::FancyZonesData()
|
||||
editorParametersFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesEditorParametersFile);
|
||||
}
|
||||
|
||||
const JSONHelpers::TDeviceInfoMap& FancyZonesData::GetDeviceInfoMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return deviceInfoMap;
|
||||
}
|
||||
|
||||
const JSONHelpers::TCustomZoneSetsMap& FancyZonesData::GetCustomZoneSetsMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return customZoneSetsMap;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>& FancyZonesData::GetAppZoneHistoryMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return appZoneHistoryMap;
|
||||
}
|
||||
|
||||
std::optional<FancyZonesDataTypes::DeviceInfoData> FancyZonesData::FindDeviceInfo(const std::wstring& zoneWindowId) const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
@@ -169,6 +188,7 @@ std::optional<FancyZonesDataTypes::CustomZoneSetData> FancyZonesData::FindCustom
|
||||
|
||||
bool FancyZonesData::AddDevice(const std::wstring& deviceId)
|
||||
{
|
||||
_TRACER_;
|
||||
using namespace FancyZonesDataTypes;
|
||||
|
||||
std::scoped_lock lock{ dataLock };
|
||||
@@ -214,6 +234,7 @@ void FancyZonesData::CloneDeviceInfo(const std::wstring& source, const std::wstr
|
||||
|
||||
void FancyZonesData::UpdatePrimaryDesktopData(const std::wstring& desktopId)
|
||||
{
|
||||
_TRACER_;
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis,
|
||||
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
|
||||
// desktops in this session value in registry will be empty and we will use default GUID in
|
||||
@@ -377,6 +398,7 @@ std::vector<size_t> FancyZonesData::GetAppLastZoneIndexSet(HWND window, const st
|
||||
|
||||
bool FancyZonesData::RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId)
|
||||
{
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
auto processPath = get_process_path(window);
|
||||
if (!processPath.empty())
|
||||
@@ -429,6 +451,7 @@ bool FancyZonesData::RemoveAppLastZone(HWND window, const std::wstring_view& dev
|
||||
|
||||
bool FancyZonesData::SetAppLastZones(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, const std::vector<size_t>& zoneIndexSet)
|
||||
{
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
|
||||
if (IsAnotherWindowOfApplicationInstanceZoned(window, deviceId))
|
||||
@@ -488,10 +511,33 @@ bool FancyZonesData::SetAppLastZones(HWND window, const std::wstring& deviceId,
|
||||
void FancyZonesData::SetActiveZoneSet(const std::wstring& deviceId, const FancyZonesDataTypes::ZoneSetData& data)
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
auto it = deviceInfoMap.find(deviceId);
|
||||
if (it != deviceInfoMap.end())
|
||||
|
||||
auto deviceIt = deviceInfoMap.find(deviceId);
|
||||
if (deviceIt == deviceInfoMap.end())
|
||||
{
|
||||
it->second.activeZoneSet = data;
|
||||
return;
|
||||
}
|
||||
|
||||
deviceIt->second.activeZoneSet = data;
|
||||
|
||||
// If the zone set is custom, we need to copy its properties to the device
|
||||
auto zonesetIt = customZoneSetsMap.find(data.uuid);
|
||||
if (zonesetIt != customZoneSetsMap.end())
|
||||
{
|
||||
if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Grid)
|
||||
{
|
||||
auto layoutInfo = std::get<FancyZonesDataTypes::GridLayoutInfo>(zonesetIt->second.info);
|
||||
deviceIt->second.sensitivityRadius = layoutInfo.sensitivityRadius();
|
||||
deviceIt->second.showSpacing = layoutInfo.showSpacing();
|
||||
deviceIt->second.spacing = layoutInfo.spacing();
|
||||
deviceIt->second.zoneCount = layoutInfo.zoneCount();
|
||||
}
|
||||
else if (zonesetIt->second.type == FancyZonesDataTypes::CustomLayoutType::Canvas)
|
||||
{
|
||||
auto layoutInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(zonesetIt->second.info);
|
||||
deviceIt->second.sensitivityRadius = layoutInfo.sensitivityRadius;
|
||||
deviceIt->second.zoneCount = (int)layoutInfo.zones.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,6 +559,7 @@ void FancyZonesData::LoadFancyZonesData()
|
||||
appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON);
|
||||
deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
|
||||
customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON);
|
||||
quickKeysMap = JSONHelpers::ParseQuickKeys(fancyZonesDataJSON);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,14 +571,14 @@ void FancyZonesData::SaveAppZoneHistoryAndZoneSettings() const
|
||||
|
||||
void FancyZonesData::SaveZoneSettings() const
|
||||
{
|
||||
Logger::trace("FancyZonesData::SaveZoneSettings()");
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap);
|
||||
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap, quickKeysMap);
|
||||
}
|
||||
|
||||
void FancyZonesData::SaveAppZoneHistory() const
|
||||
{
|
||||
Logger::trace("FancyZonesData::SaveAppZoneHistory()");
|
||||
_TRACER_;
|
||||
std::scoped_lock lock{ dataLock };
|
||||
JSONHelpers::SaveAppZoneHistory(appZoneHistoryFileName, appZoneHistoryMap);
|
||||
}
|
||||
|
||||
@@ -42,22 +42,16 @@ public:
|
||||
|
||||
std::optional<FancyZonesDataTypes::CustomZoneSetData> FindCustomZoneSet(const std::wstring& guid) const;
|
||||
|
||||
inline const JSONHelpers::TDeviceInfoMap & GetDeviceInfoMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return deviceInfoMap;
|
||||
}
|
||||
const JSONHelpers::TDeviceInfoMap& GetDeviceInfoMap() const;
|
||||
|
||||
inline const JSONHelpers::TCustomZoneSetsMap & GetCustomZoneSetsMap() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return customZoneSetsMap;
|
||||
}
|
||||
const JSONHelpers::TCustomZoneSetsMap& GetCustomZoneSetsMap() const;
|
||||
|
||||
inline const std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>& GetAppZoneHistoryMap() const
|
||||
const std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>& GetAppZoneHistoryMap() const;
|
||||
|
||||
inline const JSONHelpers::TLayoutQuickKeysMap& GetLayoutQuickKeys() const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
return appZoneHistoryMap;
|
||||
return quickKeysMap;
|
||||
}
|
||||
|
||||
inline const std::wstring& GetZonesSettingsFileName() const
|
||||
@@ -133,6 +127,8 @@ private:
|
||||
JSONHelpers::TDeviceInfoMap deviceInfoMap{};
|
||||
// Maps custom zoneset UUID to it's data
|
||||
JSONHelpers::TCustomZoneSetsMap customZoneSetsMap{};
|
||||
// Maps zoneset UUID with quick access keys
|
||||
JSONHelpers::TLayoutQuickKeysMap quickKeysMap{};
|
||||
|
||||
std::wstring zonesSettingsFileName;
|
||||
std::wstring appZoneHistoryFileName;
|
||||
|
||||
@@ -112,4 +112,18 @@ namespace FancyZonesDataTypes
|
||||
cellRow.resize(m_columns, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int GridLayoutInfo::zoneCount() const
|
||||
{
|
||||
int high = 0;
|
||||
for (const auto& row : m_cellChildMap)
|
||||
{
|
||||
for (int val : row)
|
||||
{
|
||||
high = max(high, val);
|
||||
}
|
||||
}
|
||||
|
||||
return high + 1;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user