Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Fix tooltips in high dpi",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ void ComponentView::updateProps(
updateShadowProps(oldViewProps, newViewProps);
}
if (oldViewProps.tooltip != newViewProps.tooltip) {
if (!m_tooltipTracked && newViewProps.tooltip) {
if (!m_tooltipTracked && newViewProps.tooltip && !newViewProps.tooltip->empty()) {
TooltipService::GetCurrent(m_reactContext.Properties())->StartTracking(*this);
m_tooltipTracked = true;
} else if (m_tooltipTracked && !newViewProps.tooltip) {
Expand Down
76 changes: 40 additions & 36 deletions vnext/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
#include <winrt/Microsoft.ReactNative.Composition.h>
#include <winrt/Windows.UI.ViewManagement.h>
#include "TextDrawing.h"
#include "dwmapi.h"

Expand Down Expand Up @@ -49,6 +50,8 @@ facebook::react::AttributedStringBox CreateTooltipAttributedString(const std::st
auto fragment = facebook::react::AttributedString::Fragment{};
fragment.string = tooltip;
fragment.textAttributes.fontSize = tooltipFontSize;
fragment.textAttributes.fontSizeMultiplier =
static_cast<float>(winrt::Windows::UI::ViewManagement::UISettings().TextScaleFactor());
attributedString.appendFragment(std::move(fragment));
return facebook::react::AttributedStringBox{attributedString};
}
Expand Down Expand Up @@ -231,14 +234,13 @@ void TooltipTracker::OnUnmounted(
}

void TooltipTracker::ShowTooltip(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
auto viewCompView = view.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();

auto selfView =
winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView>(viewCompView);
auto parentHwnd = selfView->GetHwndForParenting();
DestroyTimer();

if (!m_hwndTip) {
auto viewCompView = view.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();
auto selfView =
winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView>(viewCompView);
auto parentHwnd = selfView->GetHwndForParenting();
auto tooltipData = std::make_unique<TooltipData>(view);
tooltipData->attributedString = CreateTooltipAttributedString(*selfView->viewProps()->tooltip);

Expand All @@ -256,37 +258,39 @@ void TooltipTracker::ShowTooltip(const winrt::Microsoft::ReactNative::ComponentV
facebook::react::TextLayoutManager::GetTextLayout(
tooltipData->attributedString, {} /*paragraphAttributes*/, layoutConstraints, tooltipData->textLayout);

DWRITE_TEXT_METRICS tm;
winrt::check_hresult(tooltipData->textLayout->GetMetrics(&tm));

tooltipData->width =
static_cast<int>(tm.width + ((tooltipHorizontalPadding + tooltipHorizontalPadding) * scaleFactor));
tooltipData->height = static_cast<int>(tm.height + ((tooltipTopPadding + tooltipBottomPadding) * scaleFactor));

POINT pt = {static_cast<LONG>(m_pos.X), static_cast<LONG>(m_pos.Y)};
ClientToScreen(parentHwnd, &pt);

RegisterTooltipWndClass();
HINSTANCE hInstance = GetModuleHandle(NULL);
m_hwndTip = CreateWindow(
c_tooltipWindowClassName,
L"Tooltip",
WS_POPUP,
pt.x - tooltipData->width / 2,
static_cast<int>(pt.y - tooltipData->height - (toolTipPlacementMargin * scaleFactor)),
tooltipData->width,
tooltipData->height,
parentHwnd,
NULL,
hInstance,
tooltipData.get());

DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUNDSMALL;
UINT borderThickness = 0;
DwmSetWindowAttribute(m_hwndTip, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));

tooltipData.release();
AnimateWindow(m_hwndTip, toolTipAnimationTimeMs, AW_BLEND);
if (tooltipData->textLayout) {
DWRITE_TEXT_METRICS tm;
winrt::check_hresult(tooltipData->textLayout->GetMetrics(&tm));

tooltipData->width =
static_cast<int>((tm.width + tooltipHorizontalPadding + tooltipHorizontalPadding) * scaleFactor);
tooltipData->height = static_cast<int>((tm.height + tooltipTopPadding + tooltipBottomPadding) * scaleFactor);

POINT pt = {static_cast<LONG>(m_pos.X), static_cast<LONG>(m_pos.Y)};
ClientToScreen(parentHwnd, &pt);

RegisterTooltipWndClass();
HINSTANCE hInstance = GetModuleHandle(NULL);
m_hwndTip = CreateWindow(
c_tooltipWindowClassName,
L"Tooltip",
WS_POPUP,
pt.x - tooltipData->width / 2,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[non-blocking|commentary] interesting, I noticed the file explorer tooltips use this pattern (centered over the mouse point, fixed distance above mouse point unless it would push the tooltip off-screen) though the Edge/webview tooltips still align the mouse point with their top-left corner.

and the minimize/maximize/close buttons in windows still use the old-school tooltips, hah.

static_cast<int>(pt.y - tooltipData->height - (toolTipPlacementMargin * scaleFactor)),
tooltipData->width,
tooltipData->height,
parentHwnd,
NULL,
hInstance,
tooltipData.get());

DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUNDSMALL;
UINT borderThickness = 0;
DwmSetWindowAttribute(m_hwndTip, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));

tooltipData.release();
AnimateWindow(m_hwndTip, toolTipAnimationTimeMs, AW_BLEND);
}
}
}

Expand Down
Loading