Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Screen Ruler]New feature for screen ruler, showing the measurement in an extra unit #35887

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ devblogs
devdocs
devenum
devmgmt
DEVMODE
DEVMODEW
DEVMON
devpkey
Expand Down Expand Up @@ -608,6 +609,7 @@ hmenu
hmodule
hmonitor
homljgmgpmcbpjbnjpfijnhipfkiclkd
HORZSIZE
Hostbackdropbrush
hotkeycontrol
hotkeys
Expand Down Expand Up @@ -1133,6 +1135,7 @@ pcelt
pch
pchast
PCIDLIST
PCTSTR
PCWSTR
pdbs
pdisp
Expand Down Expand Up @@ -1276,6 +1279,7 @@ RAlt
Rasterize
RAWINPUTDEVICE
RAWINPUTHEADER
RAWMODE
RAWPATH
rbhid
rclsid
Expand Down Expand Up @@ -1727,6 +1731,7 @@ VERBW
VERIFYCONTEXT
verrsrc
VERSIONINFO
VERTSIZE
VFT
vget
vgetq
Expand Down
Binary file modified doc/images/overview/MeasureTool_large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/overview/MeasureTool_small.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 46 additions & 2 deletions src/common/Display/monitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ bool MonitorInfo::IsPrimary() const
MonitorInfo::MonitorInfo(HMONITOR h) :
handle{ h }
{
info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfoW(handle, &info);
if (handle != nullptr)
{
info.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfoW(handle, &info);
size = GetSize(info);
}
}

static BOOL CALLBACK GetDisplaysEnumCb(HMONITOR monitor, HDC /*hdc*/, LPRECT /*rect*/, LPARAM data)
Expand Down Expand Up @@ -52,3 +56,43 @@ 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;
}
25 changes: 25 additions & 0 deletions src/common/Display/monitors.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#pragma comment(lib, "Gdi32.lib")
#include <Windows.h>

#include <compare>
Expand Down Expand Up @@ -42,8 +43,18 @@ 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;
} Geometry;

private:
HMONITOR handle;
MONITORINFOEX info = {};
Size size = {};

public:
explicit MonitorInfo(HMONITOR h);
Expand All @@ -53,8 +64,22 @@ class MonitorInfo
}
Box GetScreenSize(const bool includeNonWorkingArea) const;
bool IsPrimary() const;
inline Size GetSize() const
{
return size;
}
inline float GetPhysicalPx2MmRatio() const
{
auto monitorSize = GetSize();
return monitorSize.width_mm / static_cast<float>(monitorSize.width_physical);
}

// 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&);
};
15 changes: 9 additions & 6 deletions src/modules/MeasureTool/MeasureToolCore/BoundsToolOverlayUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

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) =
std::minmax(static_cast<float>(cursorPos.x), currentBounds.startPos.x);
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)
Expand All @@ -29,7 +29,8 @@ namespace

if (handle == window && perScreen.currentBounds)
{
allMeasurements.push_back(GetMeasurement(*perScreen.currentBounds, cursorPos));
auto px2mmRatio = MonitorInfo::GetFromWindow(window).GetPhysicalPx2MmRatio();
allMeasurements.push_back(GetMeasurement(*perScreen.currentBounds, cursorPos, px2mmRatio));
}
}

Expand Down Expand Up @@ -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 = MonitorInfo::GetFromWindow(window).GetPhysicalPx2MmRatio();
perScreen.measurements.push_back(GetMeasurement(*perScreen.currentBounds, cursorPos, px2mmRatio));
}

perScreen.currentBounds = std::nullopt;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 = MonitorInfo::GetFromWindow(window).GetPhysicalPx2MmRatio();
DrawMeasurement(Measurement{ rect, px2mmRatio }, commonState, window, d2dState, perScreen.currentBounds->currentPos);
}
}
12 changes: 8 additions & 4 deletions src/modules/MeasureTool/MeasureToolCore/D2DState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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));
Expand Down Expand Up @@ -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] > 0 && 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));
}
Expand Down
2 changes: 1 addition & 1 deletion src/modules/MeasureTool/MeasureToolCore/D2DState.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 13 additions & 13 deletions src/modules/MeasureTool/MeasureToolCore/MeasureToolOverlayUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}

Expand Down Expand Up @@ -77,7 +77,7 @@ namespace
CopyToClipboard(window, *toolState);

auto& perScreen = toolState->perScreen[window];

const bool shiftPress = GetKeyState(VK_SHIFT) & 0x8000;
if (shiftPress && perScreen.measuredEdges)
{
Expand Down Expand Up @@ -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,
Expand Down
Loading
Loading