[ScreenRuler]Add setting to show the measurement in an extra unit (#35887)

* display ruler: supporting millimeter and other units

* Measurement Tool: UI Setting for an extra unit

* Update images

* spelling

* spelling

* suit code style

* Fix for code review

* remove weird file

* rename field
This commit is contained in:
Wenjian Chern
2024-12-06 06:02:17 +08:00
committed by GitHub
parent 076461e460
commit 09ce610dbb
26 changed files with 333 additions and 101 deletions

View File

@@ -341,6 +341,7 @@ devblogs
devdocs devdocs
devenum devenum
devmgmt devmgmt
DEVMODE
DEVMODEW DEVMODEW
DEVMON DEVMON
devpkey devpkey
@@ -607,6 +608,7 @@ hmenu
hmodule hmodule
hmonitor hmonitor
homljgmgpmcbpjbnjpfijnhipfkiclkd homljgmgpmcbpjbnjpfijnhipfkiclkd
HORZSIZE
Hostbackdropbrush Hostbackdropbrush
hotkeycontrol hotkeycontrol
hotkeys hotkeys
@@ -1129,6 +1131,7 @@ pcelt
pch pch
pchast pchast
PCIDLIST PCIDLIST
PCTSTR
PCWSTR PCWSTR
pdbs pdbs
pdisp pdisp
@@ -1272,6 +1275,7 @@ RAlt
Rasterize Rasterize
RAWINPUTDEVICE RAWINPUTDEVICE
RAWINPUTHEADER RAWINPUTHEADER
RAWMODE
RAWPATH RAWPATH
rbhid rbhid
rclsid rclsid
@@ -1723,6 +1727,7 @@ VERBW
VERIFYCONTEXT VERIFYCONTEXT
verrsrc verrsrc
VERSIONINFO VERSIONINFO
VERTSIZE
VFT VFT
vget vget
vgetq vgetq

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -52,3 +52,55 @@ MonitorInfo MonitorInfo::GetPrimaryMonitor()
} }
return monitors[0]; 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<float>(GetDeviceCaps(hdc, HORZSIZE));
size.height_mm = static_cast<float>(GetDeviceCaps(hdc, VERTSIZE));
if (hdc != nullptr)
{
ReleaseDC(nullptr, hdc);
}
auto monitor = &monitorInfoEx.rcMonitor;
size.width_logical = static_cast<uint32_t>(monitor->right - monitor->left);
size.height_logical = static_cast<uint32_t>(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{};
}
}

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#pragma comment(lib, "Gdi32.lib")
#include <Windows.h> #include <Windows.h>
#include <compare> #include <compare>
@@ -42,6 +43,15 @@ struct Box
class MonitorInfo 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; HMONITOR handle;
MONITORINFOEX info = {}; MONITORINFOEX info = {};
@@ -53,8 +63,14 @@ public:
} }
Box GetScreenSize(const bool includeNonWorkingArea) const; Box GetScreenSize(const bool includeNonWorkingArea) const;
bool IsPrimary() const; bool IsPrimary() const;
Size GetSize() const;
// Returns monitor rects ordered from left to right // Returns monitor rects ordered from left to right
static std::vector<MonitorInfo> GetMonitors(bool includeNonWorkingArea); static std::vector<MonitorInfo> GetMonitors(bool includeNonWorkingArea);
static MonitorInfo GetPrimaryMonitor(); static MonitorInfo GetPrimaryMonitor();
static MonitorInfo GetFromWindow(HWND);
static MonitorInfo GetFromPoint(int32_t, int32_t);
private:
static Size GetSize(const MONITORINFOEX&);
}; };

View File

@@ -9,7 +9,7 @@
namespace namespace
{ {
Measurement GetMeasurement(const CursorDrag& currentBounds, POINT cursorPos) Measurement GetMeasurement(const CursorDrag& currentBounds, POINT cursorPos, float px2mmRatio)
{ {
D2D1_RECT_F rect; D2D1_RECT_F rect;
std::tie(rect.left, rect.right) = std::tie(rect.left, rect.right) =
@@ -17,7 +17,7 @@ namespace
std::tie(rect.top, rect.bottom) = std::tie(rect.top, rect.bottom) =
std::minmax(static_cast<float>(cursorPos.y), currentBounds.startPos.y); std::minmax(static_cast<float>(cursorPos.y), currentBounds.startPos.y);
return Measurement(rect); return Measurement(rect, px2mmRatio);
} }
void CopyToClipboard(HWND window, const BoundsToolState& toolState, POINT cursorPos) void CopyToClipboard(HWND window, const BoundsToolState& toolState, POINT cursorPos)
@@ -29,7 +29,8 @@ namespace
if (handle == window && perScreen.currentBounds) 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) 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; perScreen.currentBounds = std::nullopt;
@@ -274,7 +276,7 @@ namespace
text.buffer.size(), text.buffer.size(),
true, true,
true, true,
commonState.units); commonState.units | Measurement::Unit::Pixel); // Always show pixels.
D2D_POINT_2F textBoxPos; D2D_POINT_2F textBoxPos;
if (textBoxCenter) if (textBoxCenter)
@@ -314,6 +316,7 @@ void DrawBoundsToolTick(const CommonState& commonState,
D2D1_RECT_F rect; D2D1_RECT_F rect;
std::tie(rect.left, rect.right) = std::minmax(perScreen.currentBounds->startPos.x, perScreen.currentBounds->currentPos.x); 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); 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);
} }
} }

View File

@@ -65,7 +65,7 @@ D2DState::D2DState(const DxgiAPI* dxgi,
void D2DState::DrawTextBox(const wchar_t* text, void D2DState::DrawTextBox(const wchar_t* text,
const size_t textLen, const size_t textLen,
const std::optional<size_t> halfOpaqueSymbolPos, const size_t halfOpaqueSymbolPos[2],
const D2D_POINT_2F center, const D2D_POINT_2F center,
const bool screenQuadrantAware, const bool screenQuadrantAware,
const HWND window) const const HWND window) const
@@ -80,8 +80,7 @@ void D2DState::DrawTextBox(const wchar_t* text,
&textLayout)); &textLayout));
DWRITE_TEXT_METRICS textMetrics = {}; DWRITE_TEXT_METRICS textMetrics = {};
winrt::check_hresult(textLayout->GetMetrics(&textMetrics)); winrt::check_hresult(textLayout->GetMetrics(&textMetrics));
// Assumes text doesn't contain new lines const float lineHeight = textMetrics.height / (textMetrics.lineCount ? textMetrics.lineCount : 1);
const float lineHeight = textMetrics.height;
textMetrics.width += lineHeight; textMetrics.width += lineHeight;
textMetrics.height += lineHeight * .5f; textMetrics.height += lineHeight * .5f;
winrt::check_hresult(textLayout->SetMaxWidth(textMetrics.width)); winrt::check_hresult(textLayout->SetMaxWidth(textMetrics.width));
@@ -147,12 +146,17 @@ void D2DState::DrawTextBox(const wchar_t* text,
// Draw text & its box // Draw text & its box
dxgiWindowState.rt->FillRoundedRectangle(textBoxRect, solidBrushes[Brush::background].get()); dxgiWindowState.rt->FillRoundedRectangle(textBoxRect, solidBrushes[Brush::background].get());
if (halfOpaqueSymbolPos.has_value()) if (halfOpaqueSymbolPos[0] > 0)
{ {
DWRITE_TEXT_RANGE textRange = { static_cast<uint32_t>(*halfOpaqueSymbolPos), 2 }; DWRITE_TEXT_RANGE textRange = { static_cast<uint32_t>(*halfOpaqueSymbolPos), 2 };
auto opacityEffect = winrt::make_self<OpacityEffect>(); auto opacityEffect = winrt::make_self<OpacityEffect>();
opacityEffect->alpha = consts::CROSS_OPACITY; opacityEffect->alpha = consts::CROSS_OPACITY;
winrt::check_hresult(textLayout->SetDrawingEffect(opacityEffect.get(), textRange)); winrt::check_hresult(textLayout->SetDrawingEffect(opacityEffect.get(), textRange));
if (halfOpaqueSymbolPos[1] > halfOpaqueSymbolPos[0])
{
textRange = { static_cast<uint32_t>(halfOpaqueSymbolPos[1]), 2 };
winrt::check_hresult(textLayout->SetDrawingEffect(opacityEffect.get(), textRange));
}
} }
winrt::check_hresult(textLayout->Draw(nullptr, textRenderer.get(), textRect.left, textRect.top)); winrt::check_hresult(textLayout->Draw(nullptr, textRenderer.get(), textRect.left, textRect.top));
} }

View File

@@ -35,7 +35,7 @@ struct D2DState
std::vector<D2D1::ColorF> solidBrushesColors); std::vector<D2D1::ColorF> solidBrushesColors);
void DrawTextBox(const wchar_t* text, void DrawTextBox(const wchar_t* text,
const size_t textLen, const size_t textLen,
const std::optional<size_t> halfOpaqueSymbolPos, const size_t halfOpaqueSymbolPos[2],
const D2D_POINT_2F center, const D2D_POINT_2F center,
const bool screenQuadrantAware, const bool screenQuadrantAware,
const HWND window) const; const HWND window) const;

View File

@@ -19,17 +19,17 @@ namespace
{ {
switch (mode) switch (mode)
{ {
case MeasureToolState::Mode::Cross: case MeasureToolState::Mode::Cross:
return { true, true }; return { true, true };
case MeasureToolState::Mode::Vertical: case MeasureToolState::Mode::Vertical:
return { false, true }; return { false, true };
case MeasureToolState::Mode::Horizontal: case MeasureToolState::Mode::Horizontal:
return { true, false }; return { true, false };
default: default:
throw std::runtime_error("Unknown MeasureToolState Mode"); throw std::runtime_error("Unknown MeasureToolState Mode");
} }
} }
@@ -144,10 +144,10 @@ namespace
const auto [crossSymbolPos, measureStringBufLen] = const auto [crossSymbolPos, measureStringBufLen] =
measurement.Print(text.buffer.data(), measurement.Print(text.buffer.data(),
text.buffer.size(), text.buffer.size(),
drawHorizontalCrossLine, drawHorizontalCrossLine,
drawVerticalCrossLine, drawVerticalCrossLine,
commonState.units); commonState.units | Measurement::Unit::Pixel); // Always show pixels.
d2dState.DrawTextBox(text.buffer.data(), d2dState.DrawTextBox(text.buffer.data(),
measureStringBufLen, measureStringBufLen,

View File

@@ -4,7 +4,8 @@
#include <iostream> #include <iostream>
Measurement::Measurement(RECT winRect) Measurement::Measurement(RECT winRect, float px2mmRatio) :
px2mmRatio{ px2mmRatio }
{ {
rect.left = static_cast<float>(winRect.left); rect.left = static_cast<float>(winRect.left);
rect.right = static_cast<float>(winRect.right); rect.right = static_cast<float>(winRect.right);
@@ -12,81 +13,192 @@ Measurement::Measurement(RECT winRect)
rect.bottom = static_cast<float>(winRect.bottom); rect.bottom = static_cast<float>(winRect.bottom);
} }
Measurement::Measurement(D2D1_RECT_F d2dRect) : Measurement::Measurement(D2D1_RECT_F d2dRect, float px2mmRatio) :
rect{ d2dRect } rect{ d2dRect }, px2mmRatio{ px2mmRatio }
{ {
} }
namespace 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: switch (units)
return pixels; {
case Measurement::Unit::Inch: case Measurement::Unit::Pixel:
return pixels / 96.f; return pixels;
case Measurement::Unit::Centimetre: case Measurement::Unit::Inch:
return pixels / 96.f * 2.54f; return pixels * px2mmRatio / 10.0f / 2.54f;
default: case Measurement::Unit::Centimetre:
return pixels; 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 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 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, Measurement::PrintResult Measurement::Print(wchar_t* buf,
const size_t bufSize, const size_t bufSize,
const bool printWidth, const bool printWidth,
const bool printHeight, const bool printHeight,
const Unit units) const const int units) const
{ {
PrintResult result; PrintResult result;
if (printWidth)
{ auto print = [=, &result](Measurement::Unit unit, const bool paren) {
result.strLen += swprintf_s(buf, if (paren)
bufSize, {
L"%g", result.strLen += swprintf_s(buf + result.strLen, bufSize - result.strLen, printWidth && printHeight ? L"\n(" : L" (");
Width(units)); }
if (printHeight) if (printWidth)
{ {
result.crossSymbolPos = result.strLen + 1;
result.strLen += swprintf_s(buf + result.strLen, result.strLen += swprintf_s(buf + result.strLen,
bufSize - 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) break;
{ case Measurement::Unit::Millimetre:
result.strLen += swprintf_s(buf + result.strLen, result.strLen += swprintf_s(buf + result.strLen,
bufSize - result.strLen, bufSize - result.strLen,
L"%g", L" %s",
Height(units)); 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: if ((unit & units) == unit)
result.strLen += swprintf_s(buf + result.strLen, {
bufSize - result.strLen, count += 1;
L" in"); if (count > 2)
break; break;
case Measurement::Unit::Centimetre: print(unit, count != 1);
result.strLen += swprintf_s(buf + result.strLen, }
bufSize - result.strLen,
L" cm");
break;
} }
return result; return result;
@@ -117,15 +229,9 @@ void Measurement::PrintToStream(std::wostream& stream,
stream << Height(units); 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" " << Measurement::GetUnitAbbreviation(units);
stream << L" in";
break;
case Measurement::Unit::Centimetre:
stream << L" cm";
break;
} }
} }

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "pch.h"
#include <dcommon.h> #include <dcommon.h>
#include <windef.h> #include <windef.h>
@@ -8,38 +9,45 @@ struct Measurement
{ {
enum Unit enum Unit
{ {
Pixel, Pixel = 1,
Inch, Inch = 2,
Centimetre Centimetre = 4,
Millimetre = 8,
}; };
D2D1_RECT_F rect = {}; // corners are inclusive 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(const Measurement&) = default;
Measurement& operator=(const Measurement&) = default; Measurement& operator=(const Measurement&) = default;
explicit Measurement(D2D1_RECT_F d2dRect); explicit Measurement(D2D1_RECT_F d2dRect, float px2mmRatio);
explicit Measurement(RECT winRect); explicit Measurement(RECT winRect, float px2mmRatio);
float Width(const Unit units) const; float Width(const Unit units) const;
float Height(const Unit units) const; float Height(const Unit units) const;
struct PrintResult struct PrintResult
{ {
std::optional<size_t> crossSymbolPos; size_t crossSymbolPos[2] = {};
size_t strLen = {}; size_t strLen = {};
}; };
static void InitResources();
static Unit GetUnitFromIndex(int index);
static const wchar_t* GetUnitAbbreviation(const Unit units);
PrintResult Print(wchar_t* buf, PrintResult Print(wchar_t* buf,
const size_t bufSize, const size_t bufSize,
const bool printWidth, const bool printWidth,
const bool printHeight, const bool printHeight,
const Unit units) const; const int units) const;
void PrintToStream(std::wostream& stream, void PrintToStream(std::wostream& stream,
const bool prependNewLine, const bool prependNewLine,
const bool printWidth, const bool printWidth,
const bool printHeight, const bool printHeight,
const Unit units) const; const Unit units) const;
}; };

View File

@@ -62,6 +62,11 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
_mouseCaptureThread.join(); _mouseCaptureThread.join();
} }
void Core::InitResources()
{
Measurement::InitResources();
}
void Core::ResetState() void Core::ResetState()
{ {
_commonState.closeOnOtherMonitors = true; _commonState.closeOnOtherMonitors = true;

View File

@@ -32,6 +32,7 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
~Core(); ~Core();
void Close(); void Close();
void InitResources();
void StartBoundsTool(); void StartBoundsTool();
void StartMeasureTool(const bool horizontal, const bool vertical); void StartMeasureTool(const bool horizontal, const bool vertical);
void SetToolCompletionEvent(ToolSessionCompleted sessionCompletedTrigger); void SetToolCompletionEvent(ToolSessionCompleted sessionCompletedTrigger);

View File

@@ -19,6 +19,7 @@ namespace PowerToys
void StartBoundsTool(); void StartBoundsTool();
void ResetState(); void ResetState();
void InitResources();
void SetToolbarBoundingBox(Int32 fromX, Int32 fromY, Int32 toX, Int32 toY); void SetToolbarBoundingBox(Int32 fromX, Int32 fromY, Int32 toX, Int32 toY);
Single GetDPIScaleForWindow(Int64 windowHandle); Single GetDPIScaleForWindow(Int64 windowHandle);
} }

View File

@@ -294,11 +294,12 @@ void UpdateCaptureState(const CommonState& commonState,
cursorPos, cursorPos,
perColorChannelEdgeDetection, perColorChannelEdgeDetection,
pixelTolerance); pixelTolerance);
auto px2mmRatio = commonState.GetPhysicalPx2MmRatio(window);
#if defined(DEBUG_EDGES) #if defined(DEBUG_EDGES)
char buffer[256]; char buffer[256];
sprintf_s(buffer, 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.x,
cursorPos.y, cursorPos.y,
bounds.left, bounds.left,
@@ -306,11 +307,12 @@ void UpdateCaptureState(const CommonState& commonState,
bounds.right, bounds.right,
bounds.bottom, bounds.bottom,
textureView.view.width, textureView.view.width,
textureView.view.height); textureView.view.height,
px2mmRatio);
OutputDebugStringA(buffer); OutputDebugStringA(buffer);
#endif #endif
state.Access([&](MeasureToolState& state) { state.Access([&](MeasureToolState& state) {
state.perScreen[window].measuredEdges = Measurement{ bounds }; state.perScreen[window].measuredEdges = Measurement{ bounds, px2mmRatio };
}); });
} }

View File

@@ -69,7 +69,8 @@ Settings Settings::LoadFromFile()
try try
{ {
result.units = static_cast<Measurement::Unit>(props.GetNamedObject(JSON_KEY_UNITS_OF_MEASURE).GetNamedNumber(JSON_KEY_VALUE)); auto index = static_cast<int>(props.GetNamedObject(JSON_KEY_UNITS_OF_MEASURE).GetNamedNumber(JSON_KEY_VALUE));
result.units = Measurement::GetUnitFromIndex(index);
} }
catch (...) catch (...)
{ {

View File

@@ -33,6 +33,17 @@ struct CommonState
POINT cursorPosSystemSpace = {}; // updated atomically POINT cursorPosSystemSpace = {}; // updated atomically
std::atomic_bool closeOnOtherMonitors = false; 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<float>(size.width_physical);
}
return ratio;
}
}; };
struct CursorDrag struct CursorDrag

View File

@@ -49,6 +49,7 @@
#include <winrt/Microsoft.UI.Xaml.Navigation.h> #include <winrt/Microsoft.UI.Xaml.Navigation.h>
#include <winrt/Microsoft.UI.Xaml.Shapes.h> #include <winrt/Microsoft.UI.Xaml.Shapes.h>
#include <winrt/Microsoft.UI.Dispatching.h> #include <winrt/Microsoft.UI.Dispatching.h>
#include <winrt/Microsoft.Windows.ApplicationModel.Resources.h>
#include <winrt/Windows.Graphics.DirectX.h> #include <winrt/Windows.Graphics.DirectX.h>
#include <winrt/Windows.Graphics.DirectX.Direct3d11.h> #include <winrt/Windows.Graphics.DirectX.Direct3d11.h>
#include <winrt/Windows.Graphics.Capture.h> #include <winrt/Windows.Graphics.Capture.h>
@@ -73,6 +74,7 @@ namespace winrt
using namespace Microsoft::UI::Xaml; using namespace Microsoft::UI::Xaml;
using namespace Microsoft::UI::Xaml::Controls; using namespace Microsoft::UI::Xaml::Controls;
using namespace Microsoft::UI::Xaml::Navigation; using namespace Microsoft::UI::Xaml::Navigation;
using namespace Microsoft::Windows::ApplicationModel::Resources;
} }
template<typename Func> template<typename Func>

View File

@@ -4,7 +4,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:p="using:PowerToys.MeasureToolUI.Properties"
xmlns:winuiex="using:WinUIEx" xmlns:winuiex="using:WinUIEx"
IsAlwaysOnTop="True" IsAlwaysOnTop="True"
IsMaximizable="False" IsMaximizable="False"

View File

@@ -64,6 +64,7 @@ namespace MeasureToolUI
_ = SetWindowLong(hwnd, GWL_STYLE, windowStyle); _ = SetWindowLong(hwnd, GWL_STYLE, windowStyle);
_coreLogic = core; _coreLogic = core;
_coreLogic.InitResources();
Closed += MainWindow_Closed; Closed += MainWindow_Closed;
DisplayArea displayArea = DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest); DisplayArea displayArea = DisplayArea.GetFromWindowId(windowId, DisplayAreaFallback.Nearest);
float dpiScale = _coreLogic.GetDPIScaleForWindow((int)hwnd); float dpiScale = _coreLogic.GetDPIScaleForWindow((int)hwnd);

View File

@@ -66,4 +66,16 @@
<data name="BtnClosePanelTooltip.Text" xml:space="preserve"> <data name="BtnClosePanelTooltip.Text" xml:space="preserve">
<value>Close (Esc)</value> <value>Close (Esc)</value>
</data> </data>
<data name="MeasurementUnitAbbrPixel" xml:space="preserve">
<value>px</value>
</data>
<data name="MeasurementUnitAbbrInch" xml:space="preserve">
<value>in</value>
</data>
<data name="MeasurementUnitAbbrCentimetre" xml:space="preserve">
<value>cm</value>
</data>
<data name="MeasurementUnitAbbrMillimetre" xml:space="preserve">
<value>mm</value>
</data>
</root> </root>

View File

@@ -38,7 +38,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonConverter(typeof(BoolPropertyJsonConverter))] [JsonConverter(typeof(BoolPropertyJsonConverter))]
public bool PerColorChannelEdgeDetection { get; set; } public bool PerColorChannelEdgeDetection { get; set; }
[CmdConfigureIgnore]
public IntProperty UnitsOfMeasure { get; set; } public IntProperty UnitsOfMeasure { get; set; }
public IntProperty PixelTolerance { get; set; } public IntProperty PixelTolerance { get; set; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 KiB

After

Width:  |  Height:  |  Size: 599 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@@ -64,13 +64,14 @@
Value="{x:Bind ViewModel.PixelTolerance, Mode=TwoWay}" /> Value="{x:Bind ViewModel.PixelTolerance, Mode=TwoWay}" />
</tkcontrols:SettingsCard> </tkcontrols:SettingsCard>
<!--<tkcontrols:SettingsCard x:Uid="MeasureTool_UnitsOfMeasure" HeaderIcon="{ui:FontIcon Glyph=&#xECC6;}"> <tkcontrols:SettingsCard x:Uid="MeasureTool_UnitsOfMeasure" HeaderIcon="{ui:FontIcon Glyph=&#xECC6;}">
<ComboBox SelectedIndex="{x:Bind Path=ViewModel.UnitsOfMeasure, Mode=TwoWay}" MinWidth="{StaticResource SettingActionControlMinWidth}"> <ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.UnitsOfMeasure, Mode=TwoWay}">
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Pixels" /> <ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Pixels" />
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Inches" /> <ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Inches" />
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Centimeters" /> <ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Centimeters" />
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Millimeters" />
</ComboBox> </ComboBox>
</tkcontrols:SettingsCard>--> </tkcontrols:SettingsCard>
<tkcontrols:SettingsCard x:Uid="MeasureTool_DrawFeetOnCross"> <tkcontrols:SettingsCard x:Uid="MeasureTool_DrawFeetOnCross">
<ToggleSwitch x:Uid="MeasureTool_DrawFeetOnCross_ToggleSwitch" IsOn="{x:Bind ViewModel.DrawFeetOnCross, Mode=TwoWay}" /> <ToggleSwitch x:Uid="MeasureTool_DrawFeetOnCross_ToggleSwitch" IsOn="{x:Bind ViewModel.DrawFeetOnCross, Mode=TwoWay}" />

View File

@@ -177,10 +177,10 @@
<value>Vertical spacing</value> <value>Vertical spacing</value>
</data> </data>
<data name="MeasureTool_UnitsOfMeasure.Header" xml:space="preserve"> <data name="MeasureTool_UnitsOfMeasure.Header" xml:space="preserve">
<value>Units of measurement</value> <value>Extra units of measurement</value>
</data> </data>
<data name="MeasureTool_UnitsOfMeasure_Pixels.Content" xml:space="preserve"> <data name="MeasureTool_UnitsOfMeasure_Pixels.Content" xml:space="preserve">
<value>Pixels</value> <value>Show only pixels</value>
</data> </data>
<data name="MeasureTool_UnitsOfMeasure_Inches.Content" xml:space="preserve"> <data name="MeasureTool_UnitsOfMeasure_Inches.Content" xml:space="preserve">
<value>Inches</value> <value>Inches</value>
@@ -188,6 +188,9 @@
<data name="MeasureTool_UnitsOfMeasure_Centimeters.Content" xml:space="preserve"> <data name="MeasureTool_UnitsOfMeasure_Centimeters.Content" xml:space="preserve">
<value>Centimeters</value> <value>Centimeters</value>
</data> </data>
<data name="MeasureTool_UnitsOfMeasure_Millimeters.Content" xml:space="preserve">
<value>Millimeters</value>
</data>
<data name="MeasureTool_PixelTolerance.Header" xml:space="preserve"> <data name="MeasureTool_PixelTolerance.Header" xml:space="preserve">
<value>Pixel tolerance for edge detection</value> <value>Pixel tolerance for edge detection</value>
</data> </data>