Skip to content

Commit

Permalink
[Fabric] APIs to enable RootViews that size to content (#13269)
Browse files Browse the repository at this point in the history
* APIs to enable RootViews that size to content

* Change files

* Replace emptyimpl with E_NOTIMPL

* Update vnext/Microsoft.ReactNative/Fabric/Composition/CompositionRootView.cpp

Co-authored-by: Marlene Cota <[email protected]>

* Update vnext/Microsoft.ReactNative/Fabric/Composition/CompositionRootView.cpp

Co-authored-by: Marlene Cota <[email protected]>

---------

Co-authored-by: Marlene Cota <[email protected]>
  • Loading branch information
acoates-ms and marlenecota authored May 28, 2024
1 parent 7d125ca commit b150f8e
Show file tree
Hide file tree
Showing 21 changed files with 251 additions and 293 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "APIs to enable RootViews that size to content",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ void UpdateRootViewSizeToAppWindow(
// Do not relayout when minimized
if (window.Presenter().as<winrt::Microsoft::UI::Windowing::OverlappedPresenter>().State() !=
winrt::Microsoft::UI::Windowing::OverlappedPresenterState::Minimized) {
rootView.Arrange(size);
rootView.Size(size);
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
constraints.MaximumSize = constraints.MinimumSize = size;
rootView.Arrange(constraints, {0, 0});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ struct WindowData {
winrt::Microsoft::ReactNative::ReactNativeHost m_host{nullptr};
winrt::Microsoft::ReactNative::ReactInstanceSettings m_instanceSettings{nullptr};
bool m_useLiftedComposition{true};
bool m_sizeToContent{false};
winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget m_target{nullptr};
LONG m_height{0};
LONG m_width{0};
Expand Down Expand Up @@ -195,6 +196,11 @@ struct WindowData {
return winrt::Microsoft::UI::GetWindowIdFromWindow(childHwnd);
}

void ApplyConstraintsForContentSizedWindow(winrt::Microsoft::ReactNative::LayoutConstraints &constraints) {
constraints.MinimumSize = {300, 300};
constraints.MaximumSize = {1000, 1000};
}

LRESULT OnCommand(HWND hwnd, int id, HWND /* hwndCtl*/, UINT) {
switch (id) {
case IDM_OPENJSFILE: {
Expand Down Expand Up @@ -254,7 +260,35 @@ struct WindowData {
bridge.Show();

m_compRootView.ScaleFactor(ScaleFactor(hwnd));
m_compRootView.Size({m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)});
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight;
constraints.MaximumSize =
constraints.MinimumSize = {m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};

if (m_sizeToContent) {
ApplyConstraintsForContentSizedWindow(constraints);

// Disable user sizing of the hwnd
::SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX);
m_compRootView.SizeChanged(
[hwnd](auto sender, const winrt::Microsoft::ReactNative::RootViewSizeChangedEventArgs &args) {
RECT rcClient, rcWindow;
GetClientRect(hwnd, &rcClient);
GetWindowRect(hwnd, &rcWindow);

SetWindowPos(
hwnd,
nullptr,
0,
0,
static_cast<int>(args.Size().Width) + rcClient.left - rcClient.right + rcWindow.right -
rcWindow.left,
static_cast<int>(args.Size().Height) + rcClient.top - rcClient.bottom + rcWindow.bottom -
rcWindow.top,
SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
});
}
m_compRootView.Arrange(constraints, {0, 0});

bridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow);

Expand Down Expand Up @@ -291,7 +325,10 @@ struct WindowData {
.InternalRootVisual(winrt::Microsoft::ReactNative::Composition::Experimental::
SystemCompositionContextHelper::CreateVisual(root));
m_compRootView.ScaleFactor(ScaleFactor(hwnd));
m_compRootView.Size({m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)});
winrt::Microsoft::ReactNative::LayoutConstraints contraints;
contraints.MaximumSize =
contraints.MinimumSize = {m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
m_compRootView.Arrange(contraints, {0, 0});
}
}

Expand Down Expand Up @@ -353,8 +390,13 @@ struct WindowData {
if (m_compRootView) {
winrt::Windows::Foundation::Size size{m_width / ScaleFactor(hwnd), m_height / ScaleFactor(hwnd)};
if (!IsIconic(hwnd)) {
m_compRootView.Arrange(size);
m_compRootView.Size(size);
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight;
constraints.MinimumSize = constraints.MaximumSize = size;
if (m_sizeToContent) {
ApplyConstraintsForContentSizedWindow(constraints);
}
m_compRootView.Arrange(constraints, {0, 0});
}
}
}
Expand Down Expand Up @@ -449,6 +491,7 @@ struct WindowData {
CheckDlgButton(hwnd, IDC_FASTREFRESH, boolToCheck(self->InstanceSettings().UseFastRefresh()));
CheckDlgButton(hwnd, IDC_DIRECTDEBUGGER, boolToCheck(self->InstanceSettings().UseDirectDebugger()));
CheckDlgButton(hwnd, IDC_BREAKONNEXTLINE, boolToCheck(self->InstanceSettings().DebuggerBreakOnNextLine()));
CheckDlgButton(hwnd, IDC_SIZETOCONTENT, boolToCheck(self->m_sizeToContent));

auto portEditControl = GetDlgItem(hwnd, IDC_DEBUGGERPORT);
SetWindowTextW(portEditControl, std::to_wstring(self->InstanceSettings().DebuggerPort()).c_str());
Expand All @@ -472,6 +515,7 @@ struct WindowData {
self->InstanceSettings().UseDirectDebugger(IsDlgButtonChecked(hwnd, IDC_DIRECTDEBUGGER) == BST_CHECKED);
self->InstanceSettings().DebuggerBreakOnNextLine(
IsDlgButtonChecked(hwnd, IDC_BREAKONNEXTLINE) == BST_CHECKED);
self->m_sizeToContent = (IsDlgButtonChecked(hwnd, IDC_SIZETOCONTENT) == BST_CHECKED);

WCHAR buffer[6] = {};
auto portEditControl = GetDlgItem(hwnd, IDC_DEBUGGERPORT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ BEGIN
DEFPUSHBUTTON "OK",IDOK,201,96,50,14,WS_GROUP
END

IDD_SETTINGSBOX DIALOGEX 0, 0, 192, 159
IDD_SETTINGSBOX DIALOGEX 0, 0, 192, 178
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Settings"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
Expand All @@ -109,14 +109,15 @@ BEGIN
CONTROL "&Fast Refresh",IDC_FASTREFRESH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,26,104,10
CONTROL "&Direct Debugger",IDC_DIRECTDEBUGGER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,44,104,10
CONTROL "&Break On Next Line",IDC_BREAKONNEXTLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,63,104,10
LTEXT "Debugger Port",IDC_DEBUGGERPORTLABEL,8,81,50,10
EDITTEXT IDC_DEBUGGERPORT,59,79,28,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "JS Engine",IDC_JSENGINELABEL,8,100,50,10
COMBOBOX IDC_JSENGINE,59,98,104,10,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_TABSTOP
COMBOBOX IDC_THEME,59,117,104,10,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_TABSTOP
LTEXT "Theme",IDC_THEMELABEL,8,119,50,10
DEFPUSHBUTTON "OK",IDOK,75,138,50,14,WS_GROUP
PUSHBUTTON "Cancel",IDCANCEL,130,138,50,14
CONTROL "&Size Window To React Content",IDC_SIZETOCONTENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,82,104,10
LTEXT "Debugger Port",IDC_DEBUGGERPORTLABEL,8,100,50,10
EDITTEXT IDC_DEBUGGERPORT,59,98,28,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "JS Engine",IDC_JSENGINELABEL,8,119,50,10
COMBOBOX IDC_JSENGINE,59,116,104,10,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_TABSTOP
COMBOBOX IDC_THEME,59,136,104,10,CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_TABSTOP
LTEXT "Theme",IDC_THEMELABEL,8,138,50,10
DEFPUSHBUTTON "OK",IDOK,75,157,50,14,WS_GROUP
PUSHBUTTON "Cancel",IDCANCEL,130,157,50,14
END

IDD_OPENJSBUNDLEBOX DIALOGEX 0, 0, 256, 177
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#define IDC_THEME 109
#define IDC_THEMELABEL 110
#define IDC_JSENGINELABEL 111
#define IDC_SIZETOCONTENT 112
#define IDI_ICON1 1008

// Next default values for new objects
Expand Down
3 changes: 3 additions & 0 deletions vnext/Desktop/module.g.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ void* winrt_make_facebook_react_NativeLogEventSource();
void* winrt_make_facebook_react_NativeTraceEventSource();

#ifndef USE_FABRIC
void* winrt_make_Microsoft_ReactNative_CompositionRootView() {
winrt::throw_hresult(E_NOTIMPL);
}
void* winrt_make_Microsoft_ReactNative_Composition_ViewComponentView() {
winrt::throw_hresult(E_NOTIMPL);
}
Expand Down
16 changes: 13 additions & 3 deletions vnext/Microsoft.ReactNative/CompositionRootView.idl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "IJSValueWriter.idl";
import "ReactCoreInjection.idl";
import "ReactNativeHost.idl";
import "Theme.idl";
import "IReactViewComponentBuilder.idl";
#include "NamespaceRedirect.h"
#include "DocString.h"

Expand Down Expand Up @@ -61,6 +62,13 @@ namespace Microsoft.ReactNative
}
}

[default_interface]
[webhosthidden]
[experimental]
runtimeclass RootViewSizeChangedEventArgs {
Windows.Foundation.Size Size { get; };
}

[default_interface]
[webhosthidden]
[experimental]
Expand All @@ -82,16 +90,16 @@ namespace Microsoft.ReactNative
DOC_STRING("The RootVisual associated with the @CompositionRootView. It must be set to show any React UI elements.")
Microsoft.UI.Composition.Visual RootVisual { get; };

Windows.Foundation.Size Size {get; set; };
Windows.Foundation.Size Size { get; };

DOC_STRING("ScaleFactor for this windows (DPI/96)")
Single ScaleFactor {get; set;};

DOC_STRING("Move focus to this @CompositionRootView")
FocusNavigationResult NavigateFocus(FocusNavigationRequest request);

Windows.Foundation.Size Measure(Windows.Foundation.Size availableSize);
Windows.Foundation.Size Arrange(Windows.Foundation.Size availableSize);
Windows.Foundation.Size Measure(LayoutConstraints layoutConstraints, Windows.Foundation.Point viewportOffset);
void Arrange(LayoutConstraints layoutConstraints, Windows.Foundation.Point viewportOffset);

Object GetUiaProvider();

Expand All @@ -104,6 +112,8 @@ namespace Microsoft.ReactNative
#ifdef USE_WINUI3
Microsoft.UI.Content.ContentIsland Island { get; };
#endif

event Windows.Foundation.EventHandler<RootViewSizeChangedEventArgs> SizeChanged;
}

} // namespace Microsoft.ReactNative
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ CompositionEventHandler::CompositionEventHandler(
: static_cast<facebook::react::Tag>(
winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(
strongRootView)
->GetTag()),
->RootTag()),
args);
auto keyboardSource = winrt::make<CompositionInputKeyboardSource>(source);
onKeyDown(keyboardSource, keyArgs);
Expand All @@ -266,7 +266,7 @@ CompositionEventHandler::CompositionEventHandler(
: static_cast<facebook::react::Tag>(
winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(
strongRootView)
->GetTag()),
->RootTag()),
args);
auto keyboardSource = winrt::make<CompositionInputKeyboardSource>(source);
onKeyUp(keyboardSource, keyArgs);
Expand All @@ -290,7 +290,7 @@ CompositionEventHandler::CompositionEventHandler(
: static_cast<facebook::react::Tag>(
winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(
strongRootView)
->GetTag()),
->RootTag()),
args);
auto keyboardSource = winrt::make<CompositionInputKeyboardSource>(source);
onCharacterReceived(keyboardSource, charArgs);
Expand Down Expand Up @@ -323,7 +323,7 @@ CompositionEventHandler::~CompositionEventHandler() {
facebook::react::SurfaceId CompositionEventHandler::SurfaceId() const noexcept {
if (auto strongRootView = m_wkRootView.get()) {
return static_cast<facebook::react::SurfaceId>(
winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(strongRootView)->GetTag());
winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(strongRootView)->RootTag());
}
return -1;
}
Expand Down Expand Up @@ -460,7 +460,7 @@ int64_t CompositionEventHandler::SendMessage(HWND hwnd, uint32_t msg, uint64_t w
: static_cast<facebook::react::Tag>(
winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(
strongRootView)
->GetTag()),
->RootTag()),
msg,
wParam,
lParam);
Expand All @@ -481,7 +481,7 @@ int64_t CompositionEventHandler::SendMessage(HWND hwnd, uint32_t msg, uint64_t w
: static_cast<facebook::react::Tag>(
winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(
strongRootView)
->GetTag()),
->RootTag()),
msg,
wParam,
lParam);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ void CompositionHwndHost::UpdateSize() noexcept {
static_cast<float>(m_width / ScaleFactor()), static_cast<float>(m_height / ScaleFactor())};
// Do not relayout when minimized
if (!IsIconic(m_hwnd)) {
m_compRootView.Size(size);
m_compRootView.Arrange(size);
winrt::Microsoft::ReactNative::LayoutConstraints constraints;
constraints.MinimumSize = constraints.MaximumSize = size;
m_compRootView.Arrange(constraints, {0, 0});
}
}
}
Expand Down
Loading

0 comments on commit b150f8e

Please sign in to comment.