[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
|
@ -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
|
||||
|
|
Двоичные данные
doc/images/overview/MeasureTool_large.png
До Ширина: | Высота: | Размер: 36 KiB После Ширина: | Высота: | Размер: 59 KiB |
Двоичные данные
doc/images/overview/MeasureTool_small.png
До Ширина: | Высота: | Размер: 18 KiB После Ширина: | Высота: | Размер: 19 KiB |
|
@ -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<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{};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#pragma comment(lib, "Gdi32.lib")
|
||||
#include <Windows.h>
|
||||
|
||||
#include <compare>
|
||||
|
@ -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<MonitorInfo> GetMonitors(bool includeNonWorkingArea);
|
||||
static MonitorInfo GetPrimaryMonitor();
|
||||
static MonitorInfo GetFromWindow(HWND);
|
||||
static MonitorInfo GetFromPoint(int32_t, int32_t);
|
||||
|
||||
private:
|
||||
static Size GetSize(const MONITORINFOEX&);
|
||||
};
|
||||
|
|
|
@ -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<float>(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ D2DState::D2DState(const DxgiAPI* dxgi,
|
|||
|
||||
void D2DState::DrawTextBox(const wchar_t* text,
|
||||
const size_t textLen,
|
||||
const std::optional<size_t> 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<uint32_t>(*halfOpaqueSymbolPos), 2 };
|
||||
auto opacityEffect = winrt::make_self<OpacityEffect>();
|
||||
opacityEffect->alpha = consts::CROSS_OPACITY;
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ struct D2DState
|
|||
std::vector<D2D1::ColorF> solidBrushesColors);
|
||||
void DrawTextBox(const wchar_t* text,
|
||||
const size_t textLen,
|
||||
const std::optional<size_t> halfOpaqueSymbolPos,
|
||||
const size_t halfOpaqueSymbolPos[2],
|
||||
const D2D_POINT_2F center,
|
||||
const bool screenQuadrantAware,
|
||||
const HWND window) const;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
Measurement::Measurement(RECT winRect)
|
||||
Measurement::Measurement(RECT winRect, float px2mmRatio) :
|
||||
px2mmRatio{ px2mmRatio }
|
||||
{
|
||||
rect.left = static_cast<float>(winRect.left);
|
||||
rect.right = static_cast<float>(winRect.right);
|
||||
|
@ -12,81 +13,192 @@ Measurement::Measurement(RECT winRect)
|
|||
rect.bottom = static_cast<float>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
#include <dcommon.h>
|
||||
#include <windef.h>
|
||||
|
@ -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<size_t> 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;
|
||||
};
|
||||
|
|
|
@ -62,6 +62,11 @@ namespace winrt::PowerToys::MeasureToolCore::implementation
|
|||
_mouseCaptureThread.join();
|
||||
}
|
||||
|
||||
void Core::InitResources()
|
||||
{
|
||||
Measurement::InitResources();
|
||||
}
|
||||
|
||||
void Core::ResetState()
|
||||
{
|
||||
_commonState.closeOnOtherMonitors = true;
|
||||
|
|
|
@ -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<std::thread> _screenCaptureThreads;
|
||||
|
||||
|
||||
std::vector<std::unique_ptr<OverlayUIState>> _overlayUIStates;
|
||||
Serialized<MeasureToolState> _measureToolState;
|
||||
BoundsToolState _boundsToolState;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,8 @@ Settings Settings::LoadFromFile()
|
|||
|
||||
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 (...)
|
||||
{
|
||||
|
|
|
@ -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<float>(size.width_physical);
|
||||
}
|
||||
return ratio;
|
||||
}
|
||||
};
|
||||
|
||||
struct CursorDrag
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include <winrt/Microsoft.UI.Xaml.Navigation.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.Shapes.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.Direct3d11.h>
|
||||
#include <winrt/Windows.Graphics.Capture.h>
|
||||
|
@ -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<typename Func>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -66,4 +66,16 @@
|
|||
<data name="BtnClosePanelTooltip.Text" xml:space="preserve">
|
||||
<value>Close (Esc)</value>
|
||||
</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>
|
|
@ -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; }
|
||||
|
|
До Ширина: | Высота: | Размер: 403 KiB После Ширина: | Высота: | Размер: 599 KiB |
До Ширина: | Высота: | Размер: 29 KiB После Ширина: | Высота: | Размер: 59 KiB |
|
@ -64,13 +64,14 @@
|
|||
Value="{x:Bind ViewModel.PixelTolerance, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<!--<tkcontrols:SettingsCard x:Uid="MeasureTool_UnitsOfMeasure" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox SelectedIndex="{x:Bind Path=ViewModel.UnitsOfMeasure, Mode=TwoWay}" MinWidth="{StaticResource SettingActionControlMinWidth}">
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_UnitsOfMeasure" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox MinWidth="{StaticResource SettingActionControlMinWidth}" SelectedIndex="{x:Bind Path=ViewModel.UnitsOfMeasure, Mode=TwoWay}">
|
||||
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Pixels" />
|
||||
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Inches" />
|
||||
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Centimeters" />
|
||||
<ComboBoxItem x:Uid="MeasureTool_UnitsOfMeasure_Millimeters" />
|
||||
</ComboBox>
|
||||
</tkcontrols:SettingsCard>-->
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="MeasureTool_DrawFeetOnCross">
|
||||
<ToggleSwitch x:Uid="MeasureTool_DrawFeetOnCross_ToggleSwitch" IsOn="{x:Bind ViewModel.DrawFeetOnCross, Mode=TwoWay}" />
|
||||
|
|
|
@ -177,10 +177,10 @@
|
|||
<value>Vertical spacing</value>
|
||||
</data>
|
||||
<data name="MeasureTool_UnitsOfMeasure.Header" xml:space="preserve">
|
||||
<value>Units of measurement</value>
|
||||
<value>Extra units of measurement</value>
|
||||
</data>
|
||||
<data name="MeasureTool_UnitsOfMeasure_Pixels.Content" xml:space="preserve">
|
||||
<value>Pixels</value>
|
||||
<value>Show only pixels</value>
|
||||
</data>
|
||||
<data name="MeasureTool_UnitsOfMeasure_Inches.Content" xml:space="preserve">
|
||||
<value>Inches</value>
|
||||
|
@ -188,6 +188,9 @@
|
|||
<data name="MeasureTool_UnitsOfMeasure_Centimeters.Content" xml:space="preserve">
|
||||
<value>Centimeters</value>
|
||||
</data>
|
||||
<data name="MeasureTool_UnitsOfMeasure_Millimeters.Content" xml:space="preserve">
|
||||
<value>Millimeters</value>
|
||||
</data>
|
||||
<data name="MeasureTool_PixelTolerance.Header" xml:space="preserve">
|
||||
<value>Pixel tolerance for edge detection</value>
|
||||
</data>
|
||||
|
|