diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index dedbb36b59..2b76fc1f52 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -341,6 +341,7 @@ devblogs devdocs devenum devmgmt +DEVMODE DEVMODEW DEVMON devpkey @@ -607,6 +608,7 @@ hmenu hmodule hmonitor homljgmgpmcbpjbnjpfijnhipfkiclkd +HORZSIZE Hostbackdropbrush hotkeycontrol hotkeys @@ -1129,6 +1131,7 @@ pcelt pch pchast PCIDLIST +PCTSTR PCWSTR pdbs pdisp @@ -1272,6 +1275,7 @@ RAlt Rasterize RAWINPUTDEVICE RAWINPUTHEADER +RAWMODE RAWPATH rbhid rclsid @@ -1723,6 +1727,7 @@ VERBW VERIFYCONTEXT verrsrc VERSIONINFO +VERTSIZE VFT vget vgetq diff --git a/doc/images/overview/MeasureTool_large.png b/doc/images/overview/MeasureTool_large.png index 5484756fb0..d7e6b5b0f1 100644 Binary files a/doc/images/overview/MeasureTool_large.png and b/doc/images/overview/MeasureTool_large.png differ diff --git a/doc/images/overview/MeasureTool_small.png b/doc/images/overview/MeasureTool_small.png index 070d159c36..10b6fe6992 100644 Binary files a/doc/images/overview/MeasureTool_small.png and b/doc/images/overview/MeasureTool_small.png differ diff --git a/src/common/Display/monitors.cpp b/src/common/Display/monitors.cpp index c203d15712..2c9a22e425 100644 --- a/src/common/Display/monitors.cpp +++ b/src/common/Display/monitors.cpp @@ -52,3 +52,55 @@ MonitorInfo MonitorInfo::GetPrimaryMonitor() } return monitors[0]; } + +MonitorInfo MonitorInfo::GetFromWindow(const HWND window) +{ + auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + return MonitorInfo::MonitorInfo(monitor); +} + +MonitorInfo MonitorInfo::GetFromPoint(int32_t x, int32_t y) +{ + auto monitor = MonitorFromPoint(POINT{ x, y }, MONITOR_DEFAULTTONULL); + return MonitorInfo::MonitorInfo(monitor); +} + +MonitorInfo::Size MonitorInfo::GetSize(const MONITORINFOEX& monitorInfoEx) +{ + Size size = {}; + + auto device_name = PCTSTR(monitorInfoEx.szDevice); + + auto hdc = CreateDC(device_name, nullptr, nullptr, nullptr); + size.width_mm = static_cast(GetDeviceCaps(hdc, HORZSIZE)); + size.height_mm = static_cast(GetDeviceCaps(hdc, VERTSIZE)); + if (hdc != nullptr) + { + ReleaseDC(nullptr, hdc); + } + + auto monitor = &monitorInfoEx.rcMonitor; + size.width_logical = static_cast(monitor->right - monitor->left); + size.height_logical = static_cast(monitor->bottom - monitor->top); + + DEVMODE dev_mode = { .dmSize = sizeof DEVMODE }; + if (EnumDisplaySettingsEx(device_name, ENUM_CURRENT_SETTINGS, &dev_mode, EDS_RAWMODE)) + { + size.width_physical = dev_mode.dmPelsWidth; + size.height_physical = dev_mode.dmPelsHeight; + } + + return size; +} + +MonitorInfo::Size MonitorInfo::GetSize() const +{ + if (this->handle) + { + return MonitorInfo::GetSize(this->info); + } + else + { + return MonitorInfo::Size{}; + } +} diff --git a/src/common/Display/monitors.h b/src/common/Display/monitors.h index 021f2b9efb..614a2258dd 100644 --- a/src/common/Display/monitors.h +++ b/src/common/Display/monitors.h @@ -1,4 +1,5 @@ #pragma once +#pragma comment(lib, "Gdi32.lib") #include #include @@ -42,6 +43,15 @@ struct Box class MonitorInfo { +public: + typedef struct Size + { + uint32_t width_logical, height_logical; + uint32_t width_physical, height_physical; + float width_mm, height_mm; + } Size; + +private: HMONITOR handle; MONITORINFOEX info = {}; @@ -53,8 +63,14 @@ public: } Box GetScreenSize(const bool includeNonWorkingArea) const; bool IsPrimary() const; + Size GetSize() const; // Returns monitor rects ordered from left to right static std::vector GetMonitors(bool includeNonWorkingArea); static MonitorInfo GetPrimaryMonitor(); + static MonitorInfo GetFromWindow(HWND); + static MonitorInfo GetFromPoint(int32_t, int32_t); + +private: + static Size GetSize(const MONITORINFOEX&); }; diff --git a/src/modules/MeasureTool/MeasureToolCore/BoundsToolOverlayUI.cpp b/src/modules/MeasureTool/MeasureToolCore/BoundsToolOverlayUI.cpp index 0542448939..bbc59eb7f0 100644 --- a/src/modules/MeasureTool/MeasureToolCore/BoundsToolOverlayUI.cpp +++ b/src/modules/MeasureTool/MeasureToolCore/BoundsToolOverlayUI.cpp @@ -9,7 +9,7 @@ namespace { - Measurement GetMeasurement(const CursorDrag& currentBounds, POINT cursorPos) + Measurement GetMeasurement(const CursorDrag& currentBounds, POINT cursorPos, float px2mmRatio) { D2D1_RECT_F rect; std::tie(rect.left, rect.right) = @@ -17,7 +17,7 @@ namespace std::tie(rect.top, rect.bottom) = std::minmax(static_cast(cursorPos.y), currentBounds.startPos.y); - return Measurement(rect); + return Measurement(rect, px2mmRatio); } void CopyToClipboard(HWND window, const BoundsToolState& toolState, POINT cursorPos) @@ -29,7 +29,8 @@ namespace if (handle == window && perScreen.currentBounds) { - allMeasurements.push_back(GetMeasurement(*perScreen.currentBounds, cursorPos)); + auto px2mmRatio = toolState.commonState->GetPhysicalPx2MmRatio(window); + allMeasurements.push_back(GetMeasurement(*perScreen.currentBounds, cursorPos, px2mmRatio)); } } @@ -85,7 +86,8 @@ namespace if (const bool shiftPress = GetKeyState(VK_SHIFT) & 0x80000; shiftPress && perScreen.currentBounds) { - perScreen.measurements.push_back(GetMeasurement(*perScreen.currentBounds, cursorPos)); + auto px2mmRatio = toolState->commonState->GetPhysicalPx2MmRatio(window); + perScreen.measurements.push_back(GetMeasurement(*perScreen.currentBounds, cursorPos, px2mmRatio)); } perScreen.currentBounds = std::nullopt; @@ -274,7 +276,7 @@ namespace text.buffer.size(), true, true, - commonState.units); + commonState.units | Measurement::Unit::Pixel); // Always show pixels. D2D_POINT_2F textBoxPos; if (textBoxCenter) @@ -314,6 +316,7 @@ void DrawBoundsToolTick(const CommonState& commonState, D2D1_RECT_F rect; std::tie(rect.left, rect.right) = std::minmax(perScreen.currentBounds->startPos.x, perScreen.currentBounds->currentPos.x); std::tie(rect.top, rect.bottom) = std::minmax(perScreen.currentBounds->startPos.y, perScreen.currentBounds->currentPos.y); - DrawMeasurement(Measurement{ rect }, commonState, window, d2dState, perScreen.currentBounds->currentPos); + auto px2mmRatio = toolState.commonState->GetPhysicalPx2MmRatio(window); + DrawMeasurement(Measurement{ rect, px2mmRatio }, commonState, window, d2dState, perScreen.currentBounds->currentPos); } } diff --git a/src/modules/MeasureTool/MeasureToolCore/D2DState.cpp b/src/modules/MeasureTool/MeasureToolCore/D2DState.cpp index 0d26dcb0ce..8ebc6b65fe 100644 --- a/src/modules/MeasureTool/MeasureToolCore/D2DState.cpp +++ b/src/modules/MeasureTool/MeasureToolCore/D2DState.cpp @@ -65,7 +65,7 @@ D2DState::D2DState(const DxgiAPI* dxgi, void D2DState::DrawTextBox(const wchar_t* text, const size_t textLen, - const std::optional halfOpaqueSymbolPos, + const size_t halfOpaqueSymbolPos[2], const D2D_POINT_2F center, const bool screenQuadrantAware, const HWND window) const @@ -80,8 +80,7 @@ void D2DState::DrawTextBox(const wchar_t* text, &textLayout)); DWRITE_TEXT_METRICS textMetrics = {}; winrt::check_hresult(textLayout->GetMetrics(&textMetrics)); - // Assumes text doesn't contain new lines - const float lineHeight = textMetrics.height; + const float lineHeight = textMetrics.height / (textMetrics.lineCount ? textMetrics.lineCount : 1); textMetrics.width += lineHeight; textMetrics.height += lineHeight * .5f; winrt::check_hresult(textLayout->SetMaxWidth(textMetrics.width)); @@ -147,12 +146,17 @@ void D2DState::DrawTextBox(const wchar_t* text, // Draw text & its box dxgiWindowState.rt->FillRoundedRectangle(textBoxRect, solidBrushes[Brush::background].get()); - if (halfOpaqueSymbolPos.has_value()) + if (halfOpaqueSymbolPos[0] > 0) { DWRITE_TEXT_RANGE textRange = { static_cast(*halfOpaqueSymbolPos), 2 }; auto opacityEffect = winrt::make_self(); opacityEffect->alpha = consts::CROSS_OPACITY; winrt::check_hresult(textLayout->SetDrawingEffect(opacityEffect.get(), textRange)); + if (halfOpaqueSymbolPos[1] > halfOpaqueSymbolPos[0]) + { + textRange = { static_cast(halfOpaqueSymbolPos[1]), 2 }; + winrt::check_hresult(textLayout->SetDrawingEffect(opacityEffect.get(), textRange)); + } } winrt::check_hresult(textLayout->Draw(nullptr, textRenderer.get(), textRect.left, textRect.top)); } diff --git a/src/modules/MeasureTool/MeasureToolCore/D2DState.h b/src/modules/MeasureTool/MeasureToolCore/D2DState.h index 3d56c37351..cfd8f629f7 100644 --- a/src/modules/MeasureTool/MeasureToolCore/D2DState.h +++ b/src/modules/MeasureTool/MeasureToolCore/D2DState.h @@ -35,7 +35,7 @@ struct D2DState std::vector solidBrushesColors); void DrawTextBox(const wchar_t* text, const size_t textLen, - const std::optional halfOpaqueSymbolPos, + const size_t halfOpaqueSymbolPos[2], const D2D_POINT_2F center, const bool screenQuadrantAware, const HWND window) const; diff --git a/src/modules/MeasureTool/MeasureToolCore/MeasureToolOverlayUI.cpp b/src/modules/MeasureTool/MeasureToolCore/MeasureToolOverlayUI.cpp index 4b948d3446..b25bc46adf 100644 --- a/src/modules/MeasureTool/MeasureToolCore/MeasureToolOverlayUI.cpp +++ b/src/modules/MeasureTool/MeasureToolCore/MeasureToolOverlayUI.cpp @@ -19,17 +19,17 @@ namespace { switch (mode) { - case MeasureToolState::Mode::Cross: - return { true, true }; + case MeasureToolState::Mode::Cross: + return { true, true }; - case MeasureToolState::Mode::Vertical: - return { false, true }; + case MeasureToolState::Mode::Vertical: + return { false, true }; - case MeasureToolState::Mode::Horizontal: - return { true, false }; + case MeasureToolState::Mode::Horizontal: + return { true, false }; - default: - throw std::runtime_error("Unknown MeasureToolState Mode"); + default: + throw std::runtime_error("Unknown MeasureToolState Mode"); } } @@ -77,7 +77,7 @@ namespace CopyToClipboard(window, *toolState); auto& perScreen = toolState->perScreen[window]; - + const bool shiftPress = GetKeyState(VK_SHIFT) & 0x8000; if (shiftPress && perScreen.measuredEdges) { @@ -144,10 +144,10 @@ namespace const auto [crossSymbolPos, measureStringBufLen] = measurement.Print(text.buffer.data(), - text.buffer.size(), - drawHorizontalCrossLine, - drawVerticalCrossLine, - commonState.units); + text.buffer.size(), + drawHorizontalCrossLine, + drawVerticalCrossLine, + commonState.units | Measurement::Unit::Pixel); // Always show pixels. d2dState.DrawTextBox(text.buffer.data(), measureStringBufLen, diff --git a/src/modules/MeasureTool/MeasureToolCore/Measurement.cpp b/src/modules/MeasureTool/MeasureToolCore/Measurement.cpp index a6a6584f70..5ddb2cbf39 100644 --- a/src/modules/MeasureTool/MeasureToolCore/Measurement.cpp +++ b/src/modules/MeasureTool/MeasureToolCore/Measurement.cpp @@ -4,7 +4,8 @@ #include -Measurement::Measurement(RECT winRect) +Measurement::Measurement(RECT winRect, float px2mmRatio) : + px2mmRatio{ px2mmRatio } { rect.left = static_cast(winRect.left); rect.right = static_cast(winRect.right); @@ -12,81 +13,192 @@ Measurement::Measurement(RECT winRect) rect.bottom = static_cast(winRect.bottom); } -Measurement::Measurement(D2D1_RECT_F d2dRect) : - rect{ d2dRect } +Measurement::Measurement(D2D1_RECT_F d2dRect, float px2mmRatio) : + rect{ d2dRect }, px2mmRatio{ px2mmRatio } { } namespace { - inline float Convert(const float pixels, const Measurement::Unit units) + inline float Convert(const float pixels, const Measurement::Unit units, float px2mmRatio) { - switch (units) + if (px2mmRatio > 0) { - case Measurement::Unit::Pixel: - return pixels; - case Measurement::Unit::Inch: - return pixels / 96.f; - case Measurement::Unit::Centimetre: - return pixels / 96.f * 2.54f; - default: - return pixels; + switch (units) + { + case Measurement::Unit::Pixel: + return pixels; + case Measurement::Unit::Inch: + return pixels * px2mmRatio / 10.0f / 2.54f; + case Measurement::Unit::Centimetre: + return pixels * px2mmRatio / 10.0f; + case Measurement::Unit::Millimetre: + return pixels * px2mmRatio; + default: + return pixels; + } + } + else + { + switch (units) + { + case Measurement::Unit::Pixel: + return pixels; + case Measurement::Unit::Inch: + return pixels / 96.0f; + case Measurement::Unit::Centimetre: + return pixels / 96.0f * 2.54f; + case Measurement::Unit::Millimetre: + return pixels / 96.0f / 10.0f * 2.54f; + default: + return pixels; + } } } } +winrt::hstring Measurement::abbreviations[4]{}; + inline float Measurement::Width(const Unit units) const { - return Convert(rect.right - rect.left + 1.f, units); + return Convert(rect.right - rect.left + 1.f, units, px2mmRatio); } inline float Measurement::Height(const Unit units) const { - return Convert(rect.bottom - rect.top + 1.f, units); + return Convert(rect.bottom - rect.top + 1.f, units, px2mmRatio); +} + +Measurement::Unit Measurement::GetUnitFromIndex(int index) +{ + switch (index) + { + case 0: + return Measurement::Unit::Pixel; + case 1: + return Measurement::Unit::Inch; + case 2: + return Measurement::Unit::Centimetre; + case 3: + return Measurement::Unit::Millimetre; + default: + return Measurement::Unit::Pixel; + } +} + +void Measurement::InitResources() +{ + auto rm = winrt::ResourceManager{}; + auto mm = rm.MainResourceMap(); + abbreviations[0] = mm.GetValue(L"Resources/MeasurementUnitAbbrPixel").ValueAsString(); + abbreviations[1] = mm.GetValue(L"Resources/MeasurementUnitAbbrInch").ValueAsString(); + abbreviations[2] = mm.GetValue(L"Resources/MeasurementUnitAbbrCentimetre").ValueAsString(); + abbreviations[3] = mm.GetValue(L"Resources/MeasurementUnitAbbrMillimetre").ValueAsString(); +} + +const wchar_t* Measurement::GetUnitAbbreviation(Measurement::Unit units) +{ + switch (units) + { + case Unit::Pixel: + return abbreviations[0].c_str(); + case Unit::Inch: + return abbreviations[1].c_str(); + case Unit::Centimetre: + return abbreviations[2].c_str(); + case Unit::Millimetre: + return abbreviations[3].c_str(); + default: + return L"??"; + } } Measurement::PrintResult Measurement::Print(wchar_t* buf, const size_t bufSize, const bool printWidth, const bool printHeight, - const Unit units) const + const int units) const { PrintResult result; - if (printWidth) - { - result.strLen += swprintf_s(buf, - bufSize, - L"%g", - Width(units)); - if (printHeight) + + auto print = [=, &result](Measurement::Unit unit, const bool paren) { + if (paren) + { + result.strLen += swprintf_s(buf + result.strLen, bufSize - result.strLen, printWidth && printHeight ? L"\n(" : L" ("); + } + if (printWidth) { - result.crossSymbolPos = result.strLen + 1; result.strLen += swprintf_s(buf + result.strLen, bufSize - result.strLen, - L" \x00D7 "); + L"%.4g", + Width(unit)); + if (printHeight) + { + result.crossSymbolPos[paren] = result.strLen + 1; + result.strLen += swprintf_s(buf + result.strLen, + bufSize - result.strLen, + L" \x00D7 "); + } } - } + if (printHeight) + { + result.strLen += swprintf_s(buf + result.strLen, + bufSize - result.strLen, + L"%.4g", + Height(unit)); + } + switch (unit) + { + case Measurement::Unit::Pixel: + result.strLen += swprintf_s(buf + result.strLen, + bufSize - result.strLen, + L" %s", + Measurement::GetUnitAbbreviation(unit)); + break; + case Measurement::Unit::Inch: + result.strLen += swprintf_s(buf + result.strLen, + bufSize - result.strLen, + L" %s", + Measurement::GetUnitAbbreviation(unit)); + break; + case Measurement::Unit::Centimetre: + result.strLen += swprintf_s(buf + result.strLen, + bufSize - result.strLen, + L" %s", + Measurement::GetUnitAbbreviation(unit)); - if (printHeight) - { - result.strLen += swprintf_s(buf + result.strLen, - bufSize - result.strLen, - L"%g", - Height(units)); - } + break; + case Measurement::Unit::Millimetre: + result.strLen += swprintf_s(buf + result.strLen, + bufSize - result.strLen, + L" %s", + Measurement::GetUnitAbbreviation(unit)); - switch (units) + break; + } + if (paren) + { + result.strLen += swprintf_s(buf + result.strLen, bufSize - result.strLen, L")"); + } + }; + + int count = 0; + const Measurement::Unit allUnits[] = { + Measurement::Unit::Pixel, + Measurement::Unit::Millimetre, + Measurement::Unit::Inch, + Measurement::Unit::Centimetre, + }; + // We only use two units at most, it would be to long otherwise. + for each (Measurement::Unit unit in allUnits) { - case Measurement::Unit::Inch: - result.strLen += swprintf_s(buf + result.strLen, - bufSize - result.strLen, - L" in"); - break; - case Measurement::Unit::Centimetre: - result.strLen += swprintf_s(buf + result.strLen, - bufSize - result.strLen, - L" cm"); - break; + if ((unit & units) == unit) + { + count += 1; + if (count > 2) + break; + print(unit, count != 1); + } } return result; @@ -117,15 +229,9 @@ void Measurement::PrintToStream(std::wostream& stream, stream << Height(units); } - switch (units) + // If the unit is pixels, then the abbreviation will not be saved as it used to be. + if (units != Measurement::Unit::Pixel) { - case Measurement::Unit::Inch: - stream << L" in"; - - break; - case Measurement::Unit::Centimetre: - stream << L" cm"; - break; + stream << L" " << Measurement::GetUnitAbbreviation(units); } } - diff --git a/src/modules/MeasureTool/MeasureToolCore/Measurement.h b/src/modules/MeasureTool/MeasureToolCore/Measurement.h index c40788dad3..057800f896 100644 --- a/src/modules/MeasureTool/MeasureToolCore/Measurement.h +++ b/src/modules/MeasureTool/MeasureToolCore/Measurement.h @@ -1,4 +1,5 @@ #pragma once +#include "pch.h" #include #include @@ -8,38 +9,45 @@ struct Measurement { enum Unit { - Pixel, - Inch, - Centimetre + Pixel = 1, + Inch = 2, + Centimetre = 4, + Millimetre = 8, }; D2D1_RECT_F rect = {}; // corners are inclusive - Measurement() = default; + float px2mmRatio = 0; + static winrt::hstring abbreviations[4]; // Abbreviations of units. + Measurement(const Measurement&) = default; Measurement& operator=(const Measurement&) = default; - explicit Measurement(D2D1_RECT_F d2dRect); - explicit Measurement(RECT winRect); + explicit Measurement(D2D1_RECT_F d2dRect, float px2mmRatio); + explicit Measurement(RECT winRect, float px2mmRatio); float Width(const Unit units) const; float Height(const Unit units) const; struct PrintResult { - std::optional crossSymbolPos; + size_t crossSymbolPos[2] = {}; size_t strLen = {}; }; + static void InitResources(); + static Unit GetUnitFromIndex(int index); + static const wchar_t* GetUnitAbbreviation(const Unit units); + PrintResult Print(wchar_t* buf, const size_t bufSize, const bool printWidth, const bool printHeight, - const Unit units) const; + const int units) const; void PrintToStream(std::wostream& stream, - const bool prependNewLine, - const bool printWidth, - const bool printHeight, - const Unit units) const; + const bool prependNewLine, + const bool printWidth, + const bool printHeight, + const Unit units) const; }; diff --git a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.cpp b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.cpp index 214d8c0818..8a16664165 100644 --- a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.cpp +++ b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.cpp @@ -62,6 +62,11 @@ namespace winrt::PowerToys::MeasureToolCore::implementation _mouseCaptureThread.join(); } + void Core::InitResources() + { + Measurement::InitResources(); + } + void Core::ResetState() { _commonState.closeOnOtherMonitors = true; diff --git a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.h b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.h index da0b3afb17..1d5f432412 100644 --- a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.h +++ b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.h @@ -32,6 +32,7 @@ namespace winrt::PowerToys::MeasureToolCore::implementation ~Core(); void Close(); + void InitResources(); void StartBoundsTool(); void StartMeasureTool(const bool horizontal, const bool vertical); void SetToolCompletionEvent(ToolSessionCompleted sessionCompletedTrigger); @@ -45,7 +46,7 @@ namespace winrt::PowerToys::MeasureToolCore::implementation wil::shared_event _stopMouseCaptureThreadSignal; std::thread _mouseCaptureThread; std::vector _screenCaptureThreads; - + std::vector> _overlayUIStates; Serialized _measureToolState; BoundsToolState _boundsToolState; diff --git a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.idl b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.idl index 8704c0b6cd..6295c6413f 100644 --- a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.idl +++ b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.idl @@ -19,6 +19,7 @@ namespace PowerToys void StartBoundsTool(); void ResetState(); + void InitResources(); void SetToolbarBoundingBox(Int32 fromX, Int32 fromY, Int32 toX, Int32 toY); Single GetDPIScaleForWindow(Int64 windowHandle); } diff --git a/src/modules/MeasureTool/MeasureToolCore/ScreenCapturing.cpp b/src/modules/MeasureTool/MeasureToolCore/ScreenCapturing.cpp index 09194e21d9..fee7ab809a 100644 --- a/src/modules/MeasureTool/MeasureToolCore/ScreenCapturing.cpp +++ b/src/modules/MeasureTool/MeasureToolCore/ScreenCapturing.cpp @@ -294,11 +294,12 @@ void UpdateCaptureState(const CommonState& commonState, cursorPos, perColorChannelEdgeDetection, pixelTolerance); + auto px2mmRatio = commonState.GetPhysicalPx2MmRatio(window); #if defined(DEBUG_EDGES) char buffer[256]; sprintf_s(buffer, - "Cursor: [%ld,%ld] Bounds: [%ld,%ld]-[%ld,%ld] Screen size: [%zu, %zu]\n", + "Cursor: [%ld,%ld] Bounds: [%ld,%ld]-[%ld,%ld] Screen size: [%zu, %zu] Ratio: %g\n", cursorPos.x, cursorPos.y, bounds.left, @@ -306,11 +307,12 @@ void UpdateCaptureState(const CommonState& commonState, bounds.right, bounds.bottom, textureView.view.width, - textureView.view.height); + textureView.view.height, + px2mmRatio); OutputDebugStringA(buffer); #endif state.Access([&](MeasureToolState& state) { - state.perScreen[window].measuredEdges = Measurement{ bounds }; + state.perScreen[window].measuredEdges = Measurement{ bounds, px2mmRatio }; }); } diff --git a/src/modules/MeasureTool/MeasureToolCore/Settings.cpp b/src/modules/MeasureTool/MeasureToolCore/Settings.cpp index 418b6d1a95..b5e11ef1d1 100644 --- a/src/modules/MeasureTool/MeasureToolCore/Settings.cpp +++ b/src/modules/MeasureTool/MeasureToolCore/Settings.cpp @@ -69,7 +69,8 @@ Settings Settings::LoadFromFile() try { - result.units = static_cast(props.GetNamedObject(JSON_KEY_UNITS_OF_MEASURE).GetNamedNumber(JSON_KEY_VALUE)); + auto index = static_cast(props.GetNamedObject(JSON_KEY_UNITS_OF_MEASURE).GetNamedNumber(JSON_KEY_VALUE)); + result.units = Measurement::GetUnitFromIndex(index); } catch (...) { diff --git a/src/modules/MeasureTool/MeasureToolCore/ToolState.h b/src/modules/MeasureTool/MeasureToolCore/ToolState.h index f769436d43..57d5d04ca1 100644 --- a/src/modules/MeasureTool/MeasureToolCore/ToolState.h +++ b/src/modules/MeasureTool/MeasureToolCore/ToolState.h @@ -33,6 +33,17 @@ struct CommonState POINT cursorPosSystemSpace = {}; // updated atomically std::atomic_bool closeOnOtherMonitors = false; + + float GetPhysicalPx2MmRatio(HWND window) const + { + auto ratio = -1.0f; + auto size = MonitorInfo::GetFromWindow(window).GetSize(); + if (size.width_physical > 0u) + { + ratio = size.width_mm / static_cast(size.width_physical); + } + return ratio; + } }; struct CursorDrag diff --git a/src/modules/MeasureTool/MeasureToolCore/pch.h b/src/modules/MeasureTool/MeasureToolCore/pch.h index 16cc5a1a62..95b368b96b 100644 --- a/src/modules/MeasureTool/MeasureToolCore/pch.h +++ b/src/modules/MeasureTool/MeasureToolCore/pch.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ namespace winrt using namespace Microsoft::UI::Xaml; using namespace Microsoft::UI::Xaml::Controls; using namespace Microsoft::UI::Xaml::Navigation; + using namespace Microsoft::Windows::ApplicationModel::Resources; } template diff --git a/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml b/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml index 9c99618a34..8e58d66499 100644 --- a/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml +++ b/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml @@ -4,7 +4,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:p="using:PowerToys.MeasureToolUI.Properties" xmlns:winuiex="using:WinUIEx" IsAlwaysOnTop="True" IsMaximizable="False" diff --git a/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml.cs b/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml.cs index ef35077a95..4f807655da 100644 --- a/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml.cs +++ b/src/modules/MeasureTool/MeasureToolUI/MeasureToolXAML/MainWindow.xaml.cs @@ -64,6 +64,7 @@ namespace MeasureToolUI _ = SetWindowLong(hwnd, GWL_STYLE, windowStyle); _coreLogic = core; + _coreLogic.InitResources(); Closed += MainWindow_Closed; DisplayArea displayArea = DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest); float dpiScale = _coreLogic.GetDPIScaleForWindow((int)hwnd); diff --git a/src/modules/MeasureTool/MeasureToolUI/Strings/en-us/Resources.resw b/src/modules/MeasureTool/MeasureToolUI/Strings/en-us/Resources.resw index b33f9d43f0..a6fe87f370 100644 --- a/src/modules/MeasureTool/MeasureToolUI/Strings/en-us/Resources.resw +++ b/src/modules/MeasureTool/MeasureToolUI/Strings/en-us/Resources.resw @@ -66,4 +66,16 @@ Close (Esc) + + px + + + in + + + cm + + + mm + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI.Library/MeasureToolProperties.cs b/src/settings-ui/Settings.UI.Library/MeasureToolProperties.cs index ebda5953d0..5edc9f9175 100644 --- a/src/settings-ui/Settings.UI.Library/MeasureToolProperties.cs +++ b/src/settings-ui/Settings.UI.Library/MeasureToolProperties.cs @@ -38,7 +38,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library [JsonConverter(typeof(BoolPropertyJsonConverter))] public bool PerColorChannelEdgeDetection { get; set; } - [CmdConfigureIgnore] public IntProperty UnitsOfMeasure { get; set; } public IntProperty PixelTolerance { get; set; } diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Modules/OOBE/ScreenRuler.gif b/src/settings-ui/Settings.UI/Assets/Settings/Modules/OOBE/ScreenRuler.gif index b88b00d101..277775ff45 100644 Binary files a/src/settings-ui/Settings.UI/Assets/Settings/Modules/OOBE/ScreenRuler.gif and b/src/settings-ui/Settings.UI/Assets/Settings/Modules/OOBE/ScreenRuler.gif differ diff --git a/src/settings-ui/Settings.UI/Assets/Settings/Modules/ScreenRuler.png b/src/settings-ui/Settings.UI/Assets/Settings/Modules/ScreenRuler.png index 8e6a5f3471..d7e6b5b0f1 100644 Binary files a/src/settings-ui/Settings.UI/Assets/Settings/Modules/ScreenRuler.png and b/src/settings-ui/Settings.UI/Assets/Settings/Modules/ScreenRuler.png differ diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/MeasureToolPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/MeasureToolPage.xaml index cc67246a2d..a757cce983 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/MeasureToolPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/MeasureToolPage.xaml @@ -64,13 +64,14 @@ Value="{x:Bind ViewModel.PixelTolerance, Mode=TwoWay}" /> - + diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 57f6468b0a..2b885d7719 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -177,10 +177,10 @@ Vertical spacing - Units of measurement + Extra units of measurement - Pixels + Show only pixels Inches @@ -188,6 +188,9 @@ Centimeters + + Millimeters + Pixel tolerance for edge detection