Skip to content

Instantly share code, notes, and snippets.

@lyahdav
Created October 28, 2020 19:45
Show Gist options
  • Save lyahdav/149b58da686890bc87f60ad731c50636 to your computer and use it in GitHub Desktop.
Save lyahdav/149b58da686890bc87f60ad731c50636 to your computer and use it in GitHub Desktop.
// (c) Facebook, Inc. and its affiliates. Confidential and proprietary.
#include "ContextMenuModule.h"
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
using namespace Microsoft::ReactNative;
void ContextMenu::initialize(React::ReactContext const& reactContext) noexcept {
m_context = reactContext;
}
void ContextMenu::showMenu(
const int target,
const React::JSValueArray items,
const std::function<void(React::JSValue, int)> onClick) noexcept {
m_context.UIDispatcher().Post(
[weakThis = weak_from_this(), target, items = items.Copy(), onClick] {
if (auto strongThis = weakThis.lock()) {
strongThis->ShowMenuFromUIDispatcher(target, items, onClick);
}
});
}
void ContextMenu::ShowMenuFromUIDispatcher(
const int target,
const React::JSValueArray& items,
const std::function<void(React::JSValue, int)> onClick) noexcept {
auto xamlRoot =
React::XamlUIService::GetXamlRoot(m_context.Properties().Handle());
if (!xamlRoot) {
return;
}
auto menu = winrt::MenuFlyout();
menu.XamlRoot(xamlRoot);
for (int i = 0; i < items.size(); i++) {
auto menuItem = CreateMenuItem(items[i], onClick, i);
menu.Items().Append(menuItem);
}
winrt::FrameworkElement targetElement = nullptr;
if (target > 0) {
auto xamlUIService = React::XamlUIService::FromContext(m_context.Handle());
targetElement =
xamlUIService.ElementFromReactTag(target).as<winrt::FrameworkElement>();
}
if (targetElement != nullptr) {
menu.ShowAt(targetElement);
} else {
menu.ShowAt(targetElement, GetPointerPosition());
}
}
winrt::MenuFlyoutItem ContextMenu::CreateMenuItem(
const React::JSValue& item,
const std::function<void(React::JSValue, int)> onClick,
const int index) noexcept {
auto menuItem = winrt::MenuFlyoutItem();
menuItem.Text(winrt::to_hstring(*item["label"].TryGetString()));
menuItem.Click(
[=](auto const& /*sender*/, winrt::RoutedEventArgs const& /*args*/) {
onClick(nullptr, index);
});
auto iconPtr = item["icon"].TryGetObject();
if (iconPtr != nullptr) {
auto const& iconSource = *iconPtr;
auto uriString = GetIconUri(iconSource);
auto icon = winrt::BitmapIcon();
winrt::Uri uri{winrt::to_hstring(uriString)};
icon.UriSource(uri);
menuItem.Icon(icon);
}
return menuItem;
}
/*static*/ winrt::Point ContextMenu::GetPointerPosition() noexcept {
auto window = winrt::CoreWindow::GetForCurrentThread();
auto pointerPosition = window.PointerPosition();
pointerPosition.X = pointerPosition.X - window.Bounds().X;
pointerPosition.Y = pointerPosition.Y - window.Bounds().Y;
return pointerPosition;
}
std::string ContextMenu::GetIconUri(
const React::JSValueObject& iconSource) noexcept {
auto uri = *iconSource["uri"].TryGetString();
auto packagerAsset = *iconSource["__packager_asset"].TryGetBoolean();
auto bundleRootPath = winrt::to_string(m_context.BundleRootPath());
if (packagerAsset && uri.find("file://") == 0) {
uri.replace(0, 7, bundleRootPath);
}
return uri;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment