diff --git a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj index f08fd189d9..ce995b255e 100644 --- a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj +++ b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj @@ -126,9 +126,12 @@ + + + diff --git a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters index 8ceff937a5..29c109ca98 100644 --- a/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters +++ b/source/uwp/Renderer/AdaptiveCardRenderer.vcxproj.filters @@ -112,6 +112,8 @@ + + @@ -231,8 +233,9 @@ + - \ No newline at end of file + diff --git a/source/uwp/Renderer/lib/ActionHelpers.cpp b/source/uwp/Renderer/lib/ActionHelpers.cpp new file mode 100644 index 0000000000..d15202ca09 --- /dev/null +++ b/source/uwp/Renderer/lib/ActionHelpers.cpp @@ -0,0 +1,1014 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include "pch.h" + +#include "ActionHelpers.h" +#include "AdaptiveImage.h" +#include "AdaptiveRenderArgs.h" +#include "AdaptiveShowCardActionRenderer.h" + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::AdaptiveNamespace; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Controls::Primitives; +using namespace ABI::Windows::UI::Xaml::Input; +using namespace ABI::Windows::UI::Xaml::Media; + +namespace AdaptiveNamespace::ActionHelpers +{ + HRESULT GetButtonMargin(_In_ IAdaptiveActionsConfig* actionsConfig, Thickness& buttonMargin) noexcept + { + buttonMargin = {0, 0, 0, 0}; + UINT32 buttonSpacing; + RETURN_IF_FAILED(actionsConfig->get_ButtonSpacing(&buttonSpacing)); + + ABI::AdaptiveNamespace::ActionsOrientation actionsOrientation; + RETURN_IF_FAILED(actionsConfig->get_ActionsOrientation(&actionsOrientation)); + + if (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal) + { + buttonMargin.Left = buttonMargin.Right = buttonSpacing / 2; + } + else + { + buttonMargin.Top = buttonMargin.Bottom = buttonSpacing / 2; + } + + return S_OK; + } + + void ArrangeButtonContent(_In_ IAdaptiveActionElement* action, + _In_ IAdaptiveActionsConfig* actionsConfig, + _In_ IAdaptiveRenderContext* renderContext, + ABI::AdaptiveNamespace::ContainerStyle containerStyle, + _In_ ABI::AdaptiveNamespace::IAdaptiveHostConfig* hostConfig, + bool allActionsHaveIcons, + _In_ IButton* button) + { + HString title; + THROW_IF_FAILED(action->get_Title(title.GetAddressOf())); + + HString iconUrl; + THROW_IF_FAILED(action->get_IconUrl(iconUrl.GetAddressOf())); + + ComPtr localButton(button); + + // Check if the button has an iconUrl + if (iconUrl != nullptr) + { + // Get icon configs + ABI::AdaptiveNamespace::IconPlacement iconPlacement; + UINT32 iconSize; + + THROW_IF_FAILED(actionsConfig->get_IconPlacement(&iconPlacement)); + THROW_IF_FAILED(actionsConfig->get_IconSize(&iconSize)); + + // Define the alignment for the button contents + ComPtr buttonContentsStackPanel = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel)); + + // Create image and add it to the button + ComPtr adaptiveImage; + THROW_IF_FAILED(MakeAndInitialize(&adaptiveImage)); + + THROW_IF_FAILED(adaptiveImage->put_Url(iconUrl.Get())); + THROW_IF_FAILED(adaptiveImage->put_HorizontalAlignment(ABI::AdaptiveNamespace::HAlignment::Center)); + + ComPtr adaptiveCardElement; + THROW_IF_FAILED(adaptiveImage.As(&adaptiveCardElement)); + ComPtr childRenderArgs; + THROW_IF_FAILED( + MakeAndInitialize(&childRenderArgs, containerStyle, buttonContentsStackPanel.Get(), nullptr)); + + ComPtr elementRenderers; + THROW_IF_FAILED(renderContext->get_ElementRenderers(&elementRenderers)); + + ComPtr buttonIcon; + ComPtr elementRenderer; + THROW_IF_FAILED(elementRenderers->Get(HStringReference(L"Image").Get(), &elementRenderer)); + if (elementRenderer != nullptr) + { + elementRenderer->Render(adaptiveCardElement.Get(), renderContext, childRenderArgs.Get(), &buttonIcon); + if (buttonIcon == nullptr) + { + XamlHelpers::SetContent(localButton.Get(), title.Get()); + return; + } + } + + // Create title text block + ComPtr buttonText = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock)); + THROW_IF_FAILED(buttonText->put_Text(title.Get())); + THROW_IF_FAILED(buttonText->put_TextAlignment(TextAlignment::TextAlignment_Center)); + + // Handle different arrangements inside button + ComPtr buttonIconAsFrameworkElement; + THROW_IF_FAILED(buttonIcon.As(&buttonIconAsFrameworkElement)); + ComPtr separator; + if (iconPlacement == ABI::AdaptiveNamespace::IconPlacement::AboveTitle && allActionsHaveIcons) + { + THROW_IF_FAILED(buttonContentsStackPanel->put_Orientation(Orientation::Orientation_Vertical)); + + // Set icon height to iconSize (aspect ratio is automatically maintained) + THROW_IF_FAILED(buttonIconAsFrameworkElement->put_Height(iconSize)); + } + else + { + THROW_IF_FAILED(buttonContentsStackPanel->put_Orientation(Orientation::Orientation_Horizontal)); + + // Add event to the image to resize itself when the textblock is rendered + ComPtr buttonIconAsImage; + THROW_IF_FAILED(buttonIcon.As(&buttonIconAsImage)); + + EventRegistrationToken eventToken; + THROW_IF_FAILED(buttonIconAsImage->add_ImageOpened( + Callback([buttonIconAsFrameworkElement, + buttonText](IInspectable* /*sender*/, IRoutedEventArgs * /*args*/) -> HRESULT { + ComPtr buttonTextAsFrameworkElement; + RETURN_IF_FAILED(buttonText.As(&buttonTextAsFrameworkElement)); + + return SetMatchingHeight(buttonIconAsFrameworkElement.Get(), buttonTextAsFrameworkElement.Get()); + }).Get(), + &eventToken)); + + // Only add spacing when the icon must be located at the left of the title + UINT spacingSize; + THROW_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig, ABI::AdaptiveNamespace::Spacing::Default, &spacingSize)); + + ABI::Windows::UI::Color color = {0}; + separator = XamlHelpers::CreateSeparator(renderContext, spacingSize, spacingSize, color, false); + } + + ComPtr buttonContentsPanel; + THROW_IF_FAILED(buttonContentsStackPanel.As(&buttonContentsPanel)); + + // Add image to stack panel + XamlHelpers::AppendXamlElementToPanel(buttonIcon.Get(), buttonContentsPanel.Get()); + + // Add separator to stack panel + if (separator != nullptr) + { + XamlHelpers::AppendXamlElementToPanel(separator.Get(), buttonContentsPanel.Get()); + } + + // Add text to stack panel + XamlHelpers::AppendXamlElementToPanel(buttonText.Get(), buttonContentsPanel.Get()); + + // Finally, put the stack panel inside the final button + ComPtr buttonContentControl; + THROW_IF_FAILED(localButton.As(&buttonContentControl)); + THROW_IF_FAILED(buttonContentControl->put_Content(buttonContentsPanel.Get())); + } + else + { + XamlHelpers::SetContent(localButton.Get(), title.Get()); + } + } + + HRESULT HandleActionStyling(_In_ IAdaptiveActionElement* adaptiveActionElement, + _In_ IFrameworkElement* buttonFrameworkElement, + _In_ IAdaptiveRenderContext* renderContext) + { + HString actionSentiment; + RETURN_IF_FAILED(adaptiveActionElement->get_Style(actionSentiment.GetAddressOf())); + + INT32 isSentimentPositive{}, isSentimentDestructive{}, isSentimentDefault{}; + + ComPtr resourceDictionary; + RETURN_IF_FAILED(renderContext->get_OverrideStyles(&resourceDictionary)); + ComPtr styleToApply; + + ComPtr contextImpl = + PeekInnards(renderContext); + + if ((SUCCEEDED(WindowsCompareStringOrdinal(actionSentiment.Get(), HStringReference(L"default").Get(), &isSentimentDefault)) && + (isSentimentDefault == 0)) || + WindowsIsStringEmpty(actionSentiment.Get())) + { + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.Action", buttonFrameworkElement)); + } + else if (SUCCEEDED(WindowsCompareStringOrdinal(actionSentiment.Get(), HStringReference(L"positive").Get(), &isSentimentPositive)) && + (isSentimentPositive == 0)) + { + if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(resourceDictionary.Get(), + L"Adaptive.Action.Positive", + &styleToApply))) + { + RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get())); + } + else + { + // By default, set the action background color to accent color + ComPtr actionSentimentDictionary = contextImpl->GetDefaultActionSentimentDictionary(); + + if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(actionSentimentDictionary.Get(), + L"PositiveActionDefaultStyle", + styleToApply.GetAddressOf()))) + { + RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get())); + } + } + } + else if (SUCCEEDED(WindowsCompareStringOrdinal(actionSentiment.Get(), HStringReference(L"destructive").Get(), &isSentimentDestructive)) && + (isSentimentDestructive == 0)) + { + if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(resourceDictionary.Get(), + L"Adaptive.Action.Destructive", + &styleToApply))) + { + RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get())); + } + else + { + // By default, set the action text color to attention color + ComPtr actionSentimentDictionary = contextImpl->GetDefaultActionSentimentDictionary(); + + if (SUCCEEDED(XamlHelpers::TryGetResourceFromResourceDictionaries(actionSentimentDictionary.Get(), + L"DestructiveActionDefaultStyle", + styleToApply.GetAddressOf()))) + { + RETURN_IF_FAILED(buttonFrameworkElement->put_Style(styleToApply.Get())); + } + } + } + else + { + HString actionSentimentStyle; + RETURN_IF_FAILED(WindowsConcatString(HStringReference(L"Adaptive.Action.").Get(), + actionSentiment.Get(), + actionSentimentStyle.GetAddressOf())); + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary( + renderContext, StringToWstring(HStringToUTF8(actionSentimentStyle.Get())), buttonFrameworkElement)); + } + return S_OK; + } + + HRESULT SetMatchingHeight(_In_ IFrameworkElement* elementToChange, _In_ IFrameworkElement* elementToMatch) + { + DOUBLE actualHeight; + RETURN_IF_FAILED(elementToMatch->get_ActualHeight(&actualHeight)); + + ComPtr localElement(elementToChange); + RETURN_IF_FAILED(localElement->put_Height(actualHeight)); + + ComPtr frameworkElementAsUIElement; + RETURN_IF_FAILED(localElement.As(&frameworkElementAsUIElement)); + RETURN_IF_FAILED(frameworkElementAsUIElement->put_Visibility(Visibility::Visibility_Visible)); + return S_OK; + } + + HRESULT BuildAction(_In_ IAdaptiveActionElement* adaptiveActionElement, + _In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveRenderArgs* renderArgs, + _Outptr_ IUIElement** actionControl) + { + // Render a button for the action + ComPtr action(adaptiveActionElement); + ComPtr button = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Button)); + + ComPtr buttonFrameworkElement; + RETURN_IF_FAILED(button.As(&buttonFrameworkElement)); + + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + ComPtr actionsConfig; + RETURN_IF_FAILED(hostConfig->get_Actions(actionsConfig.GetAddressOf())); + + Thickness buttonMargin; + RETURN_IF_FAILED(GetButtonMargin(actionsConfig.Get(), buttonMargin)); + RETURN_IF_FAILED(buttonFrameworkElement->put_Margin(buttonMargin)); + + ABI::AdaptiveNamespace::ActionsOrientation actionsOrientation; + RETURN_IF_FAILED(actionsConfig->get_ActionsOrientation(&actionsOrientation)); + + ABI::AdaptiveNamespace::ActionAlignment actionAlignment; + RETURN_IF_FAILED(actionsConfig->get_ActionAlignment(&actionAlignment)); + + if (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal) + { + // For horizontal alignment, we always use stretch + RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment( + ABI::Windows::UI::Xaml::HorizontalAlignment::HorizontalAlignment_Stretch)); + } + else + { + switch (actionAlignment) + { + case ABI::AdaptiveNamespace::ActionAlignment::Center: + RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Center)); + break; + case ABI::AdaptiveNamespace::ActionAlignment::Left: + RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Left)); + break; + case ABI::AdaptiveNamespace::ActionAlignment::Right: + RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Right)); + break; + case ABI::AdaptiveNamespace::ActionAlignment::Stretch: + RETURN_IF_FAILED(buttonFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Stretch)); + break; + } + } + + ABI::AdaptiveNamespace::ContainerStyle containerStyle; + RETURN_IF_FAILED(renderArgs->get_ContainerStyle(&containerStyle)); + + boolean allowAboveTitleIconPlacement; + RETURN_IF_FAILED(renderArgs->get_AllowAboveTitleIconPlacement(&allowAboveTitleIconPlacement)); + + ArrangeButtonContent(action.Get(), + actionsConfig.Get(), + renderContext, + containerStyle, + hostConfig.Get(), + allowAboveTitleIconPlacement, + button.Get()); + + ABI::AdaptiveNamespace::ActionType actionType; + RETURN_IF_FAILED(action->get_ActionType(&actionType)); + + ComPtr showCardActionConfig; + RETURN_IF_FAILED(actionsConfig->get_ShowCard(&showCardActionConfig)); + ABI::AdaptiveNamespace::ActionMode showCardActionMode; + RETURN_IF_FAILED(showCardActionConfig->get_ActionMode(&showCardActionMode)); + std::shared_ptr>> allShowCards = std::make_shared>>(); + + // Add click handler which calls IAdaptiveActionInvoker::SendActionEvent + ComPtr buttonBase; + RETURN_IF_FAILED(button.As(&buttonBase)); + + ComPtr actionInvoker; + RETURN_IF_FAILED(renderContext->get_ActionInvoker(&actionInvoker)); + EventRegistrationToken clickToken; + RETURN_IF_FAILED(buttonBase->add_Click(Callback([action, actionInvoker](IInspectable* /*sender*/, IRoutedEventArgs * + /*args*/) -> HRESULT { + return actionInvoker->SendActionEvent(action.Get()); + }).Get(), + &clickToken)); + + RETURN_IF_FAILED(HandleActionStyling(adaptiveActionElement, buttonFrameworkElement.Get(), renderContext)); + + ComPtr buttonAsUIElement; + RETURN_IF_FAILED(button.As(&buttonAsUIElement)); + *actionControl = buttonAsUIElement.Detach(); + return S_OK; + } + + bool WarnForInlineShowCard(_In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveActionElement* action, const std::wstring& warning) + { + if (action != nullptr) + { + ABI::AdaptiveNamespace::ActionType actionType; + THROW_IF_FAILED(action->get_ActionType(&actionType)); + + if (actionType == ABI::AdaptiveNamespace::ActionType::ShowCard) + { + THROW_IF_FAILED(renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::UnsupportedValue, + HStringReference(warning.c_str()).Get())); + return true; + } + } + + return false; + } + + static HRESULT HandleKeydownForInlineAction(_In_ IKeyRoutedEventArgs* args, + _In_ IAdaptiveActionInvoker* actionInvoker, + _In_ IAdaptiveActionElement* inlineAction) + { + ABI::Windows::System::VirtualKey key; + RETURN_IF_FAILED(args->get_Key(&key)); + + if (key == ABI::Windows::System::VirtualKey::VirtualKey_Enter) + { + ComPtr coreWindowStatics; + RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Core_CoreWindow).Get(), &coreWindowStatics)); + + ComPtr coreWindow; + RETURN_IF_FAILED(coreWindowStatics->GetForCurrentThread(&coreWindow)); + + ABI::Windows::UI::Core::CoreVirtualKeyStates shiftKeyState; + RETURN_IF_FAILED(coreWindow->GetKeyState(ABI::Windows::System::VirtualKey_Shift, &shiftKeyState)); + + ABI::Windows::UI::Core::CoreVirtualKeyStates ctrlKeyState; + RETURN_IF_FAILED(coreWindow->GetKeyState(ABI::Windows::System::VirtualKey_Control, &ctrlKeyState)); + + if (shiftKeyState == ABI::Windows::UI::Core::CoreVirtualKeyStates_None && + ctrlKeyState == ABI::Windows::UI::Core::CoreVirtualKeyStates_None) + { + RETURN_IF_FAILED(actionInvoker->SendActionEvent(inlineAction)); + RETURN_IF_FAILED(args->put_Handled(true)); + } + } + + return S_OK; + } + + void HandleInlineAction(_In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveRenderArgs* renderArgs, + _In_ ITextBox* textBox, + _In_ IAdaptiveActionElement* inlineAction, + _COM_Outptr_ IUIElement** textBoxWithInlineAction) + { + ComPtr localTextBox(textBox); + ComPtr localInlineAction(inlineAction); + + ABI::AdaptiveNamespace::ActionType actionType; + THROW_IF_FAILED(localInlineAction->get_ActionType(&actionType)); + + ComPtr hostConfig; + THROW_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + // Inline ShowCards are not supported for inline actions + if (WarnForInlineShowCard(renderContext, localInlineAction.Get(), L"Inline ShowCard not supported for InlineAction")) + { + THROW_IF_FAILED(localTextBox.CopyTo(textBoxWithInlineAction)); + return; + } + + // Create a grid to hold the text box and the action button + ComPtr gridStatics; + THROW_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid).Get(), &gridStatics)); + + ComPtr xamlGrid = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + ComPtr> columnDefinitions; + THROW_IF_FAILED(xamlGrid->get_ColumnDefinitions(&columnDefinitions)); + ComPtr gridAsPanel; + THROW_IF_FAILED(xamlGrid.As(&gridAsPanel)); + + // Create the first column and add the text box to it + ComPtr textBoxColumnDefinition = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + THROW_IF_FAILED(textBoxColumnDefinition->put_Width({1, GridUnitType::GridUnitType_Star})); + THROW_IF_FAILED(columnDefinitions->Append(textBoxColumnDefinition.Get())); + + ComPtr textBoxAsFrameworkElement; + THROW_IF_FAILED(localTextBox.As(&textBoxAsFrameworkElement)); + + THROW_IF_FAILED(gridStatics->SetColumn(textBoxAsFrameworkElement.Get(), 0)); + XamlHelpers::AppendXamlElementToPanel(textBox, gridAsPanel.Get()); + + // Create a separator column + ComPtr separatorColumnDefinition = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + THROW_IF_FAILED(separatorColumnDefinition->put_Width({1.0, GridUnitType::GridUnitType_Auto})); + THROW_IF_FAILED(columnDefinitions->Append(separatorColumnDefinition.Get())); + + UINT spacingSize; + THROW_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig.Get(), ABI::AdaptiveNamespace::Spacing::Default, &spacingSize)); + + auto separator = XamlHelpers::CreateSeparator(renderContext, spacingSize, 0, {0}, false); + + ComPtr separatorAsFrameworkElement; + THROW_IF_FAILED(separator.As(&separatorAsFrameworkElement)); + + THROW_IF_FAILED(gridStatics->SetColumn(separatorAsFrameworkElement.Get(), 1)); + XamlHelpers::AppendXamlElementToPanel(separator.Get(), gridAsPanel.Get()); + + // Create a column for the button + ComPtr inlineActionColumnDefinition = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + THROW_IF_FAILED(inlineActionColumnDefinition->put_Width({0, GridUnitType::GridUnitType_Auto})); + THROW_IF_FAILED(columnDefinitions->Append(inlineActionColumnDefinition.Get())); + + // Create a text box with the action title. This will be the tool tip if there's an icon + // or the content of the button otherwise + ComPtr titleTextBlock = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock)); + HString title; + THROW_IF_FAILED(localInlineAction->get_Title(title.GetAddressOf())); + THROW_IF_FAILED(titleTextBlock->put_Text(title.Get())); + + HString iconUrl; + THROW_IF_FAILED(localInlineAction->get_IconUrl(iconUrl.GetAddressOf())); + ComPtr actionUIElement; + if (iconUrl != nullptr) + { + // Render the icon using the adaptive image renderer + ComPtr elementRenderers; + THROW_IF_FAILED(renderContext->get_ElementRenderers(&elementRenderers)); + ComPtr imageRenderer; + THROW_IF_FAILED(elementRenderers->Get(HStringReference(L"Image").Get(), &imageRenderer)); + + ComPtr adaptiveImage; + THROW_IF_FAILED(MakeAndInitialize(&adaptiveImage)); + + THROW_IF_FAILED(adaptiveImage->put_Url(iconUrl.Get())); + + ComPtr adaptiveImageAsElement; + THROW_IF_FAILED(adaptiveImage.As(&adaptiveImageAsElement)); + + THROW_IF_FAILED(imageRenderer->Render(adaptiveImageAsElement.Get(), renderContext, renderArgs, &actionUIElement)); + + // Add the tool tip + ComPtr toolTip = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ToolTip)); + ComPtr toolTipAsContentControl; + THROW_IF_FAILED(toolTip.As(&toolTipAsContentControl)); + THROW_IF_FAILED(toolTipAsContentControl->put_Content(titleTextBlock.Get())); + + ComPtr toolTipService; + THROW_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ToolTipService).Get(), + &toolTipService)); + + ComPtr actionAsDependencyObject; + THROW_IF_FAILED(actionUIElement.As(&actionAsDependencyObject)); + + THROW_IF_FAILED(toolTipService->SetToolTip(actionAsDependencyObject.Get(), toolTip.Get())); + } + else + { + // If there's no icon, just use the title text. Put it centered in a grid so it is + // centered relative to the text box. + ComPtr textBlockAsFrameworkElement; + THROW_IF_FAILED(titleTextBlock.As(&textBlockAsFrameworkElement)); + THROW_IF_FAILED(textBlockAsFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Center)); + + ComPtr titleGrid = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + ComPtr panel; + THROW_IF_FAILED(titleGrid.As(&panel)); + XamlHelpers::AppendXamlElementToPanel(titleTextBlock.Get(), panel.Get()); + + THROW_IF_FAILED(panel.As(&actionUIElement)); + } + + // Make the action the same size as the text box + EventRegistrationToken eventToken; + THROW_IF_FAILED(textBoxAsFrameworkElement->add_Loaded( + Callback([actionUIElement, textBoxAsFrameworkElement](IInspectable* /*sender*/, IRoutedEventArgs * + /*args*/) -> HRESULT { + ComPtr actionFrameworkElement; + RETURN_IF_FAILED(actionUIElement.As(&actionFrameworkElement)); + + return ActionHelpers::SetMatchingHeight(actionFrameworkElement.Get(), textBoxAsFrameworkElement.Get()); + }).Get(), + &eventToken)); + + // Wrap the action in a button + ComPtr touchTargetUIElement; + WrapInTouchTarget(nullptr, actionUIElement.Get(), localInlineAction.Get(), renderContext, false, L"Adaptive.Input.Text.InlineAction", &touchTargetUIElement); + + ComPtr touchTargetFrameworkElement; + THROW_IF_FAILED(touchTargetUIElement.As(&touchTargetFrameworkElement)); + + // Align to bottom so the icon stays with the bottom of the text box as it grows in the multiline case + THROW_IF_FAILED(touchTargetFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Bottom)); + + // Add the action to the column + THROW_IF_FAILED(gridStatics->SetColumn(touchTargetFrameworkElement.Get(), 2)); + XamlHelpers::AppendXamlElementToPanel(touchTargetFrameworkElement.Get(), gridAsPanel.Get()); + + // If this isn't a multiline input, enter should invoke the action + ComPtr actionInvoker; + THROW_IF_FAILED(renderContext->get_ActionInvoker(&actionInvoker)); + + boolean isMultiLine; + THROW_IF_FAILED(textBox->get_AcceptsReturn(&isMultiLine)); + + if (!isMultiLine) + { + ComPtr textBoxAsUIElement; + THROW_IF_FAILED(localTextBox.As(&textBoxAsUIElement)); + + EventRegistrationToken keyDownEventToken; + THROW_IF_FAILED(textBoxAsUIElement->add_KeyDown( + Callback([actionInvoker, localInlineAction](IInspectable* /*sender*/, IKeyRoutedEventArgs* args) -> HRESULT { + return HandleKeydownForInlineAction(args, actionInvoker.Get(), localInlineAction.Get()); + }).Get(), + &keyDownEventToken)); + } + + THROW_IF_FAILED(xamlGrid.CopyTo(textBoxWithInlineAction)); + } + + void WrapInTouchTarget(_In_ IAdaptiveCardElement* adaptiveCardElement, + _In_ IUIElement* elementToWrap, + _In_ IAdaptiveActionElement* action, + _In_ IAdaptiveRenderContext* renderContext, + bool fullWidth, + const std::wstring& style, + _COM_Outptr_ IUIElement** finalElement) + { + ComPtr hostConfig; + THROW_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + if (ActionHelpers::WarnForInlineShowCard(renderContext, action, L"Inline ShowCard not supported for SelectAction")) + { + // Was inline show card, so don't wrap the element and just return + ComPtr localElementToWrap(elementToWrap); + localElementToWrap.CopyTo(finalElement); + return; + } + + ComPtr button = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Button)); + + ComPtr buttonAsContentControl; + THROW_IF_FAILED(button.As(&buttonAsContentControl)); + THROW_IF_FAILED(buttonAsContentControl->put_Content(elementToWrap)); + + ComPtr spacingConfig; + THROW_IF_FAILED(hostConfig->get_Spacing(&spacingConfig)); + + UINT32 cardPadding = 0; + if (fullWidth) + { + THROW_IF_FAILED(spacingConfig->get_Padding(&cardPadding)); + } + + ComPtr buttonAsFrameworkElement; + THROW_IF_FAILED(button.As(&buttonAsFrameworkElement)); + + // We want the hit target to equally split the vertical space above and below the current item. + // However, all we know is the spacing of the current item, which only applies to the spacing above. + // We don't know what the spacing of the NEXT element will be, so we can't calculate the correct spacing + // below. For now, we'll simply assume the bottom spacing is the same as the top. NOTE: Only apply spacings + // (padding, margin) for adaptive card elements to avoid adding spacings to card-level selectAction. + if (adaptiveCardElement != nullptr) + { + ABI::AdaptiveNamespace::Spacing elementSpacing; + THROW_IF_FAILED(adaptiveCardElement->get_Spacing(&elementSpacing)); + UINT spacingSize; + THROW_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig.Get(), elementSpacing, &spacingSize)); + double topBottomPadding = spacingSize / 2.0; + + // For button padding, we apply the cardPadding and topBottomPadding (and then we negate these in the margin) + ComPtr buttonAsControl; + THROW_IF_FAILED(button.As(&buttonAsControl)); + THROW_IF_FAILED(buttonAsControl->put_Padding({(double)cardPadding, topBottomPadding, (double)cardPadding, topBottomPadding})); + + double negativeCardMargin = cardPadding * -1.0; + double negativeTopBottomMargin = topBottomPadding * -1.0; + + THROW_IF_FAILED(buttonAsFrameworkElement->put_Margin( + {negativeCardMargin, negativeTopBottomMargin, negativeCardMargin, negativeTopBottomMargin})); + } + + // Style the hit target button + THROW_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, style.c_str(), buttonAsFrameworkElement.Get())); + + if (action != nullptr) + { + // If we have an action, use the title for the AutomationProperties.Name + HString title; + THROW_IF_FAILED(action->get_Title(title.GetAddressOf())); + + ComPtr buttonAsDependencyObject; + THROW_IF_FAILED(button.As(&buttonAsDependencyObject)); + + ComPtr automationPropertiesStatics; + THROW_IF_FAILED( + GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Automation_AutomationProperties).Get(), + &automationPropertiesStatics)); + + THROW_IF_FAILED(automationPropertiesStatics->SetName(buttonAsDependencyObject.Get(), title.Get())); + + WireButtonClickToAction(button.Get(), action, renderContext); + } + + THROW_IF_FAILED(button.CopyTo(finalElement)); + } + + void WireButtonClickToAction(_In_ IButton* button, _In_ IAdaptiveActionElement* action, _In_ IAdaptiveRenderContext* renderContext) + { + // Note that this method currently doesn't support inline show card actions, it + // assumes the caller won't call this method if inline show card is specified. + ComPtr localButton(button); + ComPtr actionInvoker; + THROW_IF_FAILED(renderContext->get_ActionInvoker(&actionInvoker)); + ComPtr strongAction(action); + + // Add click handler + ComPtr buttonBase; + THROW_IF_FAILED(localButton.As(&buttonBase)); + + EventRegistrationToken clickToken; + THROW_IF_FAILED(buttonBase->add_Click(Callback([strongAction, actionInvoker](IInspectable* /*sender*/, IRoutedEventArgs * + /*args*/) -> HRESULT { + THROW_IF_FAILED(actionInvoker->SendActionEvent(strongAction.Get())); + return S_OK; + }).Get(), + &clickToken)); + } + + void HandleSelectAction(_In_ IAdaptiveCardElement* adaptiveCardElement, + _In_ IAdaptiveActionElement* selectAction, + _In_ IAdaptiveRenderContext* renderContext, + _In_ IUIElement* uiElement, + bool supportsInteractivity, + bool fullWidthTouchTarget, + _COM_Outptr_ IUIElement** outUiElement) + { + if (selectAction != nullptr && supportsInteractivity) + { + WrapInTouchTarget(adaptiveCardElement, uiElement, selectAction, renderContext, fullWidthTouchTarget, L"Adaptive.SelectAction", outUiElement); + } + else + { + if (selectAction != nullptr) + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"SelectAction present, but Interactivity is not supported").Get()); + } + + ComPtr localUiElement(uiElement); + THROW_IF_FAILED(localUiElement.CopyTo(outUiElement)); + } + } + + HRESULT BuildActions(_In_ IAdaptiveCard* adaptiveCard, + _In_ IVector* children, + _In_ IPanel* bodyPanel, + bool insertSeparator, + _In_ IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs) + { + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + ComPtr actionsConfig; + RETURN_IF_FAILED(hostConfig->get_Actions(actionsConfig.GetAddressOf())); + + // Create a separator between the body and the actions + if (insertSeparator) + { + ABI::AdaptiveNamespace::Spacing spacing; + RETURN_IF_FAILED(actionsConfig->get_Spacing(&spacing)); + + UINT spacingSize; + RETURN_IF_FAILED(GetSpacingSizeFromSpacing(hostConfig.Get(), spacing, &spacingSize)); + + ABI::Windows::UI::Color color = {0}; + auto separator = XamlHelpers::CreateSeparator(renderContext, spacingSize, 0, color); + XamlHelpers::AppendXamlElementToPanel(separator.Get(), bodyPanel); + } + + ComPtr actionSetControl; + RETURN_IF_FAILED(BuildActionSetHelper(adaptiveCard, nullptr, children, renderContext, renderArgs, &actionSetControl)); + + XamlHelpers::AppendXamlElementToPanel(actionSetControl.Get(), bodyPanel); + return S_OK; + } + + HRESULT BuildActionSetHelper(_In_opt_ ABI::AdaptiveNamespace::IAdaptiveCard* adaptiveCard, + _In_opt_ IAdaptiveActionSet* adaptiveActionSet, + _In_ IVector* children, + _In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveRenderArgs* renderArgs, + _Outptr_ IUIElement** actionSetControl) + { + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + ComPtr actionsConfig; + RETURN_IF_FAILED(hostConfig->get_Actions(actionsConfig.GetAddressOf())); + + ABI::AdaptiveNamespace::ActionAlignment actionAlignment; + RETURN_IF_FAILED(actionsConfig->get_ActionAlignment(&actionAlignment)); + + ABI::AdaptiveNamespace::ActionsOrientation actionsOrientation; + RETURN_IF_FAILED(actionsConfig->get_ActionsOrientation(&actionsOrientation)); + + // Declare the panel that will host the buttons + ComPtr actionsPanel; + ComPtr> columnDefinitions; + + if (actionAlignment == ABI::AdaptiveNamespace::ActionAlignment::Stretch && + actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal) + { + // If stretch alignment and orientation is horizontal, we use a grid with equal column widths to achieve + // stretch behavior. For vertical orientation, we'll still just use a stack panel since the concept of + // stretching buttons height isn't really valid, especially when the height of cards are typically dynamic. + ComPtr actionsGrid = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + RETURN_IF_FAILED(actionsGrid->get_ColumnDefinitions(&columnDefinitions)); + RETURN_IF_FAILED(actionsGrid.As(&actionsPanel)); + } + else + { + // Create a stack panel for the action buttons + ComPtr actionStackPanel = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel)); + + auto uiOrientation = (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal) ? + Orientation::Orientation_Horizontal : + Orientation::Orientation_Vertical; + + RETURN_IF_FAILED(actionStackPanel->put_Orientation(uiOrientation)); + + ComPtr actionsFrameworkElement; + RETURN_IF_FAILED(actionStackPanel.As(&actionsFrameworkElement)); + + switch (actionAlignment) + { + case ABI::AdaptiveNamespace::ActionAlignment::Center: + RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Center)); + break; + case ABI::AdaptiveNamespace::ActionAlignment::Left: + RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Left)); + break; + case ABI::AdaptiveNamespace::ActionAlignment::Right: + RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Right)); + break; + case ABI::AdaptiveNamespace::ActionAlignment::Stretch: + RETURN_IF_FAILED(actionsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Stretch)); + break; + } + + // Add the action buttons to the stack panel + RETURN_IF_FAILED(actionStackPanel.As(&actionsPanel)); + } + + Thickness buttonMargin; + RETURN_IF_FAILED(ActionHelpers::GetButtonMargin(actionsConfig.Get(), buttonMargin)); + if (actionsOrientation == ABI::AdaptiveNamespace::ActionsOrientation::Horizontal) + { + // Negate the spacing on the sides so the left and right buttons are flush on the side. + // We do NOT remove the margin from the individual button itself, since that would cause + // the equal columns stretch behavior to not have equal columns (since the first and last + // button would be narrower without the same margins as its peers). + ComPtr actionsPanelAsFrameworkElement; + RETURN_IF_FAILED(actionsPanel.As(&actionsPanelAsFrameworkElement)); + RETURN_IF_FAILED(actionsPanelAsFrameworkElement->put_Margin({buttonMargin.Left * -1, 0, buttonMargin.Right * -1, 0})); + } + else + { + // Negate the spacing on the top and bottom so the first and last buttons don't have extra padding + ComPtr actionsPanelAsFrameworkElement; + RETURN_IF_FAILED(actionsPanel.As(&actionsPanelAsFrameworkElement)); + RETURN_IF_FAILED(actionsPanelAsFrameworkElement->put_Margin({0, buttonMargin.Top * -1, 0, buttonMargin.Bottom * -1})); + } + + UINT32 maxActions; + RETURN_IF_FAILED(actionsConfig->get_MaxActions(&maxActions)); + + bool allActionsHaveIcons{true}; + XamlHelpers::IterateOverVector(children, [&](IAdaptiveActionElement* child) { + HString iconUrl; + RETURN_IF_FAILED(child->get_IconUrl(iconUrl.GetAddressOf())); + + if (WindowsIsStringEmpty(iconUrl.Get())) + { + allActionsHaveIcons = false; + } + return S_OK; + }); + + UINT currentAction = 0; + + RETURN_IF_FAILED(renderArgs->put_AllowAboveTitleIconPlacement(allActionsHaveIcons)); + + std::shared_ptr>> allShowCards = std::make_shared>>(); + ComPtr showCardsStackPanel = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel)); + ComPtr gridStatics; + RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid).Get(), &gridStatics)); + XamlHelpers::IterateOverVector(children, [&](IAdaptiveActionElement* child) { + if (currentAction < maxActions) + { + // Render each action using the registered renderer + ComPtr action(child); + ComPtr actionRegistration; + RETURN_IF_FAILED(renderContext->get_ActionRenderers(&actionRegistration)); + + ComPtr renderer; + while (!renderer) + { + HString actionTypeString; + RETURN_IF_FAILED(action->get_ActionTypeString(actionTypeString.GetAddressOf())); + RETURN_IF_FAILED(actionRegistration->Get(actionTypeString.Get(), &renderer)); + if (!renderer) + { + ABI::AdaptiveNamespace::FallbackType actionFallbackType; + action->get_FallbackType(&actionFallbackType); + switch (actionFallbackType) + { + case ABI::AdaptiveNamespace::FallbackType::Drop: + { + RETURN_IF_FAILED(XamlHelpers::WarnForFallbackDrop(renderContext, actionTypeString.Get())); + return S_OK; + } + + case ABI::AdaptiveNamespace::FallbackType::Content: + { + ComPtr actionFallback; + RETURN_IF_FAILED(action->get_FallbackContent(&actionFallback)); + + HString fallbackTypeString; + RETURN_IF_FAILED(actionFallback->get_ActionTypeString(fallbackTypeString.GetAddressOf())); + RETURN_IF_FAILED(XamlHelpers::WarnForFallbackContentElement(renderContext, + actionTypeString.Get(), + fallbackTypeString.Get())); + + action = actionFallback; + break; + } + + case ABI::AdaptiveNamespace::FallbackType::None: + default: + return E_FAIL; + } + } + } + + ComPtr actionControl; + RETURN_IF_FAILED(renderer->Render(action.Get(), renderContext, renderArgs, &actionControl)); + + XamlHelpers::AppendXamlElementToPanel(actionControl.Get(), actionsPanel.Get()); + + ABI::AdaptiveNamespace::ActionType actionType; + RETURN_IF_FAILED(action->get_ActionType(&actionType)); + + // Build inline show cards if needed + if (actionType == ABI::AdaptiveNamespace::ActionType_ShowCard) + { + ComPtr uiShowCard; + + ComPtr showCardActionConfig; + RETURN_IF_FAILED(actionsConfig->get_ShowCard(&showCardActionConfig)); + + ABI::AdaptiveNamespace::ActionMode showCardActionMode; + RETURN_IF_FAILED(showCardActionConfig->get_ActionMode(&showCardActionMode)); + + if (showCardActionMode == ABI::AdaptiveNamespace::ActionMode::Inline) + { + ComPtr showCardAction; + RETURN_IF_FAILED(action.As(&showCardAction)); + + ComPtr showCard; + RETURN_IF_FAILED(showCardAction->get_Card(&showCard)); + + RETURN_IF_FAILED(AdaptiveShowCardActionRenderer::BuildShowCard( + showCard.Get(), renderContext, renderArgs, (adaptiveActionSet == nullptr), uiShowCard.GetAddressOf())); + + ComPtr showCardsPanel; + RETURN_IF_FAILED(showCardsStackPanel.As(&showCardsPanel)); + XamlHelpers::AppendXamlElementToPanel(uiShowCard.Get(), showCardsPanel.Get()); + + if (adaptiveActionSet) + { + RETURN_IF_FAILED( + renderContext->AddInlineShowCard(adaptiveActionSet, showCardAction.Get(), uiShowCard.Get())); + } + else + { + ComPtr contextImpl = + PeekInnards(renderContext); + + RETURN_IF_FAILED( + contextImpl->AddInlineShowCard(adaptiveCard, showCardAction.Get(), uiShowCard.Get())); + } + } + } + + if (columnDefinitions != nullptr) + { + // If using the equal width columns, we'll add a column and assign the column + ComPtr columnDefinition = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + RETURN_IF_FAILED(columnDefinition->put_Width({1.0, GridUnitType::GridUnitType_Star})); + RETURN_IF_FAILED(columnDefinitions->Append(columnDefinition.Get())); + + ComPtr actionFrameworkElement; + THROW_IF_FAILED(actionControl.As(&actionFrameworkElement)); + THROW_IF_FAILED(gridStatics->SetColumn(actionFrameworkElement.Get(), currentAction)); + } + } + else + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::MaxActionsExceeded, + HStringReference(L"Some actions were not rendered due to exceeding the maximum number of actions allowed") + .Get()); + } + currentAction++; + return S_OK; + }); + + // Reset icon placement value + RETURN_IF_FAILED(renderArgs->put_AllowAboveTitleIconPlacement(false)); + + ComPtr actionsPanelAsFrameworkElement; + RETURN_IF_FAILED(actionsPanel.As(&actionsPanelAsFrameworkElement)); + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Actions", + actionsPanelAsFrameworkElement.Get())); + + ComPtr actionSet = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel)); + ComPtr actionSetAsPanel; + actionSet.As(&actionSetAsPanel); + + // Add buttons and show cards to panel + XamlHelpers::AppendXamlElementToPanel(actionsPanel.Get(), actionSetAsPanel.Get()); + XamlHelpers::AppendXamlElementToPanel(showCardsStackPanel.Get(), actionSetAsPanel.Get()); + + return actionSetAsPanel.CopyTo(actionSetControl); + } +} diff --git a/source/uwp/Renderer/lib/ActionHelpers.h b/source/uwp/Renderer/lib/ActionHelpers.h new file mode 100644 index 0000000000..ae87299f48 --- /dev/null +++ b/source/uwp/Renderer/lib/ActionHelpers.h @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#pragma once + +namespace AdaptiveNamespace::ActionHelpers +{ + HRESULT BuildAction(_In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* adaptiveActionElement, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs, + _Outptr_ ABI::Windows::UI::Xaml::IUIElement** actionControl); + + HRESULT GetButtonMargin(_In_ ABI::AdaptiveNamespace::IAdaptiveActionsConfig* actionsConfig, + ABI::Windows::UI::Xaml::Thickness& buttonMargin) noexcept; + + void ArrangeButtonContent(_In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action, + _In_ ABI::AdaptiveNamespace::IAdaptiveActionsConfig* actionsConfig, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + ABI::AdaptiveNamespace::ContainerStyle containerStyle, + _In_ ABI::AdaptiveNamespace::IAdaptiveHostConfig* hostConfig, + bool allActionsHaveIcons, + _In_ ABI::Windows::UI::Xaml::Controls::IButton* button); + + HRESULT SetMatchingHeight(_In_ ABI::Windows::UI::Xaml::IFrameworkElement* elementToChange, + _In_ ABI::Windows::UI::Xaml::IFrameworkElement* elementToMatch); + + HRESULT HandleActionStyling(_In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* adaptiveActionElement, + _In_ ABI::Windows::UI::Xaml::IFrameworkElement* buttonFrameworkElement, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext); + + bool WarnForInlineShowCard(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action, + const std::wstring& warning); + + void HandleInlineAction(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs, + _In_ ABI::Windows::UI::Xaml::Controls::ITextBox* textBox, + _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* inlineAction, + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** textBoxWithInlineAction); + + void WireButtonClickToAction(_In_ ABI::Windows::UI::Xaml::Controls::IButton* button, + _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext); + + void WrapInTouchTarget(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement* adaptiveCardElement, + _In_ ABI::Windows::UI::Xaml::IUIElement* elementToWrap, + _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* action, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + bool fullWidth, + const std::wstring& style, + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** finalElement); + + void HandleSelectAction(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement* adaptiveCardElement, + _In_ ABI::AdaptiveNamespace::IAdaptiveActionElement* selectAction, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::Windows::UI::Xaml::IUIElement* uiElement, + bool supportsInteractivity, + bool fullWidthTouchTarget, + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** outUiElement); + + HRESULT BuildActions(_In_ ABI::AdaptiveNamespace::IAdaptiveCard* adaptiveCard, + _In_ ABI::Windows::Foundation::Collections::IVector* children, + _In_ ABI::Windows::UI::Xaml::Controls::IPanel* bodyPanel, + bool insertSeparator, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs); + + HRESULT BuildActionSetHelper(_In_opt_ ABI::AdaptiveNamespace::IAdaptiveCard* adaptiveCard, + _In_opt_ ABI::AdaptiveNamespace::IAdaptiveActionSet* adaptiveActionSet, + _In_ ABI::Windows::Foundation::Collections::IVector* children, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs, + _Outptr_ ABI::Windows::UI::Xaml::IUIElement** actionSetControl); +} diff --git a/source/uwp/Renderer/lib/AdaptiveActionElement.cpp b/source/uwp/Renderer/lib/AdaptiveActionElement.cpp index 311ad7801c..fc41757084 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionElement.cpp +++ b/source/uwp/Renderer/lib/AdaptiveActionElement.cpp @@ -2,7 +2,6 @@ // Licensed under the MIT License. #include "pch.h" #include "AdaptiveActionElement.h" -#include "Util.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -79,15 +78,9 @@ namespace AdaptiveNamespace HRESULT AdaptiveActionElementBase::put_IconUrl(_In_ HSTRING iconUrl) { return m_iconUrl.Set(iconUrl); } - IFACEMETHODIMP AdaptiveActionElementBase::get_Style(_Outptr_ HSTRING* style) - { - return m_style.CopyTo(style); - } + IFACEMETHODIMP AdaptiveActionElementBase::get_Style(_Outptr_ HSTRING* style) { return m_style.CopyTo(style); } - IFACEMETHODIMP AdaptiveActionElementBase::put_Style(_In_ HSTRING style) - { - return m_style.Set(style); - } + IFACEMETHODIMP AdaptiveActionElementBase::put_Style(_In_ HSTRING style) { return m_style.Set(style); } IFACEMETHODIMP AdaptiveActionElementBase::get_AdditionalProperties(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result) { diff --git a/source/uwp/Renderer/lib/AdaptiveActionElement.h b/source/uwp/Renderer/lib/AdaptiveActionElement.h index a488e72628..2dcbf08e0c 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionElement.h +++ b/source/uwp/Renderer/lib/AdaptiveActionElement.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include -#include "Enums.h" - namespace AdaptiveNamespace { class DECLSPEC_UUID("CDCCC115-7C53-4A04-9F5B-754BBC00C80E") AdaptiveActionElementBase : public IUnknown diff --git a/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp b/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp index c98d39c2fc..53589cd586 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp +++ b/source/uwp/Renderer/lib/AdaptiveActionInvoker.cpp @@ -15,7 +15,8 @@ namespace AdaptiveNamespace { HRESULT AdaptiveActionInvoker::RuntimeClassInitialize() noexcept { return S_OK; } - HRESULT AdaptiveActionInvoker::RuntimeClassInitialize(_In_ RenderedAdaptiveCard* renderResult) noexcept try + HRESULT AdaptiveActionInvoker::RuntimeClassInitialize(_In_ RenderedAdaptiveCard* renderResult) noexcept + try { ComPtr strongRenderResult = renderResult; return strongRenderResult.AsWeak(&m_weakRenderResult); diff --git a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp index 8b17c39448..20dad1186d 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp +++ b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.cpp @@ -20,7 +20,8 @@ namespace AdaptiveNamespace { AdaptiveActionParserRegistration::AdaptiveActionParserRegistration() {} - HRESULT AdaptiveActionParserRegistration::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveActionParserRegistration::RuntimeClassInitialize() noexcept + try { m_registration = std::make_shared(); m_sharedParserRegistration = std::make_shared(); @@ -38,7 +39,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveActionParserRegistration::Set(_In_ HSTRING type, _In_ IAdaptiveActionParser* Parser) noexcept try + HRESULT AdaptiveActionParserRegistration::Set(_In_ HSTRING type, _In_ IAdaptiveActionParser* Parser) noexcept + try { std::string typeString = HStringToUTF8(type); @@ -56,7 +58,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveActionParserRegistration::Get(_In_ HSTRING type, _COM_Outptr_ IAdaptiveActionParser** result) noexcept try + HRESULT AdaptiveActionParserRegistration::Get(_In_ HSTRING type, _COM_Outptr_ IAdaptiveActionParser** result) noexcept + try { *result = nullptr; @@ -69,7 +72,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveActionParserRegistration::Remove(_In_ HSTRING type) noexcept try + HRESULT AdaptiveActionParserRegistration::Remove(_In_ HSTRING type) noexcept + try { std::string typeString = HStringToUTF8(type); diff --git a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h index d2d5f34865..0a7527bce4 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h +++ b/source/uwp/Renderer/lib/AdaptiveActionParserRegistration.h @@ -3,7 +3,7 @@ #pragma once #include "AdaptiveCards.Rendering.Uwp.h" - + namespace AdaptiveNamespace { constexpr char* c_upwActionParserRegistration = "AB3CC8B0-FF27-4859-A2AA-BCE2E729805"; diff --git a/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp b/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp index e60a991411..daae972226 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp +++ b/source/uwp/Renderer/lib/AdaptiveActionRendererRegistration.cpp @@ -12,7 +12,8 @@ namespace AdaptiveNamespace { AdaptiveActionRendererRegistration::AdaptiveActionRendererRegistration() {} - HRESULT AdaptiveActionRendererRegistration::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveActionRendererRegistration::RuntimeClassInitialize() noexcept + try { m_registration = std::make_shared(); return S_OK; diff --git a/source/uwp/Renderer/lib/AdaptiveActionSet.cpp b/source/uwp/Renderer/lib/AdaptiveActionSet.cpp index 291c330f97..d2d0241c60 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionSet.cpp +++ b/source/uwp/Renderer/lib/AdaptiveActionSet.cpp @@ -3,10 +3,6 @@ #include "pch.h" #include "AdaptiveActionSet.h" -#include "Util.h" -#include "Vector.h" -#include - using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; @@ -14,21 +10,20 @@ using namespace ABI::Windows::Foundation::Collections; using namespace ABI::Windows::UI::Xaml; using namespace ABI::Windows::UI::Xaml::Controls; -namespace AdaptiveCards { namespace Rendering { namespace Uwp +namespace AdaptiveNamespace { - AdaptiveActionSet::AdaptiveActionSet() - { - m_actions = Microsoft::WRL::Make>(); - } + AdaptiveActionSet::AdaptiveActionSet() { m_actions = Microsoft::WRL::Make>(); } - HRESULT AdaptiveActionSet::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveActionSet::RuntimeClassInitialize() noexcept + try { std::shared_ptr ActionSet = std::make_shared(); return RuntimeClassInitialize(ActionSet); - } CATCH_RETURN; + } + CATCH_RETURN; - _Use_decl_annotations_ - HRESULT AdaptiveActionSet::RuntimeClassInitialize(const std::shared_ptr& sharedActionSet) try + HRESULT AdaptiveActionSet::RuntimeClassInitialize(const std::shared_ptr& sharedActionSet) + try { if (sharedActionSet == nullptr) { @@ -38,22 +33,22 @@ namespace AdaptiveCards { namespace Rendering { namespace Uwp RETURN_IF_FAILED(GenerateActionsProjection(sharedActionSet->GetActions(), m_actions.Get())); InitializeBaseElement(std::static_pointer_cast(sharedActionSet)); return S_OK; - } CATCH_RETURN; + } + CATCH_RETURN; - _Use_decl_annotations_ - HRESULT AdaptiveActionSet::get_Actions(IVector** items) + HRESULT AdaptiveActionSet::get_Actions(_COM_Outptr_ IVector** items) { return m_actions.CopyTo(items); } - _Use_decl_annotations_ - HRESULT AdaptiveActionSet::get_ElementType(ElementType* elementType) + HRESULT AdaptiveActionSet::get_ElementType(_Out_ ElementType* elementType) { *elementType = ElementType::ActionSet; return S_OK; } - HRESULT AdaptiveActionSet::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveActionSet::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr actionSet = std::make_shared(); RETURN_IF_FAILED(SetSharedElementProperties(std::static_pointer_cast(actionSet))); @@ -62,5 +57,6 @@ namespace AdaptiveCards { namespace Rendering { namespace Uwp sharedModel = actionSet; return S_OK; - }CATCH_RETURN; -}}} + } + CATCH_RETURN; +} diff --git a/source/uwp/Renderer/lib/AdaptiveActionSet.h b/source/uwp/Renderer/lib/AdaptiveActionSet.h index c56d53d3fe..c130987536 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionSet.h +++ b/source/uwp/Renderer/lib/AdaptiveActionSet.h @@ -2,11 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ActionSet.h" -#include -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { @@ -17,11 +13,12 @@ namespace AdaptiveNamespace Microsoft::WRL::CloakedIid, Microsoft::WRL::CloakedIid> { - InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSet, BaseTrust) + InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSet, BaseTrust); - public : AdaptiveActionSet(); + public: + AdaptiveActionSet(); HRESULT RuntimeClassInitialize() noexcept; - HRESULT RuntimeClassInitialize(_In_ const std::shared_ptr& sharedActionSet); + HRESULT RuntimeClassInitialize(const std::shared_ptr& sharedActionSet); // IAdaptiveActionSet IFACEMETHODIMP get_Actions( @@ -108,7 +105,6 @@ namespace AdaptiveNamespace return AdaptiveCardElementBase::get_Requirements(requirements); } - IFACEMETHODIMP ToJson(_Out_ ABI::Windows::Data::Json::IJsonObject** result) { return AdaptiveCardElementBase::ToJson(result); diff --git a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp index 48fd18580a..f019ee57b8 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.cpp @@ -2,44 +2,64 @@ // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveActionSet.h" #include "AdaptiveActionSetRenderer.h" + +#include "ActionHelpers.h" +#include "AdaptiveActionSet.h" #include "AdaptiveElementParserRegistration.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" +#include "AdaptiveRenderArgs.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Controls::Primitives; namespace AdaptiveNamespace { - HRESULT AdaptiveActionSetRenderer::RuntimeClassInitialize() noexcept try - { - return S_OK; - } - CATCH_RETURN; - - HRESULT AdaptiveActionSetRenderer::Render(_In_ IAdaptiveCardElement* cardElement, - _In_ IAdaptiveRenderContext* renderContext, - _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try - { - return XamlBuilder::BuildActionSet(cardElement, renderContext, renderArgs, result); - } - CATCH_RETURN; + HRESULT AdaptiveActionSetRenderer::RuntimeClassInitialize() noexcept { return S_OK; } HRESULT AdaptiveActionSetRenderer::FromJson( _In_ ABI::Windows::Data::Json::IJsonObject* jsonObject, _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); } CATCH_RETURN; + + HRESULT AdaptiveActionSetRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, + _In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveRenderArgs* renderArgs, + _COM_Outptr_ IUIElement** actionSetControl) noexcept + try + { + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning( + ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"ActionSet was stripped from card because interactivity is not supported").Get()); + return S_OK; + } + + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveActionSet; + RETURN_IF_FAILED(cardElement.As(&adaptiveActionSet)); + + ComPtr> actions; + RETURN_IF_FAILED(adaptiveActionSet->get_Actions(&actions)); + + return ActionHelpers::BuildActionSetHelper(nullptr, adaptiveActionSet.Get(), actions.Get(), renderContext, renderArgs, actionSetControl); + } + CATCH_RETURN; } diff --git a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h index 7ab0816f05..6e20f53f37 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveActionSetRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ActionSet.h" namespace AdaptiveNamespace @@ -13,9 +11,10 @@ namespace AdaptiveNamespace ABI::AdaptiveNamespace::IAdaptiveElementRenderer, ABI::AdaptiveNamespace::IAdaptiveElementParser> { - InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSetRenderer, BaseTrust) + InspectableClass(RuntimeClass_AdaptiveCards_Rendering_Uwp_AdaptiveActionSetRenderer, BaseTrust); - public : HRESULT RuntimeClassInitialize() noexcept; + public: + HRESULT RuntimeClassInitialize() noexcept; IFACEMETHODIMP Render(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement* cardElement, _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, diff --git a/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp b/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp index 7477c811e5..69329cccc1 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveActionsConfig.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "AdaptiveActionsConfig.h" #include "AdaptiveShowCardActionConfig.h" -#include "Util.h" using namespace Microsoft::WRL; using namespace ABI::AdaptiveNamespace; @@ -11,7 +10,8 @@ using namespace ABI::Windows::UI; namespace AdaptiveNamespace { - HRESULT AdaptiveActionsConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveActionsConfig::RuntimeClassInitialize() noexcept + try { ActionsConfig actionsConfig; return RuntimeClassInitialize(actionsConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveActionsConfig.h b/source/uwp/Renderer/lib/AdaptiveActionsConfig.h index 2694b33521..fb600ed5df 100644 --- a/source/uwp/Renderer/lib/AdaptiveActionsConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveActionsConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveActionsConfig diff --git a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp index 8d113a3855..3b96b4b471 100644 --- a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp +++ b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.cpp @@ -16,7 +16,8 @@ namespace AdaptiveNamespace { AdaptiveBackgroundImage::AdaptiveBackgroundImage() {} - HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize() noexcept + try { std::shared_ptr image = std::make_shared(); @@ -24,8 +25,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize( - const std::shared_ptr& sharedImage) try + HRESULT AdaptiveBackgroundImage::RuntimeClassInitialize(const std::shared_ptr& sharedImage) + try { if (sharedImage == nullptr) { @@ -85,7 +86,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveBackgroundImage::GetSharedModel(std::shared_ptr& sharedImage) try + HRESULT AdaptiveBackgroundImage::GetSharedModel(std::shared_ptr& sharedImage) + try { std::shared_ptr image = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h index d5a1ccda4f..a877d81621 100644 --- a/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h +++ b/source/uwp/Renderer/lib/AdaptiveBackgroundImage.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "BackgroundImage.h" -#include namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveCard.cpp b/source/uwp/Renderer/lib/AdaptiveCard.cpp index 15956f3ec0..7985b54a0a 100644 --- a/source/uwp/Renderer/lib/AdaptiveCard.cpp +++ b/source/uwp/Renderer/lib/AdaptiveCard.cpp @@ -25,8 +25,8 @@ using namespace Microsoft::WRL::Wrappers; namespace AdaptiveNamespace { - HRESULT AdaptiveCardStaticsImpl::FromJsonString(_In_ HSTRING adaptiveJson, - _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try + HRESULT AdaptiveCardStaticsImpl::FromJsonString(_In_ HSTRING adaptiveJson, _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept + try { return FromJsonStringWithParserRegistration(adaptiveJson, nullptr, nullptr, parseResult); } @@ -35,7 +35,8 @@ namespace AdaptiveNamespace HRESULT AdaptiveCardStaticsImpl::FromJsonStringWithParserRegistration(_In_ HSTRING adaptiveJson, _In_ IAdaptiveElementParserRegistration* elementParserRegistration, _In_ IAdaptiveActionParserRegistration* actionParserRegistration, - _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try + _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept + try { *parseResult = nullptr; @@ -46,8 +47,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveCardStaticsImpl::FromJson(_In_ IJsonObject* adaptiveJson, - _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try + HRESULT AdaptiveCardStaticsImpl::FromJson(_In_ IJsonObject* adaptiveJson, _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept + try { return FromJsonWithParserRegistration(adaptiveJson, nullptr, nullptr, parseResult); } @@ -56,7 +57,8 @@ namespace AdaptiveNamespace HRESULT AdaptiveCardStaticsImpl::FromJsonWithParserRegistration(_In_ IJsonObject* adaptiveJson, _In_ IAdaptiveElementParserRegistration* elementParserRegistration, _In_ IAdaptiveActionParserRegistration* actionParserRegistration, - _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept try + _COM_Outptr_ IAdaptiveCardParseResult** parseResult) noexcept + try { *parseResult = nullptr; diff --git a/source/uwp/Renderer/lib/AdaptiveCard.h b/source/uwp/Renderer/lib/AdaptiveCard.h index 602c058e89..adab26cb37 100644 --- a/source/uwp/Renderer/lib/AdaptiveCard.h +++ b/source/uwp/Renderer/lib/AdaptiveCard.h @@ -2,7 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" #include "SharedAdaptiveCard.h" #include "AdaptiveBackgroundImage.h" diff --git a/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp b/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp index be46cf9486..2cbe57176a 100644 --- a/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveCardConfig.cpp @@ -10,7 +10,8 @@ using namespace ABI::Windows::UI; namespace AdaptiveNamespace { - HRESULT AdaptiveCardConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveCardConfig::RuntimeClassInitialize() noexcept + try { AdaptiveSharedNamespace::AdaptiveCardConfig cardConfig; return RuntimeClassInitialize(cardConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveCardConfig.h b/source/uwp/Renderer/lib/AdaptiveCardConfig.h index b0b9704c6a..361f030536 100644 --- a/source/uwp/Renderer/lib/AdaptiveCardConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveCardConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveCardConfig diff --git a/source/uwp/Renderer/lib/AdaptiveCardElement.h b/source/uwp/Renderer/lib/AdaptiveCardElement.h index 7a96538b8d..15c2fecb87 100644 --- a/source/uwp/Renderer/lib/AdaptiveCardElement.h +++ b/source/uwp/Renderer/lib/AdaptiveCardElement.h @@ -2,9 +2,8 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" #include "SemanticVersion.h" -#include "Enums.h" +#include "BaseElement.h" namespace AdaptiveNamespace { @@ -41,7 +40,8 @@ namespace AdaptiveNamespace IFACEMETHODIMP get_Height(_Out_ ABI::AdaptiveNamespace::HeightType* height); IFACEMETHODIMP put_Height(ABI::AdaptiveNamespace::HeightType height); - IFACEMETHODIMP get_Requirements(_COM_Outptr_ ABI::Windows::Foundation::Collections::IVector** requirements); + IFACEMETHODIMP get_Requirements( + _COM_Outptr_ ABI::Windows::Foundation::Collections::IVector** requirements); IFACEMETHODIMP ToJson(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result); diff --git a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp index a0594d681d..e5d536bd53 100644 --- a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp +++ b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.cpp @@ -34,10 +34,6 @@ #include "DefaultResourceDictionary.h" #include "InputValue.h" #include "RenderedAdaptiveCard.h" -#include "XamlHelpers.h" -#include -#include -#include using namespace concurrency; using namespace Microsoft::WRL; @@ -57,7 +53,8 @@ using namespace ABI::Windows::UI::Xaml::Media::Imaging; namespace AdaptiveNamespace { - HRESULT AdaptiveCardRenderer::RuntimeClassInitialize() + HRESULT AdaptiveCardRenderer::RuntimeClassInitialize() noexcept + try { RETURN_IF_FAILED(MakeAndInitialize(&m_xamlBuilder)); RETURN_IF_FAILED(MakeAndInitialize(&m_elementRendererRegistration)); @@ -70,6 +67,7 @@ namespace AdaptiveNamespace UpdateActionSentimentResourceDictionary(); return MakeAndInitialize(&m_resourceResolvers); } + CATCH_RETURN; HRESULT AdaptiveCardRenderer::put_OverrideStyles(_In_ ABI::Windows::UI::Xaml::IResourceDictionary* overrideDictionary) { @@ -138,7 +136,7 @@ namespace AdaptiveNamespace if (m_explicitDimensions) { - RETURN_IF_FAILED(m_xamlBuilder->SetFixedDimensions(m_desiredWidth, m_desiredHeight)); + m_xamlBuilder->SetFixedDimensions(m_desiredWidth, m_desiredHeight); } ComPtr renderContext; @@ -300,6 +298,24 @@ namespace AdaptiveNamespace m_actionSentimentResourceDictionary = actionSentimentResourceDictionary; } + HRESULT AdaptiveCardRenderer::TryInsertResourceToSentimentResourceDictionary(const std::wstring& resourceName, + _In_ IInspectable* value) + { + ComPtr propertyValueStatics; + RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), + &propertyValueStatics)); + + ComPtr resourceKey; + RETURN_IF_FAILED(propertyValueStatics->CreateString(HStringReference(resourceName.c_str()).Get(), resourceKey.GetAddressOf())); + + ComPtr> resourceDictionaryMap; + RETURN_IF_FAILED(m_actionSentimentResourceDictionary.As(&resourceDictionaryMap)); + + boolean replaced{}; + RETURN_IF_FAILED(resourceDictionaryMap->Insert(resourceKey.Get(), value, &replaced)); + return S_OK; + } + void AdaptiveCardRenderer::UpdateActionSentimentResourceDictionary() { ABI::Windows::UI::Color accentColor; @@ -322,24 +338,20 @@ namespace AdaptiveNamespace ABI::Windows::UI::Color lighterAttentionColor = GenerateLighterColor(attentionColor); ComPtr accentColorBrush = XamlHelpers::GetSolidColorBrush(accentColor); - THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(), - L"Adaptive.Action.Positive.Button.Static.Background", - accentColorBrush.Get())); + THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Positive.Button.Static.Background", + accentColorBrush.Get())); ComPtr lightAccentColorBrush = XamlHelpers::GetSolidColorBrush(lighterAccentColor); - THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(), - L"Adaptive.Action.Positive.Button.MouseOver.Background", - lightAccentColorBrush.Get())); + THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Positive.Button.MouseOver.Background", + lightAccentColorBrush.Get())); ComPtr attentionColorBrush = XamlHelpers::GetSolidColorBrush(attentionColor); - THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(), - L"Adaptive.Action.Destructive.Button.Foreground", - attentionColorBrush.Get())); + THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Destructive.Button.Foreground", + attentionColorBrush.Get())); ComPtr lightAttentionColorBrush = XamlHelpers::GetSolidColorBrush(lighterAttentionColor); - THROW_IF_FAILED(XamlBuilder::TryInsertResourceToResourceDictionaries(m_actionSentimentResourceDictionary.Get(), - L"Adaptive.Action.Destructive.Button.MouseOver.Foreground", - lightAttentionColorBrush.Get())); + THROW_IF_FAILED(TryInsertResourceToSentimentResourceDictionary(L"Adaptive.Action.Destructive.Button.MouseOver.Foreground", + lightAttentionColorBrush.Get())); } HRESULT AdaptiveCardRenderer::SetMergedDictionary() diff --git a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h index 4f82fcd2f5..1cea156e0a 100644 --- a/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h +++ b/source/uwp/Renderer/lib/AdaptiveCardRendererComponent.h @@ -18,7 +18,7 @@ namespace AdaptiveNamespace AdaptiveRuntime(AdaptiveCardRenderer); public: - HRESULT RuntimeClassInitialize(); + HRESULT RuntimeClassInitialize() noexcept; // IAdaptiveCardRenderer IFACEMETHODIMP put_OverrideStyles(_In_ ABI::Windows::UI::Xaml::IResourceDictionary* overrideDictionary); @@ -62,6 +62,13 @@ namespace AdaptiveNamespace IFACEMETHODIMP get_ResourceResolvers(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardResourceResolvers** value); private: + HRESULT CreateAdaptiveCardFromJsonString(_In_ HSTRING adaptiveJson, + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardParseResult** adaptiveCard); + void InitializeDefaultResourceDictionary(); + void UpdateActionSentimentResourceDictionary(); + HRESULT TryInsertResourceToSentimentResourceDictionary(const std::wstring& resourceName, _In_ IInspectable* value); + HRESULT SetMergedDictionary(); + Microsoft::WRL::ComPtr m_overrideDictionary; Microsoft::WRL::ComPtr m_defaultResourceDictionary; Microsoft::WRL::ComPtr m_mergedResourceDictionary; @@ -76,12 +83,6 @@ namespace AdaptiveNamespace bool m_explicitDimensions = false; UINT32 m_desiredWidth = 0; UINT32 m_desiredHeight = 0; - - HRESULT CreateAdaptiveCardFromJsonString(_In_ HSTRING adaptiveJson, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardParseResult** adaptiveCard); - void InitializeDefaultResourceDictionary(); - void UpdateActionSentimentResourceDictionary(); - HRESULT SetMergedDictionary(); }; ActivatableClass(AdaptiveCardRenderer); diff --git a/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp b/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp index 3ae7b66045..1ef1cf1b26 100644 --- a/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp +++ b/source/uwp/Renderer/lib/AdaptiveCardResourceResolvers.cpp @@ -9,7 +9,8 @@ using namespace ABI::Windows::Foundation; namespace AdaptiveNamespace { - HRESULT AdaptiveCardResourceResolvers::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveCardResourceResolvers::RuntimeClassInitialize() noexcept + try { return S_OK; } diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp b/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp index 3cba8f7608..ab7a42df3c 100644 --- a/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp +++ b/source/uwp/Renderer/lib/AdaptiveChoiceInput.cpp @@ -14,7 +14,8 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveChoiceInput::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveChoiceInput::RuntimeClassInitialize() noexcept + try { m_sharedChoiceInput = std::make_shared(); return S_OK; diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceInput.h b/source/uwp/Renderer/lib/AdaptiveChoiceInput.h index 889fc0fcef..d64834e90a 100644 --- a/source/uwp/Renderer/lib/AdaptiveChoiceInput.h +++ b/source/uwp/Renderer/lib/AdaptiveChoiceInput.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ChoiceInput.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp index edb996cad8..8e2afc9809 100644 --- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp +++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.cpp @@ -21,7 +21,8 @@ namespace AdaptiveNamespace m_choices = Microsoft::WRL::Make>(); } - HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize() noexcept + try { std::shared_ptr choiceSet = std::make_shared(); @@ -29,7 +30,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize(const std::shared_ptr& sharedChoiceSetInput) try + HRESULT AdaptiveChoiceSetInput::RuntimeClassInitialize(const std::shared_ptr& sharedChoiceSetInput) + try { if (sharedChoiceSetInput == nullptr) { @@ -107,7 +109,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveChoiceSetInput::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveChoiceSetInput::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr choiceSet = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h index 38220c38d0..71eb9f1359 100644 --- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h +++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInput.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" #include "ChoiceSetInput.h" -#include "Enums.h" -#include #include "AdaptiveInputElement.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp index ec95ed970e..e092ba463d 100644 --- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.cpp @@ -5,29 +5,57 @@ #include "AdaptiveChoiceSetInput.h" #include "AdaptiveChoiceSetInputRenderer.h" #include "AdaptiveElementParserRegistration.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Controls::Primitives; namespace AdaptiveNamespace { - HRESULT AdaptiveChoiceSetInputRenderer::RuntimeClassInitialize() noexcept try - { - return S_OK; - } - CATCH_RETURN; + HRESULT AdaptiveChoiceSetInputRenderer::RuntimeClassInitialize() noexcept { return S_OK; } - HRESULT AdaptiveChoiceSetInputRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveChoiceSetInputRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, - _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _In_ IAdaptiveRenderArgs* /*renderArgs*/, + _COM_Outptr_ IUIElement** choiceInputSet) noexcept + try { - return XamlBuilder::BuildChoiceSetInput(cardElement, renderContext, renderArgs, result); + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning( + ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"ChoiceSet was stripped from card because interactivity is not supported").Get()); + return S_OK; + } + + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveChoiceSetInput; + RETURN_IF_FAILED(cardElement.As(&adaptiveChoiceSetInput)); + + ABI::AdaptiveNamespace::ChoiceSetStyle choiceSetStyle; + RETURN_IF_FAILED(adaptiveChoiceSetInput->get_ChoiceSetStyle(&choiceSetStyle)); + + boolean isMultiSelect; + RETURN_IF_FAILED(adaptiveChoiceSetInput->get_IsMultiSelect(&isMultiSelect)); + + if (choiceSetStyle == ABI::AdaptiveNamespace::ChoiceSetStyle_Compact && !isMultiSelect) + { + BuildCompactChoiceSetInput(renderContext, adaptiveChoiceSetInput.Get(), choiceInputSet); + } + else + { + BuildExpandedChoiceSetInput(renderContext, adaptiveChoiceSetInput.Get(), isMultiSelect, choiceInputSet); + } + + XamlHelpers::AddInputValueToContext(renderContext, adaptiveCardElement, *choiceInputSet); + return S_OK; } CATCH_RETURN; @@ -36,10 +64,183 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); } CATCH_RETURN; + + std::vector AdaptiveChoiceSetInputRenderer::GetChoiceSetValueVector(_In_ IAdaptiveChoiceSetInput* adaptiveChoiceSetInput) + { + HString value; + THROW_IF_FAILED(adaptiveChoiceSetInput->get_Value(value.GetAddressOf())); + + std::vector values; + std::string stdValue = HStringToUTF8(value.Get()); + std::stringstream streamValue(stdValue); + + while (streamValue.good()) + { + std::string subString; + std::getline(streamValue, subString, ','); + values.push_back(std::move(subString)); + } + + return values; + } + + bool AdaptiveChoiceSetInputRenderer::IsChoiceSelected(std::vector selectedValues, _In_ IAdaptiveChoiceInput* choice) + { + HString value; + THROW_IF_FAILED(choice->get_Value(value.GetAddressOf())); + std::string stdValue = HStringToUTF8(value.Get()); + return std::find(selectedValues.begin(), selectedValues.end(), stdValue) != selectedValues.end(); + } + + HRESULT AdaptiveChoiceSetInputRenderer::BuildCompactChoiceSetInput(_In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveChoiceSetInput* adaptiveChoiceSetInput, + _COM_Outptr_ IUIElement** choiceInputSet) + { + ComPtr comboBox = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ComboBox)); + + // Set HorizontalAlignment to Stretch (defaults to Left for combo boxes) + ComPtr comboBoxAsFrameworkElement; + RETURN_IF_FAILED(comboBox.As(&comboBoxAsFrameworkElement)); + RETURN_IF_FAILED(comboBoxAsFrameworkElement->put_HorizontalAlignment(HorizontalAlignment_Stretch)); + + ComPtr itemsControl; + RETURN_IF_FAILED(comboBox.As(&itemsControl)); + + ComPtr> items; + RETURN_IF_FAILED(itemsControl->get_Items(items.GetAddressOf())); + + ComPtr> itemsVector; + RETURN_IF_FAILED(items.As(&itemsVector)); + + ComPtr> choices; + RETURN_IF_FAILED(adaptiveChoiceSetInput->get_Choices(&choices)); + + std::vector values = GetChoiceSetValueVector(adaptiveChoiceSetInput); + boolean wrap; + adaptiveChoiceSetInput->get_Wrap(&wrap); + + int currentIndex = 0; + int selectedIndex = -1; + XamlHelpers::IterateOverVector( + choices.Get(), [¤tIndex, &selectedIndex, itemsVector, values, wrap](IAdaptiveChoiceInput* adaptiveChoiceInput) { + HString title; + RETURN_IF_FAILED(adaptiveChoiceInput->get_Title(title.GetAddressOf())); + + ComPtr comboBoxItem = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ComboBoxItem)); + + XamlHelpers::SetContent(comboBoxItem.Get(), title.Get(), wrap); + + // If multiple values are specified, no option is selected + if (values.size() == 1 && IsChoiceSelected(values, adaptiveChoiceInput)) + { + selectedIndex = currentIndex; + } + + ComPtr inspectable; + RETURN_IF_FAILED(comboBoxItem.As(&inspectable)); + + RETURN_IF_FAILED(itemsVector->Append(inspectable.Get())); + currentIndex++; + return S_OK; + }); + + ComPtr selector; + RETURN_IF_FAILED(comboBox.As(&selector)); + RETURN_IF_FAILED(selector->put_SelectedIndex(selectedIndex)); + + ComPtr comboBoxAsUIElement; + RETURN_IF_FAILED(comboBox.As(&comboBoxAsUIElement)); + RETURN_IF_FAILED(XamlHelpers::AddHandledTappedEvent(comboBoxAsUIElement.Get())); + + XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Input.ChoiceSet.Compact", + comboBoxAsFrameworkElement.Get()); + + return comboBoxAsUIElement.CopyTo(choiceInputSet); + } + + HRESULT AdaptiveChoiceSetInputRenderer::BuildExpandedChoiceSetInput(_In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveChoiceSetInput* adaptiveChoiceSetInput, + boolean isMultiSelect, + _COM_Outptr_ IUIElement** choiceInputSet) + { + ComPtr> choices; + RETURN_IF_FAILED(adaptiveChoiceSetInput->get_Choices(&choices)); + + ComPtr stackPanel = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel)); + stackPanel->put_Orientation(Orientation::Orientation_Vertical); + + ComPtr panel; + RETURN_IF_FAILED(stackPanel.As(&panel)); + + std::vector values = GetChoiceSetValueVector(adaptiveChoiceSetInput); + + boolean wrap; + adaptiveChoiceSetInput->get_Wrap(&wrap); + + XamlHelpers::IterateOverVector( + choices.Get(), [panel, isMultiSelect, renderContext, values, wrap](IAdaptiveChoiceInput* adaptiveChoiceInput) { + ComPtr choiceItem; + if (isMultiSelect) + { + ComPtr checkBox = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_CheckBox)); + RETURN_IF_FAILED(checkBox.As(&choiceItem)); + + ComPtr frameworkElement; + RETURN_IF_FAILED(checkBox.As(&frameworkElement)); + XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Input.Choice.Multiselect", + frameworkElement.Get()); + + XamlHelpers::SetToggleValue(choiceItem.Get(), IsChoiceSelected(values, adaptiveChoiceInput)); + } + else + { + ComPtr radioButton = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_RadioButton)); + RETURN_IF_FAILED(radioButton.As(&choiceItem)); + + ComPtr frameworkElement; + RETURN_IF_FAILED(radioButton.As(&frameworkElement)); + XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Input.Choice.SingleSelect", + frameworkElement.Get()); + + if (values.size() == 1) + { + // When isMultiSelect is false, only 1 specified value is accepted. + // Otherwise, leave all options unset + XamlHelpers::SetToggleValue(choiceItem.Get(), IsChoiceSelected(values, adaptiveChoiceInput)); + } + } + + HString title; + RETURN_IF_FAILED(adaptiveChoiceInput->get_Title(title.GetAddressOf())); + XamlHelpers::SetContent(choiceItem.Get(), title.Get(), wrap); + + RETURN_IF_FAILED(XamlHelpers::AddHandledTappedEvent(choiceItem.Get())); + + XamlHelpers::AppendXamlElementToPanel(choiceItem.Get(), panel.Get()); + return S_OK; + }); + + ComPtr choiceSetAsFrameworkElement; + RETURN_IF_FAILED(stackPanel.As(&choiceSetAsFrameworkElement)); + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Input.ChoiceSet.Expanded", + choiceSetAsFrameworkElement.Get())); + + return stackPanel.CopyTo(choiceInputSet); + } } diff --git a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h index af94926e9c..81785cd869 100644 --- a/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveChoiceSetInputRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ChoiceSetInput.h" namespace AdaptiveNamespace @@ -28,6 +26,20 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParsers, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept override; + + private: + static std::vector GetChoiceSetValueVector(_In_ ABI::AdaptiveNamespace::IAdaptiveChoiceSetInput* adaptiveChoiceSetInput); + static bool IsChoiceSelected(std::vector selectedValues, + _In_ ABI::AdaptiveNamespace::IAdaptiveChoiceInput* choice); + + HRESULT BuildExpandedChoiceSetInput(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveChoiceSetInput* adaptiveChoiceSetInput, + boolean isMultiSelect, + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** choiceInputSet); + + HRESULT BuildCompactChoiceSetInput(_In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveChoiceSetInput* adaptiveChoiceSetInput, + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** choiceInputSet); }; ActivatableClass(AdaptiveChoiceSetInputRenderer); diff --git a/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp b/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp index 9a8609182b..4fb9dc2aed 100644 --- a/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveColorConfig.cpp @@ -11,7 +11,8 @@ using namespace ABI::Windows::UI; namespace AdaptiveNamespace { - HRESULT AdaptiveColorConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveColorConfig::RuntimeClassInitialize() noexcept + try { ColorConfig colorConfig; return RuntimeClassInitialize(colorConfig); @@ -57,7 +58,6 @@ namespace AdaptiveNamespace return m_highlightColors.CopyTo(highlightColors); } - HRESULT AdaptiveColorConfig::put_HighlightColors(_In_ IAdaptiveHighlightColorConfig* highlightColors) { m_highlightColors = highlightColors; diff --git a/source/uwp/Renderer/lib/AdaptiveColorConfig.h b/source/uwp/Renderer/lib/AdaptiveColorConfig.h index fad0fa37e4..50bc759321 100644 --- a/source/uwp/Renderer/lib/AdaptiveColorConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveColorConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveColorConfig diff --git a/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp b/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp index 966996f8fa..e1f8db2f78 100644 --- a/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveColorsConfig.cpp @@ -9,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveColorsConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveColorsConfig::RuntimeClassInitialize() noexcept + try { ColorsConfig colorsConfig; return RuntimeClassInitialize(colorsConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveColorsConfig.h b/source/uwp/Renderer/lib/AdaptiveColorsConfig.h index b6d7643573..1fdcf9ba71 100644 --- a/source/uwp/Renderer/lib/AdaptiveColorsConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveColorsConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveColorsConfig diff --git a/source/uwp/Renderer/lib/AdaptiveColumn.cpp b/source/uwp/Renderer/lib/AdaptiveColumn.cpp index 3b2c458170..562e2fb8ab 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumn.cpp +++ b/source/uwp/Renderer/lib/AdaptiveColumn.cpp @@ -21,14 +21,16 @@ namespace AdaptiveNamespace m_items = Microsoft::WRL::Make>(); } - HRESULT AdaptiveColumn::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveColumn::RuntimeClassInitialize() noexcept + try { std::shared_ptr column = std::make_shared(); return RuntimeClassInitialize(column); } CATCH_RETURN; - HRESULT AdaptiveColumn::RuntimeClassInitialize(const std::shared_ptr& sharedColumn) try + HRESULT AdaptiveColumn::RuntimeClassInitialize(const std::shared_ptr& sharedColumn) + try { GenerateContainedElementsProjection(sharedColumn->GetItems(), m_items.Get()); GenerateActionProjection(sharedColumn->GetSelectAction(), &m_selectAction); @@ -157,7 +159,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveColumn::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveColumn::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr column = std::make_shared(); RETURN_IF_FAILED(SetSharedElementProperties(std::static_pointer_cast(column))); diff --git a/source/uwp/Renderer/lib/AdaptiveColumn.h b/source/uwp/Renderer/lib/AdaptiveColumn.h index e120f97bc3..c2ec5f8767 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumn.h +++ b/source/uwp/Renderer/lib/AdaptiveColumn.h @@ -2,12 +2,8 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "AdaptiveCardElement.h" #include "AdaptiveBackgroundImage.h" -#include "Enums.h" #include "Column.h" -#include namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveColumnRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveColumnRenderer.cpp index c881603484..08f075a77d 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumnRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveColumnRenderer.cpp @@ -3,31 +3,131 @@ #include "pch.h" #include "AdaptiveColumnRenderer.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" + +#include "ActionHelpers.h" #include "AdaptiveColumn.h" #include "AdaptiveElementParserRegistration.h" +#include "AdaptiveRenderArgs.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveColumnRenderer::RuntimeClassInitialize() noexcept try - { - return S_OK; - } - CATCH_RETURN; + HRESULT AdaptiveColumnRenderer::RuntimeClassInitialize() noexcept { return S_OK; } - HRESULT AdaptiveColumnRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveColumnRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** ColumnControl) noexcept + try { - return XamlBuilder::BuildColumn(cardElement, renderContext, renderArgs, result); + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveColumn; + RETURN_IF_FAILED(cardElement.As(&adaptiveColumn)); + + ComPtr columnBorder = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Border)); + + ComPtr columnPanel; + RETURN_IF_FAILED(MakeAndInitialize(&columnPanel)); + + ComPtr columnPanelAsUIElement; + RETURN_IF_FAILED(columnPanel.As(&columnPanelAsUIElement)); + + RETURN_IF_FAILED(columnBorder->put_Child(columnPanelAsUIElement.Get())); + + ComPtr columnAsContainerBase; + RETURN_IF_FAILED(adaptiveColumn.As(&columnAsContainerBase)); + + ABI::AdaptiveNamespace::ContainerStyle containerStyle; + RETURN_IF_FAILED( + XamlHelpers::HandleStylingAndPadding(columnAsContainerBase.Get(), columnBorder.Get(), renderContext, renderArgs, &containerStyle)); + + ComPtr parentElement; + RETURN_IF_FAILED(renderArgs->get_ParentElement(&parentElement)); + ComPtr newRenderArgs; + RETURN_IF_FAILED(MakeAndInitialize(&newRenderArgs, containerStyle, parentElement.Get(), renderArgs)); + + ComPtr columnAsPanel; + THROW_IF_FAILED(columnPanel.As(&columnAsPanel)); + + ComPtr> childItems; + RETURN_IF_FAILED(adaptiveColumn->get_Items(&childItems)); + RETURN_IF_FAILED(XamlBuilder::BuildPanelChildren( + childItems.Get(), columnAsPanel.Get(), renderContext, newRenderArgs.Get(), [](IUIElement*) {})); + + ABI::AdaptiveNamespace::VerticalContentAlignment verticalContentAlignment; + RETURN_IF_FAILED(adaptiveColumn->get_VerticalContentAlignment(&verticalContentAlignment)); + + XamlHelpers::SetVerticalContentAlignmentToChildren(columnPanel.Get(), verticalContentAlignment); + + // Assign vertical alignment to the top so that on fixed height cards, the content + // still renders at the top even if the content is shorter than the full card + ComPtr columnPanelAsFrameworkElement; + RETURN_IF_FAILED(columnPanel.As(&columnPanelAsFrameworkElement)); + RETURN_IF_FAILED(columnPanelAsFrameworkElement->put_VerticalAlignment(VerticalAlignment_Stretch)); + + RETURN_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.Column", columnPanelAsFrameworkElement.Get())); + + UINT32 columnMinHeight{}; + RETURN_IF_FAILED(columnAsContainerBase->get_MinHeight(&columnMinHeight)); + if (columnMinHeight > 0) + { + RETURN_IF_FAILED(columnPanelAsFrameworkElement->put_MinHeight(columnMinHeight)); + } + + ComPtr selectAction; + RETURN_IF_FAILED(columnAsContainerBase->get_SelectAction(&selectAction)); + + // Define columnAsUIElement based on the existence of a backgroundImage + ComPtr columnAsUIElement; + ComPtr backgroundImage; + BOOL backgroundImageIsValid; + RETURN_IF_FAILED(adaptiveColumn->get_BackgroundImage(&backgroundImage)); + RETURN_IF_FAILED(IsBackgroundImageValid(backgroundImage.Get(), &backgroundImageIsValid)); + if (backgroundImageIsValid) + { + ComPtr rootElement = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + ComPtr rootAsPanel; + RETURN_IF_FAILED(rootElement.As(&rootAsPanel)); + + XamlHelpers::ApplyBackgroundToRoot(rootAsPanel.Get(), backgroundImage.Get(), renderContext, newRenderArgs.Get()); + + // get HeightType for column + ABI::AdaptiveNamespace::HeightType columnHeightType{}; + RETURN_IF_FAILED(cardElement->get_Height(&columnHeightType)); + + // Add columnBorder to rootElement + ComPtr columnBorderAsFElement; + RETURN_IF_FAILED(columnBorder.As(&columnBorderAsFElement)); + XamlHelpers::AppendXamlElementToPanel(columnBorderAsFElement.Get(), rootAsPanel.Get(), columnHeightType); + + RETURN_IF_FAILED(rootElement.As(&columnAsUIElement)); + } + else + { + RETURN_IF_FAILED(columnBorder.As(&columnAsUIElement)); + } + + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + ActionHelpers::HandleSelectAction(adaptiveCardElement, + selectAction.Get(), + renderContext, + columnAsUIElement.Get(), + XamlHelpers::SupportsInteractivity(hostConfig.Get()), + false, + ColumnControl); + return S_OK; } CATCH_RETURN; @@ -36,7 +136,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveColumnRenderer.h b/source/uwp/Renderer/lib/AdaptiveColumnRenderer.h index 1aefc7efd7..7c4e01720b 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumnRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveColumnRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "Column.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveColumnSet.cpp b/source/uwp/Renderer/lib/AdaptiveColumnSet.cpp index e6a3f5affb..651ec40808 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumnSet.cpp +++ b/source/uwp/Renderer/lib/AdaptiveColumnSet.cpp @@ -23,14 +23,16 @@ namespace AdaptiveNamespace m_columns = Microsoft::WRL::Make>(); } - HRESULT AdaptiveColumnSet::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveColumnSet::RuntimeClassInitialize() noexcept + try { std::shared_ptr columnSet = std::make_shared(); return RuntimeClassInitialize(columnSet); } CATCH_RETURN; - HRESULT AdaptiveColumnSet::RuntimeClassInitialize(const std::shared_ptr& sharedColumnSet) noexcept try + HRESULT AdaptiveColumnSet::RuntimeClassInitialize(const std::shared_ptr& sharedColumnSet) noexcept + try { if (sharedColumnSet == nullptr) { @@ -117,7 +119,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveColumnSet::GetSharedModel(std::shared_ptr& sharedModel) noexcept try + HRESULT AdaptiveColumnSet::GetSharedModel(std::shared_ptr& sharedModel) noexcept + try { std::shared_ptr columnSet = std::make_shared(); RETURN_IF_FAILED(SetSharedElementProperties(std::static_pointer_cast(columnSet))); diff --git a/source/uwp/Renderer/lib/AdaptiveColumnSet.h b/source/uwp/Renderer/lib/AdaptiveColumnSet.h index b0b0616af5..612b0d3730 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumnSet.h +++ b/source/uwp/Renderer/lib/AdaptiveColumnSet.h @@ -2,11 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ColumnSet.h" -#include -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.cpp index 736f5d75e6..24aa990d89 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.cpp @@ -2,32 +2,229 @@ // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveColumnSet.h" #include "AdaptiveColumnSetRenderer.h" + +#include "ActionHelpers.h" +#include "AdaptiveColumnSet.h" #include "AdaptiveElementParserRegistration.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" +#include "AdaptiveRenderArgs.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveColumnSetRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveColumnSetRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveColumnSetRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveColumnSetRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** columnSetControl) noexcept + try { - return XamlBuilder::BuildColumnSet(cardElement, renderContext, renderArgs, result); + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveColumnSet; + RETURN_IF_FAILED(cardElement.As(&adaptiveColumnSet)); + + ComPtr columnSetBorder = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Border)); + + ComPtr gridContainer; + RETURN_IF_FAILED(MakeAndInitialize(&gridContainer)); + + ComPtr gridContainerAsUIElement; + RETURN_IF_FAILED(gridContainer.As(&gridContainerAsUIElement)); + + RETURN_IF_FAILED(columnSetBorder->put_Child(gridContainerAsUIElement.Get())); + + ComPtr columnSetAsContainerBase; + RETURN_IF_FAILED(adaptiveColumnSet.As(&columnSetAsContainerBase)); + + ABI::AdaptiveNamespace::ContainerStyle containerStyle; + RETURN_IF_FAILED(XamlHelpers::HandleStylingAndPadding( + columnSetAsContainerBase.Get(), columnSetBorder.Get(), renderContext, renderArgs, &containerStyle)); + + ComPtr parentElement; + RETURN_IF_FAILED(renderArgs->get_ParentElement(&parentElement)); + ComPtr newRenderArgs; + RETURN_IF_FAILED(MakeAndInitialize(&newRenderArgs, containerStyle, parentElement.Get(), renderArgs)); + + ComPtr xamlGrid = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + ComPtr gridStatics; + RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid).Get(), &gridStatics)); + + ComPtr> columns; + RETURN_IF_FAILED(adaptiveColumnSet->get_Columns(&columns)); + int currentColumn{}; + ComPtr elementRenderers; + RETURN_IF_FAILED(renderContext->get_ElementRenderers(&elementRenderers)); + ComPtr columnRenderer; + RETURN_IF_FAILED(elementRenderers->Get(HStringReference(L"Column").Get(), &columnRenderer)); + + if (columnRenderer == nullptr) + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::NoRendererForType, + HStringReference(L"No renderer found for type: Column").Get()); + *columnSetControl = nullptr; + return S_OK; + } + + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + boolean ancestorHasFallback; + RETURN_IF_FAILED(renderArgs->get_AncestorHasFallback(&ancestorHasFallback)); + + ComPtr gridAsPanel; + RETURN_IF_FAILED(xamlGrid.As(&gridAsPanel)); + + HRESULT hrColumns = XamlHelpers::IterateOverVectorWithFailure(columns.Get(), ancestorHasFallback, [&](IAdaptiveColumn* column) { + ComPtr columnAsCardElement; + ComPtr localColumn(column); + RETURN_IF_FAILED(localColumn.As(&columnAsCardElement)); + + ComPtr testColumn; + columnAsCardElement.As(&testColumn); + + ComPtr> columnDefinitions; + RETURN_IF_FAILED(xamlGrid->get_ColumnDefinitions(&columnDefinitions)); + + ABI::AdaptiveNamespace::FallbackType fallbackType; + RETURN_IF_FAILED(columnAsCardElement->get_FallbackType(&fallbackType)); + + // Build the Column + RETURN_IF_FAILED(newRenderArgs->put_AncestorHasFallback( + ancestorHasFallback || fallbackType != ABI::AdaptiveNamespace::FallbackType::None)); + + ComPtr xamlColumn; + HRESULT hr = columnRenderer->Render(columnAsCardElement.Get(), renderContext, newRenderArgs.Get(), &xamlColumn); + if (hr == E_PERFORM_FALLBACK) + { + RETURN_IF_FAILED(XamlHelpers::RenderFallback(columnAsCardElement.Get(), renderContext, newRenderArgs.Get(), &xamlColumn)); + } + + RETURN_IF_FAILED(newRenderArgs->put_AncestorHasFallback(ancestorHasFallback)); + + // Check the column for nullptr as it may have been dropped due to fallback + if (xamlColumn != nullptr) + { + // If not the first column + ComPtr separator; + if (currentColumn > 0) + { + // Add Separator to the columnSet + bool needsSeparator; + UINT spacing; + UINT separatorThickness; + ABI::Windows::UI::Color separatorColor; + XamlHelpers::GetSeparationConfigForElement( + columnAsCardElement.Get(), hostConfig.Get(), &spacing, &separatorThickness, &separatorColor, &needsSeparator); + + if (needsSeparator) + { + // Create a new ColumnDefinition for the separator + ComPtr separatorColumnDefinition = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + RETURN_IF_FAILED(separatorColumnDefinition->put_Width({1.0, GridUnitType::GridUnitType_Auto})); + RETURN_IF_FAILED(columnDefinitions->Append(separatorColumnDefinition.Get())); + + separator = XamlHelpers::CreateSeparator(renderContext, spacing, separatorThickness, separatorColor, false); + ComPtr separatorAsFrameworkElement; + RETURN_IF_FAILED(separator.As(&separatorAsFrameworkElement)); + gridStatics->SetColumn(separatorAsFrameworkElement.Get(), currentColumn++); + XamlHelpers::AppendXamlElementToPanel(separator.Get(), gridAsPanel.Get()); + } + } + + // Determine if the column is auto, stretch, or percentage width, and set the column width appropriately + ComPtr columnDefinition = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + + boolean isVisible; + RETURN_IF_FAILED(columnAsCardElement->get_IsVisible(&isVisible)); + + RETURN_IF_FAILED(XamlHelpers::HandleColumnWidth(column, isVisible, columnDefinition.Get())); + + RETURN_IF_FAILED(columnDefinitions->Append(columnDefinition.Get())); + + // Mark the column container with the current column + ComPtr columnAsFrameworkElement; + RETURN_IF_FAILED(xamlColumn.As(&columnAsFrameworkElement)); + gridStatics->SetColumn(columnAsFrameworkElement.Get(), currentColumn++); + + // Finally add the column container to the grid + RETURN_IF_FAILED(XamlHelpers::AddRenderedControl(xamlColumn.Get(), + columnAsCardElement.Get(), + gridAsPanel.Get(), + separator.Get(), + columnDefinition.Get(), + [](IUIElement*) {})); + } + return S_OK; + }); + RETURN_IF_FAILED(hrColumns); + + RETURN_IF_FAILED(XamlHelpers::SetSeparatorVisibility(gridAsPanel.Get())); + + ComPtr columnSetAsFrameworkElement; + RETURN_IF_FAILED(xamlGrid.As(&columnSetAsFrameworkElement)); + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.ColumnSet", + columnSetAsFrameworkElement.Get())); + RETURN_IF_FAILED(columnSetAsFrameworkElement->put_VerticalAlignment(VerticalAlignment_Stretch)); + + ComPtr selectAction; + RETURN_IF_FAILED(columnSetAsContainerBase->get_SelectAction(&selectAction)); + + ComPtr gridContainerAsPanel; + RETURN_IF_FAILED(gridContainer.As(&gridContainerAsPanel)); + + ComPtr gridContainerAsFrameworkElement; + RETURN_IF_FAILED(gridContainer.As(&gridContainerAsFrameworkElement)); + + ComPtr gridAsUIElement; + RETURN_IF_FAILED(xamlGrid.As(&gridAsUIElement)); + + ComPtr columnSetAsCardElement; + RETURN_IF_FAILED(adaptiveColumnSet.As(&columnSetAsCardElement)); + + ABI::AdaptiveNamespace::HeightType columnSetHeightType; + RETURN_IF_FAILED(columnSetAsCardElement->get_Height(&columnSetHeightType)); + + ComPtr columnAsContainerBase; + RETURN_IF_FAILED(adaptiveColumnSet.As(&columnAsContainerBase)); + + UINT32 columnSetMinHeight{}; + RETURN_IF_FAILED(columnAsContainerBase->get_MinHeight(&columnSetMinHeight)); + if (columnSetMinHeight > 0) + { + RETURN_IF_FAILED(gridContainerAsFrameworkElement->put_MinHeight(columnSetMinHeight)); + } + + XamlHelpers::AppendXamlElementToPanel(xamlGrid.Get(), gridContainerAsPanel.Get(), columnSetHeightType); + + ComPtr columnSetBorderAsUIElement; + RETURN_IF_FAILED(columnSetBorder.As(&columnSetBorderAsUIElement)); + + ActionHelpers::HandleSelectAction(adaptiveCardElement, + selectAction.Get(), + renderContext, + columnSetBorderAsUIElement.Get(), + XamlHelpers::SupportsInteractivity(hostConfig.Get()), + true, + columnSetControl); + return S_OK; } CATCH_RETURN; @@ -36,7 +233,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.h b/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.h index 5b1626d5dc..fe60baaa23 100644 --- a/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveColumnSetRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ColumnSet.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveContainer.cpp b/source/uwp/Renderer/lib/AdaptiveContainer.cpp index f326b8851b..e90022c92c 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveContainer.cpp @@ -21,14 +21,16 @@ namespace AdaptiveNamespace m_items = Microsoft::WRL::Make>(); } - HRESULT AdaptiveContainer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveContainer::RuntimeClassInitialize() noexcept + try { std::shared_ptr container = std::make_shared(); return RuntimeClassInitialize(container); } CATCH_RETURN; - HRESULT AdaptiveContainer::RuntimeClassInitialize(const std::shared_ptr& sharedContainer) try + HRESULT AdaptiveContainer::RuntimeClassInitialize(const std::shared_ptr& sharedContainer) + try { if (sharedContainer == nullptr) { @@ -144,7 +146,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveContainer::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveContainer::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr container = std::make_shared(); RETURN_IF_FAILED(SetSharedElementProperties(std::static_pointer_cast(container))); diff --git a/source/uwp/Renderer/lib/AdaptiveContainer.h b/source/uwp/Renderer/lib/AdaptiveContainer.h index 206847d190..823701ed20 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainer.h +++ b/source/uwp/Renderer/lib/AdaptiveContainer.h @@ -2,11 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "Container.h" -#include -#include "AdaptiveCardElement.h" #include "AdaptiveBackgroundImage.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveContainerRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveContainerRenderer.cpp index ae3ac231f6..fcdf0f2feb 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainerRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveContainerRenderer.cpp @@ -3,31 +3,136 @@ #include "pch.h" #include "AdaptiveContainer.h" + +#include "ActionHelpers.h" #include "AdaptiveContainerRenderer.h" #include "AdaptiveElementParserRegistration.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" +#include "AdaptiveRenderArgs.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveContainerRenderer::RuntimeClassInitialize() noexcept try - { - return S_OK; - } - CATCH_RETURN; + HRESULT AdaptiveContainerRenderer::RuntimeClassInitialize() noexcept { return S_OK; } - HRESULT AdaptiveContainerRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveContainerRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** containerControl) noexcept + try { - return XamlBuilder::BuildContainer(cardElement, renderContext, renderArgs, result); + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveContainer; + RETURN_IF_FAILED(cardElement.As(&adaptiveContainer)); + + ComPtr containerPanel; + RETURN_IF_FAILED(MakeAndInitialize(&containerPanel)); + + ComPtr containerPanelAsFrameWorkElement; + RETURN_IF_FAILED(containerPanel.As(&containerPanelAsFrameWorkElement)); + + // Assign vertical alignment to the top so that on fixed height cards, the content + // still renders at the top even if the content is shorter than the full card + ABI::AdaptiveNamespace::HeightType containerHeightType{}; + RETURN_IF_FAILED(cardElement->get_Height(&containerHeightType)); + if (containerHeightType == ABI::AdaptiveNamespace::HeightType::Auto) + { + RETURN_IF_FAILED(containerPanelAsFrameWorkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + } + + ComPtr containerAsContainerBase; + RETURN_IF_FAILED(adaptiveContainer.As(&containerAsContainerBase)); + + UINT32 containerMinHeight{}; + RETURN_IF_FAILED(containerAsContainerBase->get_MinHeight(&containerMinHeight)); + if (containerMinHeight > 0) + { + RETURN_IF_FAILED(containerPanelAsFrameWorkElement->put_MinHeight(containerMinHeight)); + } + + ComPtr containerBorder = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Border)); + + ABI::AdaptiveNamespace::ContainerStyle containerStyle; + RETURN_IF_FAILED(XamlHelpers::HandleStylingAndPadding( + containerAsContainerBase.Get(), containerBorder.Get(), renderContext, renderArgs, &containerStyle)); + + ComPtr parentElement; + RETURN_IF_FAILED(renderArgs->get_ParentElement(&parentElement)); + ComPtr newRenderArgs; + RETURN_IF_FAILED(MakeAndInitialize(&newRenderArgs, containerStyle, parentElement.Get(), renderArgs)); + + ComPtr containerPanelAsPanel; + RETURN_IF_FAILED(containerPanel.As(&containerPanelAsPanel)); + ComPtr> childItems; + RETURN_IF_FAILED(adaptiveContainer->get_Items(&childItems)); + RETURN_IF_FAILED(XamlBuilder::BuildPanelChildren( + childItems.Get(), containerPanelAsPanel.Get(), renderContext, newRenderArgs.Get(), [](IUIElement*) {})); + + ABI::AdaptiveNamespace::VerticalContentAlignment verticalContentAlignment; + RETURN_IF_FAILED(adaptiveContainer->get_VerticalContentAlignment(&verticalContentAlignment)); + + XamlHelpers::SetVerticalContentAlignmentToChildren(containerPanel.Get(), verticalContentAlignment); + + // Check if backgroundImage defined + ComPtr backgroundImage; + BOOL backgroundImageIsValid; + RETURN_IF_FAILED(adaptiveContainer->get_BackgroundImage(&backgroundImage)); + RETURN_IF_FAILED(IsBackgroundImageValid(backgroundImage.Get(), &backgroundImageIsValid)); + if (backgroundImageIsValid) + { + ComPtr rootElement = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + ComPtr rootAsPanel; + RETURN_IF_FAILED(rootElement.As(&rootAsPanel)); + + XamlHelpers::ApplyBackgroundToRoot(rootAsPanel.Get(), backgroundImage.Get(), renderContext, newRenderArgs.Get()); + + // Add rootElement to containerBorder + ComPtr rootAsUIElement; + RETURN_IF_FAILED(rootElement.As(&rootAsUIElement)); + RETURN_IF_FAILED(containerBorder->put_Child(rootAsUIElement.Get())); + + // Add containerPanel to rootElement + ComPtr containerPanelAsFElement; + RETURN_IF_FAILED(containerPanel.As(&containerPanelAsFElement)); + XamlHelpers::AppendXamlElementToPanel(containerPanelAsFElement.Get(), rootAsPanel.Get(), containerHeightType); + } + else + { + // instead, directly add containerPanel to containerBorder + ComPtr containerPanelAsUIElement; + RETURN_IF_FAILED(containerPanel.As(&containerPanelAsUIElement)); + RETURN_IF_FAILED(containerBorder->put_Child(containerPanelAsUIElement.Get())); + } + + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Container", + containerPanelAsFrameWorkElement.Get())); + + ComPtr selectAction; + RETURN_IF_FAILED(containerAsContainerBase->get_SelectAction(&selectAction)); + + ComPtr containerBorderAsUIElement; + RETURN_IF_FAILED(containerBorder.As(&containerBorderAsUIElement)); + + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + ActionHelpers::HandleSelectAction(adaptiveCardElement, + selectAction.Get(), + renderContext, + containerBorderAsUIElement.Get(), + XamlHelpers::SupportsInteractivity(hostConfig.Get()), + true, + containerControl); + return S_OK; } CATCH_RETURN; @@ -36,7 +141,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveContainerRenderer.h b/source/uwp/Renderer/lib/AdaptiveContainerRenderer.h index 3e2f8b0b7f..48a06463d3 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainerRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveContainerRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "Container.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.cpp b/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.cpp index b686bad0d7..b926a64cf9 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.cpp +++ b/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.cpp @@ -9,7 +9,8 @@ using namespace Microsoft::WRL::Wrappers; namespace AdaptiveNamespace { - HRESULT AdaptiveContainerStyleDefinition::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveContainerStyleDefinition::RuntimeClassInitialize() noexcept + try { ContainerStyleDefinition styleDefinition; return RuntimeClassInitialize(styleDefinition); diff --git a/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.h b/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.h index 65b80d79e1..61f1722f20 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.h +++ b/source/uwp/Renderer/lib/AdaptiveContainerStyleDefinition.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveContainerStyleDefinition diff --git a/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.cpp b/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.cpp index c4327d0372..5076431666 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.cpp +++ b/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.cpp @@ -7,9 +7,12 @@ using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; +using namespace ABI::AdaptiveNamespace; + namespace AdaptiveNamespace { - HRESULT AdaptiveContainerStylesDefinition::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveContainerStylesDefinition::RuntimeClassInitialize() noexcept + try { ContainerStylesDefinition stylesDefinition; return RuntimeClassInitialize(stylesDefinition); @@ -21,74 +24,75 @@ namespace AdaptiveNamespace RETURN_IF_FAILED(MakeAndInitialize(m_default.GetAddressOf(), stylesDefinition.defaultPalette)); RETURN_IF_FAILED(MakeAndInitialize(m_emphasis.GetAddressOf(), stylesDefinition.emphasisPalette)); RETURN_IF_FAILED(MakeAndInitialize(m_good.GetAddressOf(), stylesDefinition.goodPalette)); - RETURN_IF_FAILED(MakeAndInitialize(m_attention.GetAddressOf(), stylesDefinition.attentionPalette)); + RETURN_IF_FAILED(MakeAndInitialize(m_attention.GetAddressOf(), + stylesDefinition.attentionPalette)); RETURN_IF_FAILED(MakeAndInitialize(m_warning.GetAddressOf(), stylesDefinition.warningPalette)); RETURN_IF_FAILED(MakeAndInitialize(m_accent.GetAddressOf(), stylesDefinition.accentPalette)); return S_OK; } - HRESULT AdaptiveContainerStylesDefinition::get_Default(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value) + HRESULT AdaptiveContainerStylesDefinition::get_Default(_COM_Outptr_ IAdaptiveContainerStyleDefinition** value) { return m_default.CopyTo(value); } - HRESULT AdaptiveContainerStylesDefinition::put_Default(_In_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value) + HRESULT AdaptiveContainerStylesDefinition::put_Default(_In_ IAdaptiveContainerStyleDefinition* value) { m_default = value; return S_OK; } - HRESULT AdaptiveContainerStylesDefinition::get_Emphasis(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value) + HRESULT AdaptiveContainerStylesDefinition::get_Emphasis(_COM_Outptr_ IAdaptiveContainerStyleDefinition** value) { return m_emphasis.CopyTo(value); } - HRESULT AdaptiveContainerStylesDefinition::put_Emphasis(_In_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value) + HRESULT AdaptiveContainerStylesDefinition::put_Emphasis(_In_ IAdaptiveContainerStyleDefinition* value) { m_emphasis = value; return S_OK; } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::get_Good(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value) + HRESULT AdaptiveContainerStylesDefinition::get_Good(_COM_Outptr_ IAdaptiveContainerStyleDefinition** value) { return m_good.CopyTo(value); } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::put_Good(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value) + HRESULT AdaptiveContainerStylesDefinition::put_Good(_In_ IAdaptiveContainerStyleDefinition* value) { m_good = value; return S_OK; } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::get_Attention(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value) + HRESULT AdaptiveContainerStylesDefinition::get_Attention(_COM_Outptr_ IAdaptiveContainerStyleDefinition** value) { return m_attention.CopyTo(value); } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::put_Attention(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value) + HRESULT AdaptiveContainerStylesDefinition::put_Attention(_In_ IAdaptiveContainerStyleDefinition* value) { m_emphasis = value; return S_OK; } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::get_Warning(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value) + HRESULT AdaptiveContainerStylesDefinition::get_Warning(_COM_Outptr_ IAdaptiveContainerStyleDefinition** value) { return m_warning.CopyTo(value); } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::put_Warning(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value) + HRESULT AdaptiveContainerStylesDefinition::put_Warning(_In_ IAdaptiveContainerStyleDefinition* value) { m_warning = value; return S_OK; } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::get_Accent(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value) + HRESULT AdaptiveContainerStylesDefinition::get_Accent(_COM_Outptr_ IAdaptiveContainerStyleDefinition** value) { return m_accent.CopyTo(value); } - _Use_decl_annotations_ HRESULT AdaptiveContainerStylesDefinition::put_Accent(ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value) + HRESULT AdaptiveContainerStylesDefinition::put_Accent(_In_ IAdaptiveContainerStyleDefinition* value) { m_accent = value; return S_OK; diff --git a/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.h b/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.h index c6521895a3..57847e56a0 100644 --- a/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.h +++ b/source/uwp/Renderer/lib/AdaptiveContainerStylesDefinition.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveContainerStylesDefinition @@ -23,16 +19,16 @@ namespace AdaptiveNamespace IFACEMETHODIMP get_Emphasis(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); IFACEMETHODIMP put_Emphasis(_In_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value); - IFACEMETHODIMP get_Good(_Out_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); + IFACEMETHODIMP get_Good(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); IFACEMETHODIMP put_Good(_In_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value); - IFACEMETHODIMP get_Attention(_Out_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); + IFACEMETHODIMP get_Attention(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); IFACEMETHODIMP put_Attention(_In_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value); - IFACEMETHODIMP get_Warning(_Out_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); + IFACEMETHODIMP get_Warning(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); IFACEMETHODIMP put_Warning(_In_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value); - IFACEMETHODIMP get_Accent(_Out_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); + IFACEMETHODIMP get_Accent(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition** value); IFACEMETHODIMP put_Accent(_In_ ABI::AdaptiveNamespace::IAdaptiveContainerStyleDefinition* value); private: diff --git a/source/uwp/Renderer/lib/AdaptiveDateInput.cpp b/source/uwp/Renderer/lib/AdaptiveDateInput.cpp index 86b06dcacf..e199a82fff 100644 --- a/source/uwp/Renderer/lib/AdaptiveDateInput.cpp +++ b/source/uwp/Renderer/lib/AdaptiveDateInput.cpp @@ -14,14 +14,16 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveDateInput::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveDateInput::RuntimeClassInitialize() noexcept + try { std::shared_ptr dateInput = std::make_shared(); return RuntimeClassInitialize(dateInput); } CATCH_RETURN; - HRESULT AdaptiveDateInput::RuntimeClassInitialize(const std::shared_ptr& sharedDateInput) try + HRESULT AdaptiveDateInput::RuntimeClassInitialize(const std::shared_ptr& sharedDateInput) + try { if (sharedDateInput == nullptr) { @@ -63,7 +65,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveDateInput::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveDateInput::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr dateInput = std::make_shared(); RETURN_IF_FAILED(SetSharedElementProperties(std::static_pointer_cast(dateInput))); diff --git a/source/uwp/Renderer/lib/AdaptiveDateInput.h b/source/uwp/Renderer/lib/AdaptiveDateInput.h index 95f82cecc8..16b58aa0cf 100644 --- a/source/uwp/Renderer/lib/AdaptiveDateInput.h +++ b/source/uwp/Renderer/lib/AdaptiveDateInput.h @@ -2,9 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" #include "DateInput.h" -#include "Enums.h" #include "AdaptiveInputElement.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.cpp index 21d5fc953e..f9527f30d2 100644 --- a/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.cpp @@ -5,29 +5,114 @@ #include "AdaptiveDateInput.h" #include "AdaptiveDateInputRenderer.h" #include "AdaptiveElementParserRegistration.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveDateInputRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveDateInputRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveDateInputRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveDateInputRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, - _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _In_ IAdaptiveRenderArgs* /*renderArgs*/, + _COM_Outptr_ IUIElement** dateInputControl) noexcept + try { - return XamlBuilder::BuildDateInput(cardElement, renderContext, renderArgs, result); + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning( + ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"Date input was stripped from card because interactivity is not supported").Get()); + return S_OK; + } + + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveDateInput; + RETURN_IF_FAILED(cardElement.As(&adaptiveDateInput)); + + ComPtr datePicker = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_CalendarDatePicker)); + + HString placeHolderText; + RETURN_IF_FAILED(adaptiveDateInput->get_Placeholder(placeHolderText.GetAddressOf())); + RETURN_IF_FAILED(datePicker->put_PlaceholderText(placeHolderText.Get())); + + // Make the picker stretch full width + ComPtr datePickerAsFrameworkElement; + RETURN_IF_FAILED(datePicker.As(&datePickerAsFrameworkElement)); + RETURN_IF_FAILED(datePickerAsFrameworkElement->put_HorizontalAlignment(HorizontalAlignment_Stretch)); + RETURN_IF_FAILED(datePickerAsFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + + RETURN_IF_FAILED(datePicker.CopyTo(dateInputControl)); + + // Value + HString hstringValue; + RETURN_IF_FAILED(adaptiveDateInput->get_Value(hstringValue.GetAddressOf())); + std::string value = HStringToUTF8(hstringValue.Get()); + unsigned int year, month, day; + if (DateTimePreparser::TryParseSimpleDate(value, year, month, day)) + { + ComPtr> initialDateTimeReference; + RETURN_IF_FAILED(GetDateTimeReference(year, month, day, &initialDateTimeReference)); + RETURN_IF_FAILED(datePicker->put_Date(initialDateTimeReference.Get())); + } + + // Min date + HString hstringMin; + RETURN_IF_FAILED(adaptiveDateInput->get_Min(hstringMin.GetAddressOf())); + std::string min = HStringToUTF8(hstringMin.Get()); + DateTime minDate{}; + boolean isMinValid{DateTimePreparser::TryParseSimpleDate(min, year, month, day)}; + if (isMinValid) + { + minDate = GetDateTime(year, month, day); + RETURN_IF_FAILED(datePicker->put_MinDate(minDate)); + } + + // Max date + HString hstringMax; + RETURN_IF_FAILED(adaptiveDateInput->get_Max(hstringMax.GetAddressOf())); + std::string max = HStringToUTF8(hstringMax.Get()); + if (DateTimePreparser::TryParseSimpleDate(max, year, month, day)) + { + DateTime maxDate = GetDateTime(year, month, day); + if (isMinValid) + { + if (maxDate.UniversalTime > minDate.UniversalTime) + { + RETURN_IF_FAILED(datePicker->put_MaxDate(maxDate)); + } + else + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::InvalidValue, + HStringReference(L"Min value must be less than max in Input.Date").Get()); + } + } + else + { + RETURN_IF_FAILED(datePicker->put_MaxDate(maxDate)); + } + } + + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Input.Date", + datePickerAsFrameworkElement.Get())); + + XamlHelpers::AddInputValueToContext(renderContext, adaptiveCardElement, *dateInputControl); + return S_OK; } CATCH_RETURN; @@ -36,7 +121,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.h b/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.h index 1bfb83bf14..2acb9adc6f 100644 --- a/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveDateInputRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "DateInput.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveElementParserRegistration.cpp b/source/uwp/Renderer/lib/AdaptiveElementParserRegistration.cpp index 4c47592ef4..ebe5e35e17 100644 --- a/source/uwp/Renderer/lib/AdaptiveElementParserRegistration.cpp +++ b/source/uwp/Renderer/lib/AdaptiveElementParserRegistration.cpp @@ -35,7 +35,8 @@ namespace AdaptiveNamespace { AdaptiveElementParserRegistration::AdaptiveElementParserRegistration() {} - HRESULT AdaptiveElementParserRegistration::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveElementParserRegistration::RuntimeClassInitialize() noexcept + try { m_registration = std::make_shared(); m_sharedParserRegistration = std::make_shared(); @@ -52,7 +53,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveElementParserRegistration::Set(_In_ HSTRING type, _In_ IAdaptiveElementParser* Parser) noexcept try + HRESULT AdaptiveElementParserRegistration::Set(_In_ HSTRING type, _In_ IAdaptiveElementParser* Parser) noexcept + try { std::string typeString = HStringToUTF8(type); @@ -70,7 +72,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveElementParserRegistration::Get(_In_ HSTRING type, _COM_Outptr_ IAdaptiveElementParser** result) noexcept try + HRESULT AdaptiveElementParserRegistration::Get(_In_ HSTRING type, _COM_Outptr_ IAdaptiveElementParser** result) noexcept + try { *result = nullptr; @@ -83,7 +86,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveElementParserRegistration::Remove(_In_ HSTRING type) noexcept try + HRESULT AdaptiveElementParserRegistration::Remove(_In_ HSTRING type) noexcept + try { std::string typeString = HStringToUTF8(type); diff --git a/source/uwp/Renderer/lib/AdaptiveElementRendererRegistration.cpp b/source/uwp/Renderer/lib/AdaptiveElementRendererRegistration.cpp index 21d3cff158..a43e635108 100644 --- a/source/uwp/Renderer/lib/AdaptiveElementRendererRegistration.cpp +++ b/source/uwp/Renderer/lib/AdaptiveElementRendererRegistration.cpp @@ -12,7 +12,8 @@ namespace AdaptiveNamespace { AdaptiveElementRendererRegistration::AdaptiveElementRendererRegistration() {} - HRESULT AdaptiveElementRendererRegistration::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveElementRendererRegistration::RuntimeClassInitialize() noexcept + try { m_registration = std::make_shared(); return S_OK; diff --git a/source/uwp/Renderer/lib/AdaptiveFact.cpp b/source/uwp/Renderer/lib/AdaptiveFact.cpp index bd40fd3145..98e3530952 100644 --- a/source/uwp/Renderer/lib/AdaptiveFact.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFact.cpp @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveFact.h" -#include "Util.h" -#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -14,7 +13,8 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveFact::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFact::RuntimeClassInitialize() noexcept + try { RuntimeClassInitialize(std::make_shared()); return S_OK; @@ -47,7 +47,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveFact::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveFact::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr fact = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveFact.h b/source/uwp/Renderer/lib/AdaptiveFact.h index 6bc5ac3044..14d42aaec2 100644 --- a/source/uwp/Renderer/lib/AdaptiveFact.h +++ b/source/uwp/Renderer/lib/AdaptiveFact.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "Fact.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveFactSet.cpp b/source/uwp/Renderer/lib/AdaptiveFactSet.cpp index 96c3f86a43..b6c9579ffc 100644 --- a/source/uwp/Renderer/lib/AdaptiveFactSet.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFactSet.cpp @@ -18,14 +18,16 @@ namespace AdaptiveNamespace { AdaptiveFactSet::AdaptiveFactSet() { m_facts = Microsoft::WRL::Make>(); } - HRESULT AdaptiveFactSet::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFactSet::RuntimeClassInitialize() noexcept + try { std::shared_ptr factSet = std::make_shared(); return RuntimeClassInitialize(factSet); } CATCH_RETURN; - HRESULT AdaptiveFactSet::RuntimeClassInitialize(const std::shared_ptr& sharedFactSet) try + HRESULT AdaptiveFactSet::RuntimeClassInitialize(const std::shared_ptr& sharedFactSet) + try { if (sharedFactSet == nullptr) { @@ -50,7 +52,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveFactSet::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveFactSet::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr factSet = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveFactSet.h b/source/uwp/Renderer/lib/AdaptiveFactSet.h index 161a6e73d2..03206285cf 100644 --- a/source/uwp/Renderer/lib/AdaptiveFactSet.h +++ b/source/uwp/Renderer/lib/AdaptiveFactSet.h @@ -2,11 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "FactSet.h" -#include -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveFactSetConfig.cpp b/source/uwp/Renderer/lib/AdaptiveFactSetConfig.cpp index 8cf73f335a..e87ea8ce5e 100644 --- a/source/uwp/Renderer/lib/AdaptiveFactSetConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFactSetConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveFactSetConfig.h" #include "AdaptiveTextConfig.h" @@ -9,7 +10,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveFactSetConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFactSetConfig::RuntimeClassInitialize() noexcept + try { FactSetConfig factSetConfig; return RuntimeClassInitialize(factSetConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveFactSetConfig.h b/source/uwp/Renderer/lib/AdaptiveFactSetConfig.h index 34445bc049..1e23cd469f 100644 --- a/source/uwp/Renderer/lib/AdaptiveFactSetConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveFactSetConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveFactSetConfig diff --git a/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.cpp index 82991d0f6e..982837ed55 100644 --- a/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.cpp @@ -5,29 +5,156 @@ #include "AdaptiveElementParserRegistration.h" #include "AdaptiveFactSet.h" #include "AdaptiveFactSetRenderer.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" +#include "TextHelpers.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveFactSetRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFactSetRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveFactSetRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveFactSetRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** factSetControl) noexcept + try { - return XamlBuilder::BuildFactSet(cardElement, renderContext, renderArgs, result); + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveFactSet; + + RETURN_IF_FAILED(cardElement.As(&adaptiveFactSet)); + + ComPtr xamlGrid = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + ComPtr gridStatics; + RETURN_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid).Get(), &gridStatics)); + + ComPtr titleColumn = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + ComPtr valueColumn = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_ColumnDefinition)); + GridLength factSetGridTitleLength = {0, GridUnitType::GridUnitType_Auto}; + GridLength factSetGridValueLength = {1, GridUnitType::GridUnitType_Star}; + + RETURN_IF_FAILED(titleColumn->put_Width(factSetGridTitleLength)); + RETURN_IF_FAILED(valueColumn->put_Width(factSetGridValueLength)); + ComPtr> columnDefinitions; + RETURN_IF_FAILED(xamlGrid->get_ColumnDefinitions(&columnDefinitions)); + RETURN_IF_FAILED(columnDefinitions->Append(titleColumn.Get())); + RETURN_IF_FAILED(columnDefinitions->Append(valueColumn.Get())); + + GridLength factSetGridHeight = {0, GridUnitType::GridUnitType_Auto}; + ABI::AdaptiveNamespace::HeightType heightType; + RETURN_IF_FAILED(cardElement->get_Height(&heightType)); + if (heightType == ABI::AdaptiveNamespace::HeightType::Stretch) + { + factSetGridHeight = {1, GridUnitType::GridUnitType_Star}; + } + + ComPtr> facts; + RETURN_IF_FAILED(adaptiveFactSet->get_Facts(&facts)); + int currentFact = 0; + XamlHelpers::IterateOverVector( + facts.Get(), [xamlGrid, gridStatics, factSetGridHeight, ¤tFact, renderContext, renderArgs](IAdaptiveFact* fact) { + ComPtr factRow = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_RowDefinition)); + RETURN_IF_FAILED(factRow->put_Height(factSetGridHeight)); + + ComPtr> rowDefinitions; + RETURN_IF_FAILED(xamlGrid->get_RowDefinitions(&rowDefinitions)); + RETURN_IF_FAILED(rowDefinitions->Append(factRow.Get())); + + ComPtr localFact(fact); + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + ComPtr factSetConfig; + RETURN_IF_FAILED(hostConfig->get_FactSet(&factSetConfig)); + + // Get Language + HString language; + RETURN_IF_FAILED(localFact->get_Language(language.GetAddressOf())); + + // Create the title xaml textblock and style it from Host options + ComPtr titleTextConfig; + RETURN_IF_FAILED(factSetConfig->get_Title(&titleTextConfig)); + + ComPtr titleTextBlock = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock)); + + HString factTitle; + RETURN_IF_FAILED(localFact->get_Title(factTitle.GetAddressOf())); + + RETURN_IF_FAILED(SetXamlInlinesWithTextConfig( + renderContext, renderArgs, titleTextConfig.Get(), language.Get(), factTitle.Get(), titleTextBlock.Get())); + + // Create the value xaml textblock and style it from Host options + ComPtr valueTextConfig; + RETURN_IF_FAILED(factSetConfig->get_Value(&valueTextConfig)); + + ComPtr valueTextBlock = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock)); + + HString factValue; + RETURN_IF_FAILED(localFact->get_Value(factValue.GetAddressOf())); + + RETURN_IF_FAILED(SetXamlInlinesWithTextConfig( + renderContext, renderArgs, valueTextConfig.Get(), language.Get(), factValue.Get(), valueTextBlock.Get())); + + // Mark the column container with the current column + ComPtr titleTextBlockAsFrameWorkElement; + RETURN_IF_FAILED(titleTextBlock.As(&titleTextBlockAsFrameWorkElement)); + ComPtr valueTextBlockAsFrameWorkElement; + RETURN_IF_FAILED(valueTextBlock.As(&valueTextBlockAsFrameWorkElement)); + + UINT32 spacing; + RETURN_IF_FAILED(factSetConfig->get_Spacing(&spacing)); + // Add spacing from hostconfig to right margin of title. + titleTextBlockAsFrameWorkElement->put_Margin({0, 0, (double)spacing, 0}); + + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Fact.Title", + titleTextBlockAsFrameWorkElement.Get())); + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Fact.Value", + valueTextBlockAsFrameWorkElement.Get())); + + RETURN_IF_FAILED(gridStatics->SetColumn(titleTextBlockAsFrameWorkElement.Get(), 0)); + RETURN_IF_FAILED(gridStatics->SetRow(titleTextBlockAsFrameWorkElement.Get(), currentFact)); + + RETURN_IF_FAILED(gridStatics->SetColumn(valueTextBlockAsFrameWorkElement.Get(), 1)); + RETURN_IF_FAILED(gridStatics->SetRow(valueTextBlockAsFrameWorkElement.Get(), currentFact)); + + // Finally add the column container to the grid, and increment the column count + ComPtr gridAsPanel; + RETURN_IF_FAILED(xamlGrid.As(&gridAsPanel)); + ComPtr titleUIElement; + RETURN_IF_FAILED(titleTextBlockAsFrameWorkElement.As(&titleUIElement)); + ComPtr valueUIElement; + RETURN_IF_FAILED(valueTextBlockAsFrameWorkElement.As(&valueUIElement)); + + XamlHelpers::AppendXamlElementToPanel(titleUIElement.Get(), gridAsPanel.Get()); + XamlHelpers::AppendXamlElementToPanel(valueUIElement.Get(), gridAsPanel.Get()); + ++currentFact; + return S_OK; + }); + + ComPtr factSetAsFrameworkElement; + RETURN_IF_FAILED(xamlGrid.As(&factSetAsFrameworkElement)); + RETURN_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.FactSet", factSetAsFrameworkElement.Get())); + + return xamlGrid.CopyTo(factSetControl); } CATCH_RETURN; @@ -36,7 +163,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.h b/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.h index 04f5f64ad1..6927e32664 100644 --- a/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveFactSetRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "FactSet.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveFeatureRegistration.cpp b/source/uwp/Renderer/lib/AdaptiveFeatureRegistration.cpp index b2b7456cc7..9dd6b3b7ff 100644 --- a/source/uwp/Renderer/lib/AdaptiveFeatureRegistration.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFeatureRegistration.cpp @@ -12,28 +12,32 @@ namespace AdaptiveNamespace { AdaptiveFeatureRegistration::AdaptiveFeatureRegistration() {} - HRESULT AdaptiveFeatureRegistration::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFeatureRegistration::RuntimeClassInitialize() noexcept + try { std::shared_ptr sharedParserRegistration = std::make_shared(); return RuntimeClassInitialize(sharedParserRegistration); } CATCH_RETURN; - HRESULT AdaptiveFeatureRegistration::RuntimeClassInitialize(std::shared_ptr sharedParserRegistration) noexcept try + HRESULT AdaptiveFeatureRegistration::RuntimeClassInitialize(std::shared_ptr sharedParserRegistration) noexcept + try { m_sharedFeatureRegistration = sharedParserRegistration; return S_OK; } CATCH_RETURN; - HRESULT AdaptiveFeatureRegistration::Set(_In_ HSTRING name, _In_ HSTRING version) noexcept try + HRESULT AdaptiveFeatureRegistration::Set(_In_ HSTRING name, _In_ HSTRING version) noexcept + try { m_sharedFeatureRegistration->AddFeature(HStringToUTF8(name), HStringToUTF8(version)); return S_OK; } CATCH_RETURN; - HRESULT AdaptiveFeatureRegistration::Get(_In_ HSTRING name, _Outptr_ HSTRING* version) noexcept try + HRESULT AdaptiveFeatureRegistration::Get(_In_ HSTRING name, _Outptr_ HSTRING* version) noexcept + try { *version = nullptr; const std::string featureVersion = m_sharedFeatureRegistration->GetFeatureVersion(HStringToUTF8(name)); @@ -42,7 +46,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveFeatureRegistration::Remove(_In_ HSTRING name) noexcept try + HRESULT AdaptiveFeatureRegistration::Remove(_In_ HSTRING name) noexcept + try { m_sharedFeatureRegistration->RemoveFeature(HStringToUTF8(name)); diff --git a/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.cpp b/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.cpp index 9f9fd89545..bfc8640c9b 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveFontSizesConfig.h" using namespace Microsoft::WRL; @@ -8,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveFontSizesConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFontSizesConfig::RuntimeClassInitialize() noexcept + try { FontSizesConfig fontSizesConfig; return RuntimeClassInitialize(fontSizesConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.h b/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.h index e247879924..34ad2b6833 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveFontSizesConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveFontSizesConfig diff --git a/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.cpp b/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.cpp index aecaf16f19..2fbce011f4 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveFontTypeDefinition.h" #include "AdaptiveFontWeightsConfig.h" #include "AdaptiveFontSizesConfig.h" @@ -10,7 +11,8 @@ using namespace Microsoft::WRL::Wrappers; namespace AdaptiveNamespace { - HRESULT AdaptiveFontTypeDefinition::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFontTypeDefinition::RuntimeClassInitialize() noexcept + try { FontTypeDefinition typeDefinition; return RuntimeClassInitialize(typeDefinition); @@ -27,10 +29,7 @@ namespace AdaptiveNamespace HRESULT AdaptiveFontTypeDefinition::get_FontFamily(_Outptr_ HSTRING* value) { return m_fontFamily.CopyTo(value); } - HRESULT AdaptiveFontTypeDefinition::put_FontFamily(_In_ HSTRING fontFamily) - { - return m_fontFamily.Set(fontFamily); - } + HRESULT AdaptiveFontTypeDefinition::put_FontFamily(_In_ HSTRING fontFamily) { return m_fontFamily.Set(fontFamily); } HRESULT AdaptiveFontTypeDefinition::get_FontWeights(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveFontWeightsConfig** weightsConfig) { diff --git a/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.h b/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.h index 77bed7fd68..16be36b1c2 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.h +++ b/source/uwp/Renderer/lib/AdaptiveFontTypeDefinition.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveFontTypeDefinition diff --git a/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.cpp b/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.cpp index 937f860520..2b1a36c389 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveFontTypeDefinition.h" #include "AdaptiveFontTypesDefinition.h" @@ -9,7 +10,8 @@ using namespace Microsoft::WRL::Wrappers; namespace AdaptiveNamespace { - HRESULT AdaptiveFontTypesDefinition::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFontTypesDefinition::RuntimeClassInitialize() noexcept + try { FontTypesDefinition stylesDefinition; return RuntimeClassInitialize(stylesDefinition); diff --git a/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.h b/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.h index 80721cccf3..60ccbee1f1 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.h +++ b/source/uwp/Renderer/lib/AdaptiveFontTypesDefinition.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveFontTypesDefinition diff --git a/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.cpp b/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.cpp index beaa899b8b..57a6fa692d 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveFontWeightsConfig.h" using namespace Microsoft::WRL; @@ -8,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveFontWeightsConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveFontWeightsConfig::RuntimeClassInitialize() noexcept + try { FontWeightsConfig fontWeightsConfig; return RuntimeClassInitialize(fontWeightsConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.h b/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.h index cf8f4d771b..e1384d009e 100644 --- a/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveFontWeightsConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveFontWeightsConfig diff --git a/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.cpp b/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.cpp index 789bc47e42..41ef529c6f 100644 --- a/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "Util.h" + #include "AdaptiveHighlightColorConfig.h" using namespace Microsoft::WRL; @@ -10,7 +10,8 @@ using namespace ABI::Windows::UI; namespace AdaptiveNamespace { - HRESULT AdaptiveHighlightColorConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveHighlightColorConfig::RuntimeClassInitialize() noexcept + try { HighlightColorConfig colorConfig; return RuntimeClassInitialize(colorConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.h b/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.h index 3c50f9f5d3..097fff532d 100644 --- a/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveHighlightColorConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveHighlightColorConfig diff --git a/source/uwp/Renderer/lib/AdaptiveHostConfig.cpp b/source/uwp/Renderer/lib/AdaptiveHostConfig.cpp index e28ad4d53c..5996827955 100644 --- a/source/uwp/Renderer/lib/AdaptiveHostConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveHostConfig.cpp @@ -1,24 +1,24 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveHostConfig.h" -#include "Util.h" + #include "AdaptiveActionsConfig.h" #include "AdaptiveCardConfig.h" #include "AdaptiveColorsConfig.h" #include "AdaptiveContainerStylesDefinition.h" #include "AdaptiveFactSetConfig.h" #include "AdaptiveFontSizesConfig.h" -#include "AdaptiveFontWeightsConfig.h" #include "AdaptiveFontTypeDefinition.h" #include "AdaptiveFontTypesDefinition.h" +#include "AdaptiveFontWeightsConfig.h" +#include "AdaptiveHostConfig.h" #include "AdaptiveHostConfigParseResult.h" #include "AdaptiveImageConfig.h" #include "AdaptiveImageSetConfig.h" #include "AdaptiveImageSizesConfig.h" #include "AdaptiveMediaConfig.h" -#include "AdaptiveSpacingConfig.h" #include "AdaptiveSeparatorConfig.h" +#include "AdaptiveSpacingConfig.h" using namespace Microsoft::WRL; using namespace ABI::AdaptiveNamespace; @@ -27,7 +27,8 @@ using namespace ABI::Windows::Data::Json; namespace AdaptiveNamespace { HRESULT AdaptiveHostConfigStaticsImpl::FromJsonString(_In_ HSTRING adaptiveJson, - _COM_Outptr_ IAdaptiveHostConfigParseResult** parseResult) noexcept try + _COM_Outptr_ IAdaptiveHostConfigParseResult** parseResult) noexcept + try { *parseResult = nullptr; @@ -38,7 +39,8 @@ namespace AdaptiveNamespace CATCH_RETURN; HRESULT AdaptiveHostConfigStaticsImpl::FromJson(_In_ IJsonObject* adaptiveJson, - _COM_Outptr_ IAdaptiveHostConfigParseResult** parseResult) noexcept try + _COM_Outptr_ IAdaptiveHostConfigParseResult** parseResult) noexcept + try { *parseResult = nullptr; @@ -61,7 +63,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveHostConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveHostConfig::RuntimeClassInitialize() noexcept + try { HostConfig sharedHostConfig; return RuntimeClassInitialize(sharedHostConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveHostConfig.h b/source/uwp/Renderer/lib/AdaptiveHostConfig.h index e74b1f273f..aa673e5e13 100644 --- a/source/uwp/Renderer/lib/AdaptiveHostConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveHostConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveHostConfig diff --git a/source/uwp/Renderer/lib/AdaptiveImage.cpp b/source/uwp/Renderer/lib/AdaptiveImage.cpp index e57972248f..04523e2fda 100644 --- a/source/uwp/Renderer/lib/AdaptiveImage.cpp +++ b/source/uwp/Renderer/lib/AdaptiveImage.cpp @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveImage.h" -#include "Util.h" +#include "AdaptiveImage.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -16,14 +15,16 @@ namespace AdaptiveNamespace { AdaptiveImage::AdaptiveImage() {} - HRESULT AdaptiveImage::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveImage::RuntimeClassInitialize() noexcept + try { std::shared_ptr image = std::make_shared(); return RuntimeClassInitialize(image); } CATCH_RETURN; - HRESULT AdaptiveImage::RuntimeClassInitialize(const std::shared_ptr& sharedImage) try + HRESULT AdaptiveImage::RuntimeClassInitialize(const std::shared_ptr& sharedImage) + try { if (sharedImage == nullptr) { @@ -142,7 +143,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveImage::GetSharedModel(std::shared_ptr& sharedImage) try + HRESULT AdaptiveImage::GetSharedModel(std::shared_ptr& sharedImage) + try { std::shared_ptr image = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveImage.h b/source/uwp/Renderer/lib/AdaptiveImage.h index 254facfbd7..f8fa4422ba 100644 --- a/source/uwp/Renderer/lib/AdaptiveImage.h +++ b/source/uwp/Renderer/lib/AdaptiveImage.h @@ -2,11 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "Image.h" -#include -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveImageConfig.cpp b/source/uwp/Renderer/lib/AdaptiveImageConfig.cpp index f97dc83fd3..455436a151 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveImageConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveImageConfig.h" using namespace Microsoft::WRL; @@ -8,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveImageConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveImageConfig::RuntimeClassInitialize() noexcept + try { ImageConfig imageConfig; return RuntimeClassInitialize(imageConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveImageConfig.h b/source/uwp/Renderer/lib/AdaptiveImageConfig.h index c450cc1c10..98f71e6341 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveImageConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveImageConfig diff --git a/source/uwp/Renderer/lib/AdaptiveImageRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveImageRenderer.cpp index 066dbcbf96..da587e3452 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveImageRenderer.cpp @@ -2,26 +2,47 @@ // Licensed under the MIT License. #include "pch.h" +#include "AdaptiveImageRenderer.h" + +#include "ActionHelpers.h" #include "AdaptiveElementParserRegistration.h" #include "AdaptiveImage.h" -#include "AdaptiveImageRenderer.h" -#include "enums.h" -#include "Util.h" +#include "AdaptiveBase64Util.h" +#include "AdaptiveCardGetResourceStreamArgs.h" +#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; +using namespace ABI::Windows::Data::Json; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::Storage; +using namespace ABI::Windows::Storage::Streams; +using namespace ABI::Windows::UI; +using namespace ABI::Windows::UI::Text; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Data; +using namespace ABI::Windows::UI::Xaml::Documents; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Controls::Primitives; +using namespace ABI::Windows::UI::Xaml::Markup; +using namespace ABI::Windows::UI::Xaml::Media; +using namespace ABI::Windows::UI::Xaml::Media::Imaging; +using namespace ABI::Windows::UI::Xaml::Shapes; +using namespace ABI::Windows::UI::Xaml::Input; +using namespace ABI::Windows::UI::Xaml::Automation; +using namespace ABI::Windows::Web::Http; +using namespace ABI::Windows::Web::Http::Filters; namespace AdaptiveNamespace { AdaptiveImageRenderer::AdaptiveImageRenderer() {} - AdaptiveImageRenderer::AdaptiveImageRenderer(ComPtr xamlBuilder) : m_xamlBuilder(xamlBuilder) - { - } + AdaptiveImageRenderer::AdaptiveImageRenderer(ComPtr xamlBuilder) : m_xamlBuilder(xamlBuilder) {} - HRESULT AdaptiveImageRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveImageRenderer::RuntimeClassInitialize() noexcept + try { RETURN_IF_FAILED(MakeAndInitialize(&m_xamlBuilder)); return S_OK; @@ -31,7 +52,8 @@ namespace AdaptiveNamespace HRESULT AdaptiveImageRenderer::Render(_In_ IAdaptiveCardElement* cardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept + try { return m_xamlBuilder->BuildImage(cardElement, renderContext, renderArgs, result); } @@ -42,10 +64,702 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); } CATCH_RETURN; + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // IMPORTANT! Methods below here are actually XamlBuilder methods. They're defined here because they're only used + // by the AdaptiveImageRenderer. They exist on XamlBuilder because it's the only place we have that can track + // loading and lifetime for images. + // + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + HRESULT XamlBuilder::BuildImage(_In_ IAdaptiveCardElement* adaptiveCardElement, + _In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveRenderArgs* renderArgs, + _COM_Outptr_ IUIElement** imageControl) + { + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveImage; + RETURN_IF_FAILED(cardElement.As(&adaptiveImage)); + + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + HString url; + RETURN_IF_FAILED(adaptiveImage->get_Url(url.GetAddressOf())); + + ComPtr imageUrl; + GetUrlFromString(hostConfig.Get(), url.Get(), imageUrl.GetAddressOf()); + + if (imageUrl == nullptr) + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::AssetLoadFailed, + HStringReference(L"Image not found").Get()); + *imageControl = nullptr; + return S_OK; + } + + UINT32 pixelWidth = 0, pixelHeight = 0; + RETURN_IF_FAILED(adaptiveImage->get_PixelWidth(&pixelWidth)); + RETURN_IF_FAILED(adaptiveImage->get_PixelHeight(&pixelHeight)); + bool hasExplicitMeasurements = (pixelWidth || pixelHeight); + bool isAspectRatioNeeded = (pixelWidth && pixelHeight); + + // Get the image's size and style + ABI::AdaptiveNamespace::ImageSize size = ABI::AdaptiveNamespace::ImageSize::None; + if (!hasExplicitMeasurements) + { + RETURN_IF_FAILED(adaptiveImage->get_Size(&size)); + } + + if (size == ABI::AdaptiveNamespace::ImageSize::None && !hasExplicitMeasurements) + { + ComPtr imageConfig; + RETURN_IF_FAILED(hostConfig->get_Image(&imageConfig)); + RETURN_IF_FAILED(imageConfig->get_ImageSize(&size)); + } + + ABI::AdaptiveNamespace::ImageStyle imageStyle; + RETURN_IF_FAILED(adaptiveImage->get_Style(&imageStyle)); + ComPtr resourceResolvers; + RETURN_IF_FAILED(renderContext->get_ResourceResolvers(&resourceResolvers)); + + HString backgroundColor; + RETURN_IF_FAILED(adaptiveImage->get_BackgroundColor(backgroundColor.GetAddressOf())); + + boolean isVisible; + RETURN_IF_FAILED(adaptiveCardElement->get_IsVisible(&isVisible)); + + ComPtr frameworkElement; + if (imageStyle == ImageStyle_Person) + { + ComPtr ellipse = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Shapes_Ellipse)); + ComPtr backgroundEllipse = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Shapes_Ellipse)); + + Stretch imageStretch = (isAspectRatioNeeded) ? Stretch::Stretch_Fill : Stretch::Stretch_UniformToFill; + bool mustHideElement{true}; + + ComPtr parentElement; + RETURN_IF_FAILED(renderArgs->get_ParentElement(&parentElement)); + + ComPtr ellipseAsShape; + RETURN_IF_FAILED(ellipse.As(&ellipseAsShape)); + + SetImageOnUIElement(imageUrl.Get(), + ellipse.Get(), + resourceResolvers.Get(), + (size == ABI::AdaptiveNamespace::ImageSize_Auto), + parentElement.Get(), + ellipseAsShape.Get(), + isVisible, + &mustHideElement, + imageStretch); + + ComPtr backgroundEllipseAsShape; + RETURN_IF_FAILED(backgroundEllipse.As(&backgroundEllipseAsShape)); + + if (size == ABI::AdaptiveNamespace::ImageSize::None || size == ABI::AdaptiveNamespace::ImageSize::Stretch || + size == ABI::AdaptiveNamespace::ImageSize::Auto || hasExplicitMeasurements) + { + RETURN_IF_FAILED(ellipseAsShape->put_Stretch(imageStretch)); + RETURN_IF_FAILED(backgroundEllipseAsShape->put_Stretch(imageStretch)); + } + else + { + // Set the stretch for the ellipse - this is different to the stretch used for the image brush + // above. This will force the ellipse to conform to fit within the confines of its parent. + Stretch ellipseStretch = Stretch::Stretch_UniformToFill; + RETURN_IF_FAILED(ellipseAsShape->put_Stretch(ellipseStretch)); + RETURN_IF_FAILED(backgroundEllipseAsShape->put_Stretch(ellipseStretch)); + } + + if (backgroundColor.Get() != nullptr) + { + // Fill the background ellipse with solid color brush + ABI::Windows::UI::Color color; + RETURN_IF_FAILED(GetColorFromString(HStringToUTF8(backgroundColor.Get()), &color)); + ComPtr backgroundColorBrush = XamlHelpers::GetSolidColorBrush(color); + RETURN_IF_FAILED(backgroundEllipseAsShape->put_Fill(backgroundColorBrush.Get())); + + // Create a grid to contain the background color ellipse and the image ellipse + ComPtr imageGrid = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Grid)); + + ComPtr panel; + RETURN_IF_FAILED(imageGrid.As(&panel)); + + XamlHelpers::AppendXamlElementToPanel(backgroundEllipse.Get(), panel.Get()); + XamlHelpers::AppendXamlElementToPanel(ellipse.Get(), panel.Get()); + + RETURN_IF_FAILED(imageGrid.As(&frameworkElement)); + } + else + { + RETURN_IF_FAILED(ellipse.As(&frameworkElement)); + } + } + else + { + ComPtr xamlImage = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Image)); + + if (backgroundColor != nullptr) + { + // Create a surrounding border with solid color background to contain the image + ComPtr border = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_Border)); + + ABI::Windows::UI::Color color; + RETURN_IF_FAILED(GetColorFromString(HStringToUTF8(backgroundColor.Get()), &color)); + ComPtr backgroundColorBrush = XamlHelpers::GetSolidColorBrush(color); + RETURN_IF_FAILED(border->put_Background(backgroundColorBrush.Get())); + + ComPtr imageAsUiElement; + RETURN_IF_FAILED(xamlImage.CopyTo(imageAsUiElement.GetAddressOf())); + RETURN_IF_FAILED(border->put_Child(imageAsUiElement.Get())); + + RETURN_IF_FAILED(border.As(&frameworkElement)); + } + else + { + RETURN_IF_FAILED(xamlImage.As(&frameworkElement)); + } + + if (isAspectRatioNeeded) + { + xamlImage->put_Stretch(Stretch::Stretch_Fill); + } + + ComPtr parentElement; + RETURN_IF_FAILED(renderArgs->get_ParentElement(&parentElement)); + + bool mustHideElement{true}; + SetImageOnUIElement(imageUrl.Get(), + xamlImage.Get(), + resourceResolvers.Get(), + (size == ABI::AdaptiveNamespace::ImageSize_Auto), + parentElement.Get(), + frameworkElement.Get(), + isVisible, + &mustHideElement); + } + + ComPtr sizeOptions; + RETURN_IF_FAILED(hostConfig->get_ImageSizes(sizeOptions.GetAddressOf())); + + if (hasExplicitMeasurements) + { + if (pixelWidth) + { + if (imageStyle == ImageStyle_Person) + { + RETURN_IF_FAILED(frameworkElement->put_Width(pixelWidth)); + } + else + { + RETURN_IF_FAILED(frameworkElement->put_MaxWidth(pixelWidth)); + } + } + + if (pixelHeight) + { + if (imageStyle == ImageStyle_Person) + { + RETURN_IF_FAILED(frameworkElement->put_Height(pixelHeight)); + } + else + { + RETURN_IF_FAILED(frameworkElement->put_MaxHeight(pixelHeight)); + } + } + } + else + { + if (size == ABI::AdaptiveNamespace::ImageSize::Small || size == ABI::AdaptiveNamespace::ImageSize::Medium || + size == ABI::AdaptiveNamespace::ImageSize::Large) + { + UINT32 imageSize; + switch (size) + { + case ABI::AdaptiveNamespace::ImageSize::Small: + { + RETURN_IF_FAILED(sizeOptions->get_Small(&imageSize)); + break; + } + + case ABI::AdaptiveNamespace::ImageSize::Medium: + { + RETURN_IF_FAILED(sizeOptions->get_Medium(&imageSize)); + break; + } + + case ABI::AdaptiveNamespace::ImageSize::Large: + { + RETURN_IF_FAILED(sizeOptions->get_Large(&imageSize)); + + break; + } + default: + { + return E_UNEXPECTED; + } + } + + RETURN_IF_FAILED(frameworkElement->put_MaxWidth(imageSize)); + + // We don't want to set a max height on the person ellipse as ellipses do not understand preserving + // aspect ratio when constrained on both axes. + if (imageStyle != ImageStyle_Person) + { + RETURN_IF_FAILED(frameworkElement->put_MaxHeight(imageSize)); + } + } + } + + ABI::AdaptiveNamespace::HAlignment adaptiveHorizontalAlignment; + RETURN_IF_FAILED(adaptiveImage->get_HorizontalAlignment(&adaptiveHorizontalAlignment)); + + switch (adaptiveHorizontalAlignment) + { + case ABI::AdaptiveNamespace::HAlignment::Left: + RETURN_IF_FAILED(frameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Left)); + break; + case ABI::AdaptiveNamespace::HAlignment::Right: + RETURN_IF_FAILED(frameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Right)); + break; + case ABI::AdaptiveNamespace::HAlignment::Center: + RETURN_IF_FAILED(frameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Center)); + break; + } + + RETURN_IF_FAILED(frameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.Image", frameworkElement.Get())); + + ComPtr selectAction; + RETURN_IF_FAILED(adaptiveImage->get_SelectAction(&selectAction)); + + ComPtr imageAsUIElement; + RETURN_IF_FAILED(frameworkElement.As(&imageAsUIElement)); + + HString altText; + RETURN_IF_FAILED(adaptiveImage->get_AltText(altText.GetAddressOf())); + + ComPtr imageAsDependencyObject; + RETURN_IF_FAILED(imageAsUIElement.As(&imageAsDependencyObject)); + + ComPtr automationPropertiesStatics; + RETURN_IF_FAILED( + GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_Xaml_Automation_AutomationProperties).Get(), + &automationPropertiesStatics)); + + RETURN_IF_FAILED(automationPropertiesStatics->SetName(imageAsDependencyObject.Get(), altText.Get())); + + ActionHelpers::HandleSelectAction(adaptiveCardElement, + selectAction.Get(), + renderContext, + imageAsUIElement.Get(), + XamlHelpers::SupportsInteractivity(hostConfig.Get()), + true, + imageControl); + + return S_OK; + } + + template + void XamlBuilder::SetImageOnUIElement(_In_ ABI::Windows::Foundation::IUriRuntimeClass* imageUrl, + _In_ T* uiElement, + _In_opt_ IAdaptiveCardResourceResolvers* resolvers, + bool isAutoSize, + IInspectable* parentElement, + IInspectable* imageContainer, + bool isVisible, + _Out_ bool* mustHideElement, + ABI::Windows::UI::Xaml::Media::Stretch stretch) + { + *mustHideElement = true; + + // Get the image url scheme + HString schemeName; + THROW_IF_FAILED(imageUrl->get_SchemeName(schemeName.GetAddressOf())); + + // Get the resolver for the image + ComPtr resolver; + if (resolvers != nullptr) + { + THROW_IF_FAILED(resolvers->Get(schemeName.Get(), &resolver)); + // If we have a resolver + if (resolver != nullptr) + { + // Create a BitmapImage to hold the image data. We use BitmapImage in order to allow + // the tracker to subscribe to the ImageLoaded/Failed events + ComPtr bitmapImage = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Media_Imaging_BitmapImage)); + + if (!m_enableXamlImageHandling && (m_listeners.size() != 0)) + { + m_imageLoadTracker.TrackBitmapImage(bitmapImage.Get()); + } + + THROW_IF_FAILED(bitmapImage->put_CreateOptions(BitmapCreateOptions::BitmapCreateOptions_None)); + ComPtr bitmapSource; + bitmapImage.As(&bitmapSource); + + // Create the arguments to pass to the resolver + ComPtr args; + THROW_IF_FAILED(MakeAndInitialize(&args, imageUrl)); + + // And call the resolver to get the image stream + ComPtr> getResourceStreamOperation; + THROW_IF_FAILED(resolver->GetResourceStreamAsync(args.Get(), &getResourceStreamOperation)); + + ComPtr strongImageControl(uiElement); + ComPtr strongThis(this); + THROW_IF_FAILED(getResourceStreamOperation->put_Completed( + Callback, IAsyncOperationCompletedHandler>>( + [strongThis, this, bitmapSource, strongImageControl, bitmapImage, stretch, isAutoSize, parentElement, imageContainer, isVisible]( + IAsyncOperation* operation, AsyncStatus status) -> HRESULT { + if (status == AsyncStatus::Completed) + { + // Get the random access stream + ComPtr randomAccessStream; + RETURN_IF_FAILED(operation->GetResults(&randomAccessStream)); + + if (randomAccessStream == nullptr) + { + m_imageLoadTracker.MarkFailedLoadBitmapImage(bitmapImage.Get()); + return S_OK; + } + + RETURN_IF_FAILED(bitmapSource->SetSource(randomAccessStream.Get())); + + ComPtr imageSource; + RETURN_IF_FAILED(bitmapSource.As(&imageSource)); + + SetImageSource(strongImageControl.Get(), imageSource.Get(), stretch); + + // Here should be the auto resizing, at this time we already have the image and everything set + if (isAutoSize) + { + SetAutoSize(strongImageControl.Get(), parentElement, imageContainer, isVisible, false /* imageFiresOpenEvent */); + } + + return S_OK; + } + else + { + m_imageLoadTracker.MarkFailedLoadBitmapImage(bitmapImage.Get()); + return S_OK; + } + }) + .Get())); + + return; + } + } + + INT32 isDataUriImage{}; + THROW_IF_FAILED(WindowsCompareStringOrdinal(schemeName.Get(), HStringReference(L"data").Get(), &isDataUriImage)); + if (isDataUriImage == 0) + { + // Decode base 64 string + HString dataPath; + THROW_IF_FAILED(imageUrl->get_Path(dataPath.GetAddressOf())); + + std::string data = AdaptiveBase64Util::ExtractDataFromUri(HStringToUTF8(dataPath.Get())); + std::vector decodedData = AdaptiveBase64Util::Decode(data); + + ComPtr bufferFactory; + THROW_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + bufferFactory.GetAddressOf())); + + ComPtr buffer; + THROW_IF_FAILED(bufferFactory->Create(static_cast(decodedData.size()), buffer.GetAddressOf())); + + ComPtr<::Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess; + THROW_IF_FAILED(buffer.As(&bufferByteAccess)); + + BYTE* dataInternal{}; + THROW_IF_FAILED(bufferByteAccess->Buffer(&dataInternal)); + + memcpy_s(dataInternal, decodedData.size(), decodedData.data(), decodedData.size()); + + THROW_IF_FAILED(buffer->put_Length(static_cast(decodedData.size()))); + + ComPtr bitmapImage = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Media_Imaging_BitmapImage)); + m_imageLoadTracker.TrackBitmapImage(bitmapImage.Get()); + THROW_IF_FAILED(bitmapImage->put_CreateOptions(BitmapCreateOptions::BitmapCreateOptions_IgnoreImageCache)); + ComPtr bitmapSource; + THROW_IF_FAILED(bitmapImage.As(&bitmapSource)); + + ComPtr randomAccessStream = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream)); + + ComPtr outputStream; + THROW_IF_FAILED(randomAccessStream.As(&outputStream)); + + ComPtr> bufferWriteOperation; + THROW_IF_FAILED(outputStream->WriteAsync(buffer.Get(), &bufferWriteOperation)); + + ComPtr strongImageControl(uiElement); + ComPtr strongThis(this); + THROW_IF_FAILED(bufferWriteOperation->put_Completed( + Callback, IAsyncOperationWithProgressCompletedHandler>>( + [strongThis, this, bitmapSource, randomAccessStream, strongImageControl, isAutoSize, parentElement, imageContainer, isVisible]( + IAsyncOperationWithProgress* /*operation*/, AsyncStatus /*status*/) -> HRESULT { + randomAccessStream->Seek(0); + RETURN_IF_FAILED(bitmapSource->SetSource(randomAccessStream.Get())); + + ComPtr imageSource; + RETURN_IF_FAILED(bitmapSource.As(&imageSource)); + + SetImageSource(strongImageControl.Get(), imageSource.Get()); + + if (isAutoSize) + { + SetAutoSize(strongImageControl.Get(), parentElement, imageContainer, isVisible, false /* imageFiresOpenEvent */); + } + + return S_OK; + }) + .Get())); + + m_writeAsyncOperations.push_back(bufferWriteOperation); + *mustHideElement = false; + return; + } + + // Otherwise, no resolver... + if ((m_enableXamlImageHandling) || (m_listeners.size() == 0)) + { + // If we've been explicitly told to let Xaml handle the image loading, or there are + // no listeners waiting on the image load callbacks, use Xaml to load the images + ComPtr bitmapImage = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Media_Imaging_BitmapImage)); + THROW_IF_FAILED(bitmapImage->put_UriSource(imageUrl)); + + ComPtr bitmapImageSource; + THROW_IF_FAILED(bitmapImage.As(&bitmapImageSource)); + SetImageSource(uiElement, bitmapImageSource.Get(), stretch); + + if (isAutoSize) + { + SetAutoSize(uiElement, parentElement, imageContainer, isVisible, true /* imageFiresOpenEvent */); + } + } + else + { + PopulateImageFromUrlAsync(imageUrl, uiElement); + } + } + + template + void XamlBuilder::PopulateImageFromUrlAsync(_In_ IUriRuntimeClass* imageUrl, _In_ T* imageControl) + { + // Create the HttpClient to load the image stream + ComPtr httpBaseProtocolFilter = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_Web_Http_Filters_HttpBaseProtocolFilter)); + THROW_IF_FAILED(httpBaseProtocolFilter->put_AllowUI(false)); + ComPtr httpFilter; + THROW_IF_FAILED(httpBaseProtocolFilter.As(&httpFilter)); + ComPtr httpClient; + ComPtr httpClientFactory; + THROW_IF_FAILED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Web_Http_HttpClient).Get(), + httpClientFactory.ReleaseAndGetAddressOf())); + THROW_IF_FAILED(httpClientFactory->Create(httpFilter.Get(), httpClient.ReleaseAndGetAddressOf())); + + // Create a BitmapImage to hold the image data. We use BitmapImage in order to allow + // the tracker to subscribe to the ImageLoaded/Failed events + ComPtr bitmapImage = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Media_Imaging_BitmapImage)); + m_imageLoadTracker.TrackBitmapImage(bitmapImage.Get()); + THROW_IF_FAILED(bitmapImage->put_CreateOptions(BitmapCreateOptions::BitmapCreateOptions_None)); + ComPtr bitmapSource; + bitmapImage.As(&bitmapSource); + ComPtr> getStreamOperation; + THROW_IF_FAILED(httpClient->GetInputStreamAsync(imageUrl, &getStreamOperation)); + + ComPtr strongImageControl(imageControl); + ComPtr strongThis(this); + THROW_IF_FAILED(getStreamOperation->put_Completed( + Callback, IAsyncOperationWithProgressCompletedHandler>>( + [strongThis, this, bitmapSource, strongImageControl, bitmapImage]( + IAsyncOperationWithProgress* operation, AsyncStatus status) -> HRESULT { + if (status == AsyncStatus::Completed) + { + // Load the image stream into an in memory random access stream, which is what + // SetSource needs + ComPtr imageStream; + RETURN_IF_FAILED(operation->GetResults(&imageStream)); + ComPtr randomAccessStream = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream)); + ComPtr outputStream; + RETURN_IF_FAILED(randomAccessStream.As(&outputStream)); + ComPtr> copyStreamOperation; + RETURN_IF_FAILED(m_randomAccessStreamStatics->CopyAsync(imageStream.Get(), outputStream.Get(), ©StreamOperation)); + + m_copyStreamOperations.push_back(copyStreamOperation); + return copyStreamOperation->put_Completed( + Callback, IAsyncOperationWithProgressCompletedHandler>>( + [strongThis, this, bitmapSource, randomAccessStream, strongImageControl]( + IAsyncOperationWithProgress* /*operation*/, AsyncStatus /*status*/) -> HRESULT { + randomAccessStream->Seek(0); + RETURN_IF_FAILED(bitmapSource->SetSource(randomAccessStream.Get())); + + ComPtr imageSource; + RETURN_IF_FAILED(bitmapSource.As(&imageSource)); + + SetImageSource(strongImageControl.Get(), imageSource.Get()); + return S_OK; + }) + .Get()); + } + else + { + m_imageLoadTracker.MarkFailedLoadBitmapImage(bitmapImage.Get()); + return S_OK; + } + }) + .Get())); + m_getStreamOperations.push_back(getStreamOperation); + } + + template + void XamlBuilder::SetImageSource(_In_ T* destination, _In_ IImageSource* imageSource, ABI::Windows::UI::Xaml::Media::Stretch /*stretch*/) + { + THROW_IF_FAILED(destination->put_Source(imageSource)); + }; + + template<> + void XamlBuilder::SetImageSource(_In_ IEllipse* destination, + _In_ IImageSource* imageSource, + ABI::Windows::UI::Xaml::Media::Stretch stretch) + { + ComPtr imageBrush = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Media_ImageBrush)); + THROW_IF_FAILED(imageBrush->put_ImageSource(imageSource)); + + ComPtr tileBrush; + THROW_IF_FAILED(imageBrush.As(&tileBrush)); + THROW_IF_FAILED(tileBrush->put_Stretch(stretch)); + + ComPtr brush; + THROW_IF_FAILED(imageBrush.As(&brush)); + + ComPtr ellipseAsShape; + ComPtr ellipse(destination); + THROW_IF_FAILED(ellipse.As(&ellipseAsShape)); + + THROW_IF_FAILED(ellipseAsShape->put_Fill(brush.Get())); + }; + + template<> + void XamlBuilder::SetAutoSize(IEllipse* destination, IInspectable* parentElement, IInspectable* imageContainer, bool isVisible, bool imageFiresOpenEvent) + { + // Check if the image source fits in the parent container, if so, set the framework element's size to match the original image. + if (parentElement != nullptr && m_enableXamlImageHandling) + { + ComPtr ellipseShape(imageContainer); + ComPtr ellipseAsShape; + THROW_IF_FAILED(ellipseShape.As(&ellipseAsShape)); + + ComPtr ellipseBrush; + THROW_IF_FAILED(ellipseAsShape->get_Fill(&ellipseBrush)); + ComPtr brushAsImageBrush; + THROW_IF_FAILED(ellipseBrush.As(&brushAsImageBrush)); + + ComPtr ellipse(destination); + + ComPtr ellipseAsUIElement; + THROW_IF_FAILED(ellipse.As(&ellipseAsUIElement)); + + ComPtr ellipseAsFrameworkElement; + THROW_IF_FAILED(ellipse.As(&ellipseAsFrameworkElement)); + + ComPtr imageSource; + THROW_IF_FAILED(brushAsImageBrush->get_ImageSource(&imageSource)); + ComPtr imageSourceAsBitmap; + THROW_IF_FAILED(imageSource.As(&imageSourceAsBitmap)); + + // If the image hasn't loaded yet + if (imageFiresOpenEvent) + { + // Collapse the Ellipse while the image loads, so that resizing is not noticeable + THROW_IF_FAILED(ellipseAsUIElement->put_Visibility(Visibility::Visibility_Collapsed)); + // Handle ImageOpened event so we can check the imageSource's size to determine if it fits in its parent + EventRegistrationToken eventToken; + ComPtr strongParentElement(parentElement); + THROW_IF_FAILED(brushAsImageBrush->add_ImageOpened( + Callback([ellipseAsUIElement, ellipseAsFrameworkElement, imageSourceAsBitmap, strongParentElement, isVisible]( + IInspectable* /*sender*/, IRoutedEventArgs * /*args*/) -> HRESULT { + if (isVisible) + { + RETURN_IF_FAILED(ellipseAsUIElement->put_Visibility(Visibility::Visibility_Visible)); + RETURN_IF_FAILED(XamlHelpers::SetAutoImageSize(ellipseAsFrameworkElement.Get(), + strongParentElement.Get(), + imageSourceAsBitmap.Get(), + isVisible)); + } + return S_OK; + }).Get(), + &eventToken)); + } + else + { + XamlHelpers::SetAutoImageSize(ellipseAsFrameworkElement.Get(), parentElement, imageSourceAsBitmap.Get(), isVisible); + } + } + } + + template + void XamlBuilder::SetAutoSize(T* destination, IInspectable* parentElement, IInspectable* /* imageContainer */, bool isVisible, bool imageFiresOpenEvent) + { + if (parentElement != nullptr && m_enableXamlImageHandling) + { + ComPtr xamlImage(destination); + ComPtr imageAsFrameworkElement; + THROW_IF_FAILED(xamlImage.As(&imageAsFrameworkElement)); + ComPtr imageSource; + THROW_IF_FAILED(xamlImage->get_Source(&imageSource)); + ComPtr imageSourceAsBitmap; + THROW_IF_FAILED(imageSource.As(&imageSourceAsBitmap)); + + ComPtr imageAsUIElement; + THROW_IF_FAILED(xamlImage.As(&imageAsUIElement)); + + // If the image hasn't loaded yet + if (imageFiresOpenEvent) + { + // Collapse the Image control while the image loads, so that resizing is not noticeable + THROW_IF_FAILED(imageAsUIElement->put_Visibility(Visibility::Visibility_Collapsed)); + + // Handle ImageOpened event so we can check the imageSource's size to determine if it fits in its parent + ComPtr strongParentElement(parentElement); + EventRegistrationToken eventToken; + THROW_IF_FAILED(xamlImage->add_ImageOpened( + Callback([imageAsFrameworkElement, strongParentElement, imageSourceAsBitmap, isVisible]( + IInspectable* /*sender*/, IRoutedEventArgs * + /*args*/) -> HRESULT { + return XamlHelpers::SetAutoImageSize(imageAsFrameworkElement.Get(), + strongParentElement.Get(), + imageSourceAsBitmap.Get(), + isVisible); + }).Get(), + &eventToken)); + } + else + { + XamlHelpers::SetAutoImageSize(imageAsFrameworkElement.Get(), parentElement, imageSourceAsBitmap.Get(), isVisible); + } + } + } } diff --git a/source/uwp/Renderer/lib/AdaptiveImageRenderer.h b/source/uwp/Renderer/lib/AdaptiveImageRenderer.h index e2f16dc7cc..f8219fb773 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveImageRenderer.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "Image.h" -#include "XamlBuilder.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveImageSet.cpp b/source/uwp/Renderer/lib/AdaptiveImageSet.cpp index 5b83274408..750edc7061 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSet.cpp +++ b/source/uwp/Renderer/lib/AdaptiveImageSet.cpp @@ -1,11 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveImageSet.h" -#include "Util.h" -#include "Vector.h" -#include +#include "AdaptiveImageSet.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -18,14 +15,16 @@ namespace AdaptiveNamespace { AdaptiveImageSet::AdaptiveImageSet() { m_images = Microsoft::WRL::Make>(); } - HRESULT AdaptiveImageSet::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveImageSet::RuntimeClassInitialize() noexcept + try { std::shared_ptr imageSet = std::make_shared(); return RuntimeClassInitialize(imageSet); } CATCH_RETURN; - HRESULT AdaptiveImageSet::RuntimeClassInitialize(const std::shared_ptr& sharedImageSet) try + HRESULT AdaptiveImageSet::RuntimeClassInitialize(const std::shared_ptr& sharedImageSet) + try { if (sharedImageSet == nullptr) { @@ -64,7 +63,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveImageSet::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveImageSet::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr imageSet = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveImageSet.h b/source/uwp/Renderer/lib/AdaptiveImageSet.h index f59618c5dc..224dffb8f6 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSet.h +++ b/source/uwp/Renderer/lib/AdaptiveImageSet.h @@ -2,11 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ImageSet.h" -#include -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveImageSetConfig.cpp b/source/uwp/Renderer/lib/AdaptiveImageSetConfig.cpp index 51ddb1b7c0..4f12a80b71 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSetConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveImageSetConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveImageSetConfig.h" using namespace Microsoft::WRL; @@ -8,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveImageSetConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveImageSetConfig::RuntimeClassInitialize() noexcept + try { ImageSetConfig imageSetConfig; return RuntimeClassInitialize(imageSetConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveImageSetConfig.h b/source/uwp/Renderer/lib/AdaptiveImageSetConfig.h index 86e4cc7fce..708e3d8d17 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSetConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveImageSetConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveImageSetConfig diff --git a/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.cpp index 3287b33269..340dcc13c2 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.cpp @@ -5,29 +5,107 @@ #include "AdaptiveElementParserRegistration.h" #include "AdaptiveImageSet.h" #include "AdaptiveImageSetRenderer.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" +#include "AdaptiveRenderArgs.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveImageSetRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveImageSetRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveImageSetRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveImageSetRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** imageSetControl) noexcept + try { - return XamlBuilder::BuildImageSet(cardElement, renderContext, renderArgs, result); + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveImageSet; + RETURN_IF_FAILED(cardElement.As(&adaptiveImageSet)); + + ComPtr xamlGrid = XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_VariableSizedWrapGrid)); + + RETURN_IF_FAILED(xamlGrid->put_Orientation(Orientation_Horizontal)); + + ComPtr> images; + RETURN_IF_FAILED(adaptiveImageSet->get_Images(&images)); + + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + ComPtr imageSetConfig; + RETURN_IF_FAILED(hostConfig->get_ImageSet(&imageSetConfig)); + + ABI::AdaptiveNamespace::ImageSize imageSize; + RETURN_IF_FAILED(adaptiveImageSet->get_ImageSize(&imageSize)); + + if (imageSize == ABI::AdaptiveNamespace::ImageSize::None) + { + RETURN_IF_FAILED(imageSetConfig->get_ImageSize(&imageSize)); + } + + ComPtr elementRenderers; + RETURN_IF_FAILED(renderContext->get_ElementRenderers(&elementRenderers)); + ComPtr imageRenderer; + RETURN_IF_FAILED(elementRenderers->Get(HStringReference(L"Image").Get(), &imageRenderer)); + if (imageRenderer != nullptr) + { + ABI::AdaptiveNamespace::ContainerStyle containerStyle; + RETURN_IF_FAILED(renderArgs->get_ContainerStyle(&containerStyle)); + + ComPtr childRenderArgs; + RETURN_IF_FAILED(MakeAndInitialize(&childRenderArgs, containerStyle, xamlGrid.Get(), renderArgs)); + + XamlHelpers::IterateOverVector( + images.Get(), + [imageSize, xamlGrid, renderContext, childRenderArgs, imageRenderer, imageSetConfig](IAdaptiveImage* adaptiveImage) { + ComPtr uiImage; + ComPtr localAdaptiveImage(adaptiveImage); + RETURN_IF_FAILED(localAdaptiveImage->put_Size(imageSize)); + + ComPtr adaptiveElementImage; + RETURN_IF_FAILED(localAdaptiveImage.As(&adaptiveElementImage)); + RETURN_IF_FAILED(imageRenderer->Render(adaptiveElementImage.Get(), renderContext, childRenderArgs.Get(), &uiImage)); + + ComPtr imageAsFrameworkElement; + RETURN_IF_FAILED(uiImage.As(&imageAsFrameworkElement)); + + UINT32 maxImageHeight; + RETURN_IF_FAILED(imageSetConfig->get_MaxImageHeight(&maxImageHeight)); + RETURN_IF_FAILED(imageAsFrameworkElement->put_MaxHeight(maxImageHeight)); + + ComPtr gridAsPanel; + RETURN_IF_FAILED(xamlGrid.As(&gridAsPanel)); + + XamlHelpers::AppendXamlElementToPanel(uiImage.Get(), gridAsPanel.Get()); + return S_OK; + }); + } + else + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::NoRendererForType, + HStringReference(L"No renderer found for type: Image").Get()); + *imageSetControl = nullptr; + return S_OK; + } + + ComPtr imageSetAsFrameworkElement; + RETURN_IF_FAILED(xamlGrid.As(&imageSetAsFrameworkElement)); + RETURN_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.ImageSet", imageSetAsFrameworkElement.Get())); + + return xamlGrid.CopyTo(imageSetControl); } CATCH_RETURN; @@ -36,7 +114,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.h b/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.h index be46fd96e3..61c10aee56 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveImageSetRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ImageSet.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.cpp b/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.cpp index 6185875f15..a89347f875 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveImageSizesConfig.h" using namespace Microsoft::WRL; @@ -8,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveImageSizesConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveImageSizesConfig::RuntimeClassInitialize() noexcept + try { ImageSizesConfig imageSizesConfig; return RuntimeClassInitialize(imageSizesConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.h b/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.h index 82d5c747d3..39be92dbc6 100644 --- a/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveImageSizesConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveImageSizesConfig diff --git a/source/uwp/Renderer/lib/AdaptiveInputElement.cpp b/source/uwp/Renderer/lib/AdaptiveInputElement.cpp index a2c7f9d19e..f01fc4eec8 100644 --- a/source/uwp/Renderer/lib/AdaptiveInputElement.cpp +++ b/source/uwp/Renderer/lib/AdaptiveInputElement.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveInputElement.h" using namespace Microsoft::WRL; diff --git a/source/uwp/Renderer/lib/AdaptiveInputElement.h b/source/uwp/Renderer/lib/AdaptiveInputElement.h index 35eea6bf92..674d687cca 100644 --- a/source/uwp/Renderer/lib/AdaptiveInputElement.h +++ b/source/uwp/Renderer/lib/AdaptiveInputElement.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "BaseInputElement.h" -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveMedia.cpp b/source/uwp/Renderer/lib/AdaptiveMedia.cpp index 37cce06cde..5f7037bc37 100644 --- a/source/uwp/Renderer/lib/AdaptiveMedia.cpp +++ b/source/uwp/Renderer/lib/AdaptiveMedia.cpp @@ -9,14 +9,16 @@ using namespace ABI::Windows::Foundation::Collections; namespace AdaptiveNamespace { - HRESULT AdaptiveMedia::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveMedia::RuntimeClassInitialize() noexcept + try { std::shared_ptr media = std::make_shared(); return RuntimeClassInitialize(media); } CATCH_RETURN; - HRESULT AdaptiveMedia::RuntimeClassInitialize(const std::shared_ptr& sharedMedia) try + HRESULT AdaptiveMedia::RuntimeClassInitialize(const std::shared_ptr& sharedMedia) + try { if (sharedMedia == nullptr) { @@ -53,7 +55,8 @@ namespace AdaptiveNamespace return m_sources.CopyTo(sources); } - HRESULT AdaptiveMedia::GetSharedModel(std::shared_ptr& sharedMedia) try + HRESULT AdaptiveMedia::GetSharedModel(std::shared_ptr& sharedMedia) + try { std::shared_ptr media = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveMedia.h b/source/uwp/Renderer/lib/AdaptiveMedia.h index e93addbd5f..0d19e114df 100644 --- a/source/uwp/Renderer/lib/AdaptiveMedia.h +++ b/source/uwp/Renderer/lib/AdaptiveMedia.h @@ -58,10 +58,22 @@ namespace AdaptiveNamespace IFACEMETHODIMP get_Id(_Outptr_ HSTRING* id) { return AdaptiveCardElementBase::get_Id(id); } IFACEMETHODIMP put_Id(_In_ HSTRING id) { return AdaptiveCardElementBase::put_Id(id); } - IFACEMETHODIMP get_FallbackType(_Out_ ABI::AdaptiveNamespace::FallbackType * fallback) { return AdaptiveCardElementBase::get_FallbackType(fallback); } - IFACEMETHODIMP get_FallbackContent(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement ** content) { return AdaptiveCardElementBase::get_FallbackContent(content); } - IFACEMETHODIMP put_FallbackType(ABI::AdaptiveNamespace::FallbackType fallback) { return AdaptiveCardElementBase::put_FallbackType(fallback); } - IFACEMETHODIMP put_FallbackContent(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement * content) { return AdaptiveCardElementBase::put_FallbackContent(content); } + IFACEMETHODIMP get_FallbackType(_Out_ ABI::AdaptiveNamespace::FallbackType* fallback) + { + return AdaptiveCardElementBase::get_FallbackType(fallback); + } + IFACEMETHODIMP get_FallbackContent(_COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** content) + { + return AdaptiveCardElementBase::get_FallbackContent(content); + } + IFACEMETHODIMP put_FallbackType(ABI::AdaptiveNamespace::FallbackType fallback) + { + return AdaptiveCardElementBase::put_FallbackType(fallback); + } + IFACEMETHODIMP put_FallbackContent(_In_ ABI::AdaptiveNamespace::IAdaptiveCardElement* content) + { + return AdaptiveCardElementBase::put_FallbackContent(content); + } IFACEMETHODIMP get_ElementTypeString(_Outptr_ HSTRING* value) { diff --git a/source/uwp/Renderer/lib/AdaptiveMediaConfig.cpp b/source/uwp/Renderer/lib/AdaptiveMediaConfig.cpp index 0c41d43b83..6e33c207f3 100644 --- a/source/uwp/Renderer/lib/AdaptiveMediaConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveMediaConfig.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "Util.h" + #include "AdaptiveMediaConfig.h" using namespace Microsoft::WRL; @@ -9,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveMediaConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveMediaConfig::RuntimeClassInitialize() noexcept + try { MediaConfig mediaConfig; return RuntimeClassInitialize(mediaConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveMediaConfig.h b/source/uwp/Renderer/lib/AdaptiveMediaConfig.h index 890de2e390..82fc053c59 100644 --- a/source/uwp/Renderer/lib/AdaptiveMediaConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveMediaConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveMediaConfig diff --git a/source/uwp/Renderer/lib/AdaptiveMediaEventInvoker.cpp b/source/uwp/Renderer/lib/AdaptiveMediaEventInvoker.cpp index f834aa8e89..cceeca9c3a 100644 --- a/source/uwp/Renderer/lib/AdaptiveMediaEventInvoker.cpp +++ b/source/uwp/Renderer/lib/AdaptiveMediaEventInvoker.cpp @@ -15,7 +15,8 @@ namespace AdaptiveNamespace { HRESULT AdaptiveMediaEventInvoker::RuntimeClassInitialize() noexcept { return S_OK; } - HRESULT AdaptiveMediaEventInvoker::RuntimeClassInitialize(_In_ RenderedAdaptiveCard* renderResult) noexcept try + HRESULT AdaptiveMediaEventInvoker::RuntimeClassInitialize(_In_ RenderedAdaptiveCard* renderResult) noexcept + try { ComPtr strongRenderResult = renderResult; return strongRenderResult.AsWeak(&m_weakRenderResult); diff --git a/source/uwp/Renderer/lib/AdaptiveMediaRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveMediaRenderer.cpp index f85185d0ce..ef4aced326 100644 --- a/source/uwp/Renderer/lib/AdaptiveMediaRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveMediaRenderer.cpp @@ -3,27 +3,173 @@ #include "pch.h" #include "AdaptiveMedia.h" + +#include "ActionHelpers.h" #include "AdaptiveMediaRenderer.h" -#include "XamlBuilder.h" #include "AdaptiveElementParserRegistration.h" +#include "MediaHelpers.h" using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Controls::Primitives; +using namespace ABI::Windows::UI::Xaml::Media; namespace AdaptiveNamespace { - HRESULT AdaptiveMediaRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveMediaRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveMediaRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveMediaRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** mediaControl) noexcept + try { - return XamlBuilder::BuildMedia(cardElement, renderContext, renderArgs, result); + ComPtr localCardElement{adaptiveCardElement}; + ComPtr adaptiveMedia; + RETURN_IF_FAILED(localCardElement.As(&adaptiveMedia)); + + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + // Get the poster image + ComPtr posterImage; + GetMediaPosterAsImage(renderContext, renderArgs, adaptiveMedia.Get(), &posterImage); + + // If the host doesn't support interactivity we're done here, just return the poster image + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"Media was present in card, but interactivity is not supported").Get()); + + if (posterImage != nullptr) + { + RETURN_IF_FAILED(posterImage.CopyTo(mediaControl)); + } + + return S_OK; + } + + // Put the poster image in a container with a play button + ComPtr posterContainer; + CreatePosterContainerWithPlayButton(posterImage.Get(), renderContext, renderArgs, &posterContainer); + + ComPtr touchTargetUIElement; + ActionHelpers::WrapInTouchTarget(adaptiveCardElement, posterContainer.Get(), nullptr, renderContext, true, L"Adaptive.SelectAction", &touchTargetUIElement); + + // Create a panel to hold the poster and the media element + ComPtr mediaStackPanel = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_StackPanel)); + ComPtr mediaPanel; + RETURN_IF_FAILED(mediaStackPanel.As(&mediaPanel)); + + XamlHelpers::AppendXamlElementToPanel(touchTargetUIElement.Get(), mediaPanel.Get()); + + // Check if this host allows inline playback + ComPtr mediaConfig; + RETURN_IF_FAILED(hostConfig->get_Media(&mediaConfig)); + + boolean allowInlinePlayback; + RETURN_IF_FAILED(mediaConfig->get_AllowInlinePlayback(&allowInlinePlayback)); + + ComPtr mediaInvoker; + RETURN_IF_FAILED(renderContext->get_MediaEventInvoker(&mediaInvoker)); + + HString mimeType; + ComPtr mediaElement; + ComPtr mediaSourceUrl; + if (allowInlinePlayback) + { + // Create a media element and set it's source + mediaElement = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_MediaElement)); + + GetMediaSource(hostConfig.Get(), adaptiveMedia.Get(), mediaSourceUrl.GetAddressOf(), mimeType.GetAddressOf()); + + if (mediaSourceUrl == nullptr) + { + renderContext->AddWarning(ABI::AdaptiveNamespace::WarningStatusCode::UnsupportedMediaType, + HStringReference(L"Unsupported media element dropped").Get()); + return S_OK; + } + + // Configure Auto Play and Controls + RETURN_IF_FAILED(mediaElement->put_AutoPlay(false)); + + ComPtr mediaElement2; + RETURN_IF_FAILED(mediaElement.As(&mediaElement2)); + RETURN_IF_FAILED(mediaElement2->put_AreTransportControlsEnabled(true)); + ComPtr mediaElement3; + RETURN_IF_FAILED(mediaElement.As(&mediaElement3)); + ComPtr mediaTransportControl; + RETURN_IF_FAILED(mediaElement3->get_TransportControls(&mediaTransportControl)); + RETURN_IF_FAILED(mediaTransportControl->put_IsCompact(true)); + RETURN_IF_FAILED(mediaTransportControl->put_IsZoomButtonVisible(false)); + + ComPtr mediaUIElement; + RETURN_IF_FAILED(mediaElement.As(&mediaUIElement)); + + if (posterImage != nullptr) + { + // Set the poster on the media element + ComPtr posterImageSource; + RETURN_IF_FAILED(posterImage->get_Source(&posterImageSource)); + RETURN_IF_FAILED(mediaElement->put_PosterSource(posterImageSource.Get())); + } + + // Make the media element collapsed until the user clicks + RETURN_IF_FAILED(mediaUIElement->put_Visibility(Visibility_Collapsed)); + + XamlHelpers::AppendXamlElementToPanel(mediaElement.Get(), mediaPanel.Get()); + } + + ComPtr mediaPanelAsUIElement; + RETURN_IF_FAILED(mediaPanel.As(&mediaPanelAsUIElement)); + + ComPtr touchTargetAsButtonBase; + RETURN_IF_FAILED(touchTargetUIElement.As(&touchTargetAsButtonBase)); + + // Take a reference to the mime type string for the lambda (lifetime dictated by localMimeType in the below + // lambda) + HSTRING lambdaMimeType; + WindowsDuplicateString(mimeType.Get(), &lambdaMimeType); + ComPtr lambdaRenderContext{renderContext}; + + EventRegistrationToken clickToken; + RETURN_IF_FAILED(touchTargetAsButtonBase->add_Click( + Callback([touchTargetUIElement, lambdaRenderContext, adaptiveMedia, mediaElement, mediaSourceUrl, lambdaMimeType, mediaInvoker]( + IInspectable* /*sender*/, IRoutedEventArgs * /*args*/) -> HRESULT { + // Take ownership of the passed in HSTRING + HString localMimeType; + localMimeType.Attach(lambdaMimeType); + + // Turn off the button to prevent extra clicks + ComPtr buttonAsControl; + touchTargetUIElement.As(&buttonAsControl); + RETURN_IF_FAILED(buttonAsControl->put_IsEnabled(false)); + + // Handle the click + return HandleMediaClick(lambdaRenderContext.Get(), + adaptiveMedia.Get(), + mediaElement.Get(), + touchTargetUIElement.Get(), + mediaSourceUrl.Get(), + lambdaMimeType, + mediaInvoker.Get()); + }).Get(), + &clickToken)); + + RETURN_IF_FAILED(mediaPanelAsUIElement.CopyTo(mediaControl)); + return S_OK; } CATCH_RETURN; @@ -32,7 +178,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveMediaSource.cpp b/source/uwp/Renderer/lib/AdaptiveMediaSource.cpp index 01377a4b6c..7891eca043 100644 --- a/source/uwp/Renderer/lib/AdaptiveMediaSource.cpp +++ b/source/uwp/Renderer/lib/AdaptiveMediaSource.cpp @@ -5,7 +5,8 @@ namespace AdaptiveNamespace { - HRESULT AdaptiveMediaSource::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveMediaSource::RuntimeClassInitialize() noexcept + try { std::shared_ptr mediaSource = std::make_shared(); @@ -13,7 +14,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveMediaSource::RuntimeClassInitialize(const std::shared_ptr& sharedMediaSource) try + HRESULT AdaptiveMediaSource::RuntimeClassInitialize(const std::shared_ptr& sharedMediaSource) + try { if (sharedMediaSource == nullptr) { @@ -35,7 +37,8 @@ namespace AdaptiveNamespace HRESULT AdaptiveMediaSource::put_Url(_In_ HSTRING value) { return m_url.Set(value); } - HRESULT AdaptiveMediaSource::GetSharedModel(std::shared_ptr& sharedMediaSource) try + HRESULT AdaptiveMediaSource::GetSharedModel(std::shared_ptr& sharedMediaSource) + try { std::shared_ptr mediaSource = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveNumberInput.cpp b/source/uwp/Renderer/lib/AdaptiveNumberInput.cpp index 0634cf9f95..1fb1d551f2 100644 --- a/source/uwp/Renderer/lib/AdaptiveNumberInput.cpp +++ b/source/uwp/Renderer/lib/AdaptiveNumberInput.cpp @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveNumberInput.h" -#include "Util.h" -#include +#include "AdaptiveNumberInput.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -15,7 +13,8 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveNumberInput::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveNumberInput::RuntimeClassInitialize() noexcept + try { std::shared_ptr numberInput = std::make_shared(); @@ -23,7 +22,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveNumberInput::RuntimeClassInitialize(const std::shared_ptr& sharedNumberInput) try + HRESULT AdaptiveNumberInput::RuntimeClassInitialize(const std::shared_ptr& sharedNumberInput) + try { if (sharedNumberInput == nullptr) { @@ -89,7 +89,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveNumberInput::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveNumberInput::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr numberInput = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveNumberInput.h b/source/uwp/Renderer/lib/AdaptiveNumberInput.h index 81e3528fe2..1e4e63c679 100644 --- a/source/uwp/Renderer/lib/AdaptiveNumberInput.h +++ b/source/uwp/Renderer/lib/AdaptiveNumberInput.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "NumberInput.h" #include "AdaptiveInputElement.h" diff --git a/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.cpp index cd3488fcec..190b0ee527 100644 --- a/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.cpp @@ -5,29 +5,84 @@ #include "AdaptiveElementParserRegistration.h" #include "AdaptiveNumberInput.h" #include "AdaptiveNumberInputRenderer.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Input; namespace AdaptiveNamespace { - HRESULT AdaptiveNumberInputRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveNumberInputRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveNumberInputRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveNumberInputRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, - _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _In_ IAdaptiveRenderArgs* /*renderArgs*/, + _COM_Outptr_ IUIElement** numberInputControl) noexcept + try { - return XamlBuilder::BuildNumberInput(cardElement, renderContext, renderArgs, result); + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning( + ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"Number input was stripped from card because interactivity is not supported").Get()); + return S_OK; + } + + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveNumberInput; + RETURN_IF_FAILED(cardElement.As(&adaptiveNumberInput)); + + ComPtr textBox = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBox)); + + ComPtr inputScopeName = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Input_InputScopeName)); + RETURN_IF_FAILED(inputScopeName->put_NameValue(InputScopeNameValue::InputScopeNameValue_Number)); + + ComPtr inputScope = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Input_InputScope)); + ComPtr> names; + RETURN_IF_FAILED(inputScope->get_Names(names.GetAddressOf())); + RETURN_IF_FAILED(names->Append(inputScopeName.Get())); + + RETURN_IF_FAILED(textBox->put_InputScope(inputScope.Get())); + + INT32 value; + RETURN_IF_FAILED(adaptiveNumberInput->get_Value(&value)); + + std::wstring stringValue = std::to_wstring(value); + RETURN_IF_FAILED(textBox->put_Text(HStringReference(stringValue.c_str()).Get())); + + ComPtr textBox2; + RETURN_IF_FAILED(textBox.As(&textBox2)); + + HString placeHolderText; + RETURN_IF_FAILED(adaptiveNumberInput->get_Placeholder(placeHolderText.GetAddressOf())); + RETURN_IF_FAILED(textBox2->put_PlaceholderText(placeHolderText.Get())); + + ComPtr frameworkElement; + RETURN_IF_FAILED(textBox.As(&frameworkElement)); + RETURN_IF_FAILED(frameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + RETURN_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.Input.Number", frameworkElement.Get())); + + // TODO: Handle max and min? + RETURN_IF_FAILED(textBox.CopyTo(numberInputControl)); + XamlHelpers::AddInputValueToContext(renderContext, adaptiveCardElement, *numberInputControl); + + return S_OK; } CATCH_RETURN; @@ -36,7 +91,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.h b/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.h index 760aa56c16..01c8ecb1e1 100644 --- a/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveNumberInputRenderer.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "NumberInput.h" - namespace AdaptiveNamespace { class AdaptiveNumberInputRenderer diff --git a/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.cpp b/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.cpp index a64b810787..2513e0ac32 100644 --- a/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.cpp +++ b/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.cpp @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveOpenUrlAction.h" -#include "Util.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -11,7 +11,8 @@ using namespace ABI::Windows::Foundation; namespace AdaptiveNamespace { - HRESULT AdaptiveOpenUrlAction::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveOpenUrlAction::RuntimeClassInitialize() noexcept + try { std::shared_ptr openUrlAction = std::make_shared(); @@ -19,7 +20,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveOpenUrlAction::RuntimeClassInitialize(const std::shared_ptr& sharedOpenUrlAction) try + HRESULT AdaptiveOpenUrlAction::RuntimeClassInitialize(const std::shared_ptr& sharedOpenUrlAction) + try { if (sharedOpenUrlAction == nullptr) { @@ -43,7 +45,8 @@ namespace AdaptiveNamespace HRESULT AdaptiveOpenUrlAction::get_Url(_COM_Outptr_ IUriRuntimeClass** url) { return m_url.CopyTo(url); } - HRESULT AdaptiveOpenUrlAction::put_Url(_In_ IUriRuntimeClass* url) try + HRESULT AdaptiveOpenUrlAction::put_Url(_In_ IUriRuntimeClass* url) + try { m_url = url; return S_OK; @@ -56,7 +59,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveOpenUrlAction::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveOpenUrlAction::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr openUrlAction = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.h b/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.h index 17f5b6c961..9071f28910 100644 --- a/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.h +++ b/source/uwp/Renderer/lib/AdaptiveOpenUrlAction.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "OpenUrlAction.h" #include "AdaptiveActionElement.h" @@ -65,14 +63,8 @@ namespace AdaptiveNamespace } IFACEMETHODIMP put_IconUrl(_In_ HSTRING iconUrl) { return AdaptiveActionElementBase::put_IconUrl(iconUrl); } - IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) - { - return AdaptiveActionElementBase::get_Style(style); - } - IFACEMETHODIMP put_Style(_In_ HSTRING style) - { - return AdaptiveActionElementBase::put_Style(style); - } + IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) { return AdaptiveActionElementBase::get_Style(style); } + IFACEMETHODIMP put_Style(_In_ HSTRING style) { return AdaptiveActionElementBase::put_Style(style); } IFACEMETHODIMP get_AdditionalProperties(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result) { diff --git a/source/uwp/Renderer/lib/AdaptiveOpenUrlActionRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveOpenUrlActionRenderer.cpp index 4d416b9031..cf682a0c79 100644 --- a/source/uwp/Renderer/lib/AdaptiveOpenUrlActionRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveOpenUrlActionRenderer.cpp @@ -6,14 +6,15 @@ #include "AdaptiveOpenUrlActionRenderer.h" #include "Util.h" #include "AdaptiveElementParserRegistration.h" -#include "XamlBuilder.h" +#include "ActionHelpers.h" using namespace ABI::AdaptiveNamespace; using namespace Microsoft::WRL; namespace AdaptiveNamespace { - HRESULT AdaptiveOpenUrlActionRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveOpenUrlActionRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } @@ -22,9 +23,10 @@ namespace AdaptiveNamespace HRESULT AdaptiveOpenUrlActionRenderer::Render(_In_ IAdaptiveActionElement* action, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept + try { - return XamlBuilder::BuildAction(action, renderContext, renderArgs, result); + return ActionHelpers::BuildAction(action, renderContext, renderArgs, result); } CATCH_RETURN; @@ -33,7 +35,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.cpp b/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.cpp index 27d2960290..932c398eed 100644 --- a/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.cpp +++ b/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.cpp @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveRemoteResourceInformation.h" -#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -13,14 +13,16 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveRemoteResourceInformation::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveRemoteResourceInformation::RuntimeClassInitialize() noexcept + try { RemoteResourceInformation uriInformation; return RuntimeClassInitialize(uriInformation); } CATCH_RETURN; - HRESULT AdaptiveRemoteResourceInformation::RuntimeClassInitialize(RemoteResourceInformation& uriInformation) try + HRESULT AdaptiveRemoteResourceInformation::RuntimeClassInitialize(RemoteResourceInformation& uriInformation) + try { RETURN_IF_FAILED(UTF8ToHString(uriInformation.url, m_url.GetAddressOf())); RETURN_IF_FAILED(UTF8ToHString(uriInformation.mimeType, m_mimeType.GetAddressOf())); diff --git a/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.h b/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.h index 3edf81f82d..05d28a7734 100644 --- a/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.h +++ b/source/uwp/Renderer/lib/AdaptiveRemoteResourceInformation.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "TextBlock.h" -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveRenderArgs.cpp b/source/uwp/Renderer/lib/AdaptiveRenderArgs.cpp index 3c00444d13..011dff923c 100644 --- a/source/uwp/Renderer/lib/AdaptiveRenderArgs.cpp +++ b/source/uwp/Renderer/lib/AdaptiveRenderArgs.cpp @@ -16,7 +16,8 @@ namespace AdaptiveNamespace HRESULT AdaptiveRenderArgs::RuntimeClassInitialize(ABI::AdaptiveNamespace::ContainerStyle containerStyle, _In_opt_ IInspectable* parentElement, - _In_opt_ IAdaptiveRenderArgs* renderArgs) noexcept try + _In_opt_ IAdaptiveRenderArgs* renderArgs) noexcept + try { m_containerStyle = containerStyle; m_parentElement = parentElement; diff --git a/source/uwp/Renderer/lib/AdaptiveRenderContext.cpp b/source/uwp/Renderer/lib/AdaptiveRenderContext.cpp index fd5579859a..93e61a2fe7 100644 --- a/source/uwp/Renderer/lib/AdaptiveRenderContext.cpp +++ b/source/uwp/Renderer/lib/AdaptiveRenderContext.cpp @@ -26,7 +26,8 @@ namespace AdaptiveNamespace _In_ IAdaptiveCardResourceResolvers* resourceResolvers, _In_ IResourceDictionary* overrideDictionary, _In_ IResourceDictionary* defaultActionSentimentStyles, - _In_ RenderedAdaptiveCard* renderResult) noexcept try + _In_ RenderedAdaptiveCard* renderResult) noexcept + try { m_hostConfig = hostConfig; m_featureRegistration = featureRegistration; diff --git a/source/uwp/Renderer/lib/AdaptiveRichTextBlock.cpp b/source/uwp/Renderer/lib/AdaptiveRichTextBlock.cpp index fc67f51978..f9485b0b1e 100644 --- a/source/uwp/Renderer/lib/AdaptiveRichTextBlock.cpp +++ b/source/uwp/Renderer/lib/AdaptiveRichTextBlock.cpp @@ -1,11 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveRichTextBlock.h" -#include "Util.h" #include "DateTimeParser.h" -#include "Vector.h" -#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -18,7 +16,8 @@ namespace AdaptiveNamespace { AdaptiveRichTextBlock::AdaptiveRichTextBlock() { m_inlines = Microsoft::WRL::Make>(); } - HRESULT AdaptiveRichTextBlock::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveRichTextBlock::RuntimeClassInitialize() noexcept + try { std::shared_ptr richTextBlock = std::make_shared(); @@ -26,7 +25,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveRichTextBlock::RuntimeClassInitialize(const std::shared_ptr& sharedRichTextBlock) noexcept try + HRESULT AdaptiveRichTextBlock::RuntimeClassInitialize(const std::shared_ptr& sharedRichTextBlock) noexcept + try { if (sharedRichTextBlock == nullptr) { @@ -66,7 +66,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveRichTextBlock::GetSharedModel(std::shared_ptr& sharedRichTextBlock) noexcept try + HRESULT AdaptiveRichTextBlock::GetSharedModel(std::shared_ptr& sharedRichTextBlock) noexcept + try { std::shared_ptr richTextBlock = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveRichTextBlock.h b/source/uwp/Renderer/lib/AdaptiveRichTextBlock.h index f204d0fa95..c7ad67dc9b 100644 --- a/source/uwp/Renderer/lib/AdaptiveRichTextBlock.h +++ b/source/uwp/Renderer/lib/AdaptiveRichTextBlock.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "RichTextBlock.h" -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.cpp index 6535c46a16..de2941cc3d 100644 --- a/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.cpp @@ -5,18 +5,22 @@ #include "AdaptiveRichTextBlock.h" #include "AdaptiveRichTextBlockRenderer.h" #include "AdaptiveRenderContext.h" -#include "Util.h" -#include "XamlBuilder.h" #include "AdaptiveElementParserRegistration.h" +#include "TextHelpers.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Documents; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveRichTextBlockRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveRichTextBlockRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } @@ -25,10 +29,144 @@ namespace AdaptiveNamespace HRESULT AdaptiveRichTextBlockRenderer::Render(_In_ IAdaptiveCardElement* cardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept + try { - XamlBuilder::BuildRichTextBlock(cardElement, renderContext, renderArgs, result); - return S_OK; + // Create the top level rich text block and set it's properties + ComPtr xamlRichTextBlock = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_RichTextBlock)); + + ComPtr localAdaptiveCardElement(cardElement); + ComPtr adaptiveRichTextBlock; + RETURN_IF_FAILED(localAdaptiveCardElement.As(&adaptiveRichTextBlock)); + + // Set the horizontal Alingment + RETURN_IF_FAILED(SetHorizontalAlignment(adaptiveRichTextBlock.Get(), xamlRichTextBlock.Get())); + + // Get the highlighters + ComPtr xamlRichTextBlock5; + RETURN_IF_FAILED(xamlRichTextBlock.As(&xamlRichTextBlock5)); + + ComPtr> textHighlighters; + RETURN_IF_FAILED(xamlRichTextBlock5->get_TextHighlighters(&textHighlighters)); + + // Add a paragraph for the inlines + ComPtr> xamlBlocks; + RETURN_IF_FAILED(xamlRichTextBlock->get_Blocks(&xamlBlocks)); + + ComPtr xamlParagraph = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Documents_Paragraph)); + + ComPtr paragraphAsBlock; + RETURN_IF_FAILED(xamlParagraph.As(¶graphAsBlock)); + RETURN_IF_FAILED(xamlBlocks->Append(paragraphAsBlock.Get())); + + // Add the Inlines + ComPtr> xamlInlines; + RETURN_IF_FAILED(xamlParagraph->get_Inlines(&xamlInlines)); + + ComPtr> adaptiveInlines; + RETURN_IF_FAILED(adaptiveRichTextBlock->get_Inlines(&adaptiveInlines)); + + UINT currentOffset = 0; + XamlHelpers::IterateOverVector(adaptiveInlines.Get(), [&](IAdaptiveInline* adaptiveInline) { + // We only support TextRun inlines for now + ComPtr localInline(adaptiveInline); + ComPtr adaptiveTextRun; + RETURN_IF_FAILED(localInline.As(&adaptiveTextRun)); + + ComPtr selectAction; + RETURN_IF_FAILED(adaptiveTextRun->get_SelectAction(&selectAction)); + + ComPtr adaptiveTextElement; + RETURN_IF_FAILED(localInline.As(&adaptiveTextElement)); + + HString text; + RETURN_IF_FAILED(adaptiveTextElement->get_Text(text.GetAddressOf())); + + boolean isStrikethrough{false}; + RETURN_IF_FAILED(adaptiveTextRun->get_Strikethrough(&isStrikethrough)); + + boolean isItalic{false}; + RETURN_IF_FAILED(adaptiveTextRun->get_Italic(&isItalic)); + + boolean isUnderline{}; + RETURN_IF_FAILED(adaptiveTextRun->get_Underline(&isUnderline)); + + UINT inlineLength; + if (selectAction != nullptr) + { + // If there's a select action, create a hyperlink that triggers the action + ComPtr hyperlink = + XamlHelpers::CreateXamlClass( + HStringReference(RuntimeClass_Windows_UI_Xaml_Documents_Hyperlink)); + + ComPtr actionInvoker; + renderContext->get_ActionInvoker(&actionInvoker); + + EventRegistrationToken clickToken; + RETURN_IF_FAILED( + hyperlink->add_Click(Callback>( + [selectAction, actionInvoker](IInspectable*, IHyperlinkClickEventArgs*) -> HRESULT { + return actionInvoker->SendActionEvent(selectAction.Get()); + }) + .Get(), + &clickToken)); + + // Add the run text to the hyperlink's inlines + ComPtr hyperlinkAsSpan; + RETURN_IF_FAILED(hyperlink.As(&hyperlinkAsSpan)); + + ComPtr> hyperlinkInlines; + RETURN_IF_FAILED(hyperlinkAsSpan->get_Inlines(hyperlinkInlines.GetAddressOf())); + RETURN_IF_FAILED(AddSingleTextInline(adaptiveTextElement.Get(), + renderContext, + renderArgs, + text.Get(), + TextRunStyleParameters(isStrikethrough, isItalic, isUnderline, true), + hyperlinkInlines.Get(), + &inlineLength)); + + ComPtr hyperlinkAsInline; + RETURN_IF_FAILED(hyperlink.As(&hyperlinkAsInline)); + + // Add the hyperlink to the paragraph's inlines + RETURN_IF_FAILED(xamlInlines->Append(hyperlinkAsInline.Get())); + } + else + { + // Add the text to the paragraph's inlines + RETURN_IF_FAILED(AddSingleTextInline(adaptiveTextElement.Get(), + renderContext, + renderArgs, + text.Get(), + TextRunStyleParameters(isStrikethrough, isItalic, isUnderline, false), + xamlInlines.Get(), + &inlineLength)); + } + + boolean highlight; + RETURN_IF_FAILED(adaptiveTextRun->get_Highlight(&highlight)); + + if (highlight) + { + ComPtr textHighlighter; + RETURN_IF_FAILED(GetHighlighter(adaptiveTextElement.Get(), renderContext, renderArgs, &textHighlighter)); + + ComPtr> ranges; + RETURN_IF_FAILED(textHighlighter->get_Ranges(&ranges)); + + TextRange textRange = {(INT32)currentOffset, (INT32)inlineLength}; + RETURN_IF_FAILED(ranges->Append(textRange)); + + RETURN_IF_FAILED(textHighlighters->Append(textHighlighter.Get())); + } + + currentOffset += inlineLength; + return S_OK; + }); + + return xamlRichTextBlock.CopyTo(result); } CATCH_RETURN; @@ -37,7 +175,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.h b/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.h index f694d16173..027a9bd3a7 100644 --- a/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveRichTextBlockRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "RichTextBlock.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveSeparator.cpp b/source/uwp/Renderer/lib/AdaptiveSeparator.cpp index f1ecd14f2f..12fbc54fff 100644 --- a/source/uwp/Renderer/lib/AdaptiveSeparator.cpp +++ b/source/uwp/Renderer/lib/AdaptiveSeparator.cpp @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveSeparator.h" -#include "Util.h" -#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -14,7 +13,8 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveSeparator::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveSeparator::RuntimeClassInitialize() noexcept + try { m_sharedSeparator = std::make_shared(); return S_OK; diff --git a/source/uwp/Renderer/lib/AdaptiveSeparator.h b/source/uwp/Renderer/lib/AdaptiveSeparator.h index a6a00cc3f2..e62b9cb463 100644 --- a/source/uwp/Renderer/lib/AdaptiveSeparator.h +++ b/source/uwp/Renderer/lib/AdaptiveSeparator.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "Separator.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.cpp b/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.cpp index a558c063b1..54d3a3afa4 100644 --- a/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveSeparatorConfig.h" using namespace Microsoft::WRL; @@ -8,14 +9,16 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveSeparatorConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveSeparatorConfig::RuntimeClassInitialize() noexcept + try { SeparatorConfig separatorConfig; return RuntimeClassInitialize(separatorConfig); } CATCH_RETURN; - HRESULT AdaptiveSeparatorConfig::RuntimeClassInitialize(SeparatorConfig sharedSeparatorConfig) noexcept try + HRESULT AdaptiveSeparatorConfig::RuntimeClassInitialize(SeparatorConfig sharedSeparatorConfig) noexcept + try { RETURN_IF_FAILED(GetColorFromString(sharedSeparatorConfig.lineColor, &m_lineColor)); m_lineThickness = sharedSeparatorConfig.lineThickness; diff --git a/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.h b/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.h index a7281976f5..45bee70cdf 100644 --- a/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveSeparatorConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveSeparatorConfig diff --git a/source/uwp/Renderer/lib/AdaptiveShowCardAction.cpp b/source/uwp/Renderer/lib/AdaptiveShowCardAction.cpp index cf43706bc8..da5b419316 100644 --- a/source/uwp/Renderer/lib/AdaptiveShowCardAction.cpp +++ b/source/uwp/Renderer/lib/AdaptiveShowCardAction.cpp @@ -1,16 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveCard.h" #include "AdaptiveShowCardAction.h" -#include "Util.h" using namespace Microsoft::WRL; using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveShowCardAction::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveShowCardAction::RuntimeClassInitialize() noexcept + try { std::shared_ptr showCardAction = std::make_shared(); @@ -18,7 +19,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveShowCardAction::RuntimeClassInitialize(const std::shared_ptr& sharedShowCardAction) try + HRESULT AdaptiveShowCardAction::RuntimeClassInitialize(const std::shared_ptr& sharedShowCardAction) + try { if (sharedShowCardAction == nullptr) { @@ -53,7 +55,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveShowCardAction::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveShowCardAction::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr showCardAction = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveShowCardAction.h b/source/uwp/Renderer/lib/AdaptiveShowCardAction.h index 171a802958..c0026c140b 100644 --- a/source/uwp/Renderer/lib/AdaptiveShowCardAction.h +++ b/source/uwp/Renderer/lib/AdaptiveShowCardAction.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ShowCardAction.h" #include "AdaptiveActionElement.h" @@ -65,14 +63,8 @@ namespace AdaptiveNamespace } IFACEMETHODIMP put_IconUrl(_In_ HSTRING iconUrl) { return AdaptiveActionElementBase::put_IconUrl(iconUrl); } - IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) - { - return AdaptiveActionElementBase::get_Style(style); - } - IFACEMETHODIMP put_Style(_In_ HSTRING style) - { - return AdaptiveActionElementBase::put_Style(style); - } + IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) { return AdaptiveActionElementBase::get_Style(style); } + IFACEMETHODIMP put_Style(_In_ HSTRING style) { return AdaptiveActionElementBase::put_Style(style); } IFACEMETHODIMP get_AdditionalProperties(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result) { diff --git a/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.cpp b/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.cpp index d902de6f6c..2c3f943213 100644 --- a/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "Util.h" + #include "AdaptiveShowCardActionConfig.h" using namespace Microsoft::WRL; @@ -10,7 +10,8 @@ using namespace ABI::Windows::UI; namespace AdaptiveNamespace { - HRESULT AdaptiveShowCardActionConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveShowCardActionConfig::RuntimeClassInitialize() noexcept + try { ShowCardActionConfig showCardActionConfig; return RuntimeClassInitialize(showCardActionConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.h b/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.h index f0a55b08ae..bd5c84cad5 100644 --- a/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveShowCardActionConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveShowCardActionConfig diff --git a/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.cpp index b7806c633e..fee5d0fb9f 100644 --- a/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.cpp @@ -4,16 +4,19 @@ #include "AdaptiveShowCardAction.h" #include "AdaptiveShowCardActionRenderer.h" -#include "Util.h" #include "AdaptiveElementParserRegistration.h" -#include "XamlBuilder.h" +#include "ActionHelpers.h" -using namespace ABI::AdaptiveNamespace; using namespace Microsoft::WRL; +using namespace ABI::AdaptiveNamespace; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveShowCardActionRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveShowCardActionRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } @@ -22,9 +25,10 @@ namespace AdaptiveNamespace HRESULT AdaptiveShowCardActionRenderer::Render(_In_ IAdaptiveActionElement* action, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept + try { - return XamlBuilder::BuildAction(action, renderContext, renderArgs, result); + return ActionHelpers::BuildAction(action, renderContext, renderArgs, result); } CATCH_RETURN; @@ -33,10 +37,79 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); } CATCH_RETURN; + + HRESULT AdaptiveShowCardActionRenderer::BuildShowCard(_In_ IAdaptiveCard* showCard, + _In_ IAdaptiveRenderContext* renderContext, + _In_ IAdaptiveRenderArgs* renderArgs, + bool isBottomActionBar, + _Outptr_ IUIElement** uiShowCard) noexcept + try + { + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + + ComPtr actionsConfig; + RETURN_IF_FAILED(hostConfig->get_Actions(&actionsConfig)); + + ComPtr showCardActionConfig; + RETURN_IF_FAILED(actionsConfig->get_ShowCard(&showCardActionConfig)); + + ABI::AdaptiveNamespace::ContainerStyle showCardConfigStyle; + RETURN_IF_FAILED(showCardActionConfig->get_Style(&showCardConfigStyle)); + + boolean wasInShowCard; + RETURN_IF_FAILED(renderArgs->get_IsInShowCard(&wasInShowCard)); + RETURN_IF_FAILED(renderArgs->put_IsInShowCard(true)); + + ComPtr localUiShowCard; + RETURN_IF_FAILED( + XamlBuilder::BuildXamlTreeFromAdaptiveCard(showCard, localUiShowCard.GetAddressOf(), renderContext, nullptr, showCardConfigStyle)); + + RETURN_IF_FAILED(renderArgs->put_IsInShowCard(wasInShowCard)); + + ComPtr showCardGrid; + RETURN_IF_FAILED(localUiShowCard.As(&showCardGrid)); + + // Set the padding + ComPtr spacingConfig; + RETURN_IF_FAILED(hostConfig->get_Spacing(&spacingConfig)); + + UINT32 padding; + RETURN_IF_FAILED(spacingConfig->get_Padding(&padding)); + + ABI::AdaptiveNamespace::ActionMode showCardActionMode; + RETURN_IF_FAILED(showCardActionConfig->get_ActionMode(&showCardActionMode)); + + // Set the top margin + ComPtr showCardFrameworkElement; + RETURN_IF_FAILED(localUiShowCard.As(&showCardFrameworkElement)); + + UINT32 inlineTopMargin; + RETURN_IF_FAILED(showCardActionConfig->get_InlineTopMargin(&inlineTopMargin)); + + const double negativePadding = -(static_cast(padding)); + const double sideMargin = negativePadding; + const double topMargin = isBottomActionBar ? inlineTopMargin + padding : inlineTopMargin; + const double bottomMargin = isBottomActionBar ? negativePadding : 0; + + Thickness margin = {sideMargin, topMargin, sideMargin, bottomMargin}; + RETURN_IF_FAILED(showCardFrameworkElement->put_Margin(margin)); + + ComPtr showCardUIElement; + RETURN_IF_FAILED(localUiShowCard.As(&showCardUIElement)); + + // Set the visibility as Collapsed until the action is triggered + RETURN_IF_FAILED(showCardUIElement->put_Visibility(Visibility_Collapsed)); + + *uiShowCard = showCardUIElement.Detach(); + return S_OK; + } + CATCH_RETURN; } diff --git a/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.h b/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.h index cf33f14d7c..f111d2a943 100644 --- a/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveShowCardActionRenderer.h @@ -26,6 +26,12 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept override; + + static HRESULT BuildShowCard(_In_ ABI::AdaptiveNamespace::IAdaptiveCard* showCard, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderContext* renderContext, + _In_ ABI::AdaptiveNamespace::IAdaptiveRenderArgs* renderArgs, + bool isBottomActionBar, + _Outptr_ ABI::Windows::UI::Xaml::IUIElement** uiShowCard) noexcept; }; ActivatableClass(AdaptiveShowCardActionRenderer); diff --git a/source/uwp/Renderer/lib/AdaptiveSpacingConfig.cpp b/source/uwp/Renderer/lib/AdaptiveSpacingConfig.cpp index 9ad07f2b99..b5806be831 100644 --- a/source/uwp/Renderer/lib/AdaptiveSpacingConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveSpacingConfig.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveSpacingConfig.h" using namespace Microsoft::WRL; @@ -8,14 +9,16 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveSpacingConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveSpacingConfig::RuntimeClassInitialize() noexcept + try { SpacingConfig spacingConfig; return RuntimeClassInitialize(spacingConfig); } CATCH_RETURN; - HRESULT AdaptiveSpacingConfig::RuntimeClassInitialize(SpacingConfig spacingConfig) noexcept try + HRESULT AdaptiveSpacingConfig::RuntimeClassInitialize(SpacingConfig spacingConfig) noexcept + try { m_small = spacingConfig.smallSpacing; m_medium = spacingConfig.mediumSpacing; diff --git a/source/uwp/Renderer/lib/AdaptiveSpacingConfig.h b/source/uwp/Renderer/lib/AdaptiveSpacingConfig.h index 953640e0c1..9d014f7a75 100644 --- a/source/uwp/Renderer/lib/AdaptiveSpacingConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveSpacingConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveSpacingConfig diff --git a/source/uwp/Renderer/lib/AdaptiveSubmitAction.cpp b/source/uwp/Renderer/lib/AdaptiveSubmitAction.cpp index 87940b3538..1ad5f07cc7 100644 --- a/source/uwp/Renderer/lib/AdaptiveSubmitAction.cpp +++ b/source/uwp/Renderer/lib/AdaptiveSubmitAction.cpp @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveSubmitAction.h" -#include "Util.h" using namespace Microsoft::WRL; using namespace ABI::AdaptiveNamespace; @@ -10,7 +10,8 @@ using namespace ABI::Windows::Data::Json; namespace AdaptiveNamespace { - HRESULT AdaptiveSubmitAction::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveSubmitAction::RuntimeClassInitialize() noexcept + try { std::shared_ptr submitAction = std::make_shared(); @@ -18,7 +19,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveSubmitAction::RuntimeClassInitialize(const std::shared_ptr& sharedSubmitAction) try + HRESULT AdaptiveSubmitAction::RuntimeClassInitialize(const std::shared_ptr& sharedSubmitAction) + try { if (sharedSubmitAction == nullptr) { @@ -64,7 +66,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveSubmitAction::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveSubmitAction::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr submitAction = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveSubmitAction.h b/source/uwp/Renderer/lib/AdaptiveSubmitAction.h index 683ef0b7bc..a4097c9445 100644 --- a/source/uwp/Renderer/lib/AdaptiveSubmitAction.h +++ b/source/uwp/Renderer/lib/AdaptiveSubmitAction.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "SubmitAction.h" #include "AdaptiveActionElement.h" @@ -68,14 +66,8 @@ namespace AdaptiveNamespace } IFACEMETHODIMP put_IconUrl(_In_ HSTRING iconUrl) { return AdaptiveActionElementBase::put_IconUrl(iconUrl); } - IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) - { - return AdaptiveActionElementBase::get_Style(style); - } - IFACEMETHODIMP put_Style(_In_ HSTRING style) - { - return AdaptiveActionElementBase::put_Style(style); - } + IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) { return AdaptiveActionElementBase::get_Style(style); } + IFACEMETHODIMP put_Style(_In_ HSTRING style) { return AdaptiveActionElementBase::put_Style(style); } IFACEMETHODIMP get_AdditionalProperties(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result) { diff --git a/source/uwp/Renderer/lib/AdaptiveSubmitActionRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveSubmitActionRenderer.cpp index 54c341ed59..e1081f730d 100644 --- a/source/uwp/Renderer/lib/AdaptiveSubmitActionRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveSubmitActionRenderer.cpp @@ -4,16 +4,16 @@ #include "AdaptiveSubmitAction.h" #include "AdaptiveSubmitActionRenderer.h" -#include "Util.h" #include "AdaptiveElementParserRegistration.h" -#include "XamlBuilder.h" +#include "ActionHelpers.h" using namespace ABI::AdaptiveNamespace; using namespace Microsoft::WRL; namespace AdaptiveNamespace { - HRESULT AdaptiveSubmitActionRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveSubmitActionRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } @@ -22,9 +22,10 @@ namespace AdaptiveNamespace HRESULT AdaptiveSubmitActionRenderer::Render(_In_ IAdaptiveActionElement* action, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept + try { - return XamlBuilder::BuildAction(action, renderContext, renderArgs, result); + return ActionHelpers::BuildAction(action, renderContext, renderArgs, result); } CATCH_RETURN; @@ -33,7 +34,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveTextBlock.cpp b/source/uwp/Renderer/lib/AdaptiveTextBlock.cpp index 9670256b04..3bf1133309 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextBlock.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTextBlock.cpp @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveTextBlock.h" -#include "Util.h" #include "DateTimeParser.h" -#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -15,14 +14,16 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveTextBlock::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveTextBlock::RuntimeClassInitialize() noexcept + try { std::shared_ptr textBlock = std::make_shared(); return RuntimeClassInitialize(textBlock); } CATCH_RETURN; - HRESULT AdaptiveTextBlock::RuntimeClassInitialize(const std::shared_ptr& sharedTextBlock) try + HRESULT AdaptiveTextBlock::RuntimeClassInitialize(const std::shared_ptr& sharedTextBlock) + try { if (sharedTextBlock == nullptr) { @@ -81,7 +82,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveTextBlock::GetSharedModel(std::shared_ptr& sharedTextBlock) try + HRESULT AdaptiveTextBlock::GetSharedModel(std::shared_ptr& sharedTextBlock) + try { std::shared_ptr textBlock = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveTextBlock.h b/source/uwp/Renderer/lib/AdaptiveTextBlock.h index 6ed5d5a53d..d1ddec66bb 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextBlock.h +++ b/source/uwp/Renderer/lib/AdaptiveTextBlock.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "TextBlock.h" -#include "AdaptiveCardElement.h" #include "AdaptiveTextElement.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.cpp index 0ce9cca3ac..68b2a505bb 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.cpp @@ -5,29 +5,61 @@ #include "AdaptiveTextBlock.h" #include "AdaptiveTextBlockRenderer.h" #include "AdaptiveRenderContext.h" -#include "Util.h" -#include "XamlBuilder.h" #include "AdaptiveElementParserRegistration.h" +#include "TextHelpers.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveTextBlockRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveTextBlockRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveTextBlockRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveTextBlockRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** textBlockControl) noexcept + try { - return XamlBuilder::BuildTextBlock(cardElement, renderContext, renderArgs, result); + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveTextBlock; + RETURN_IF_FAILED(cardElement.As(&adaptiveTextBlock)); + + ComPtr xamlTextBlock = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock)); + + ComPtr adaptiveTextElement; + RETURN_IF_FAILED(adaptiveTextBlock.As(&adaptiveTextElement)); + + RETURN_IF_FAILED(StyleXamlTextBlockProperties(adaptiveTextBlock.Get(), renderContext, renderArgs, xamlTextBlock.Get())); + + ComPtr> inlines; + RETURN_IF_FAILED(xamlTextBlock->get_Inlines(&inlines)); + + RETURN_IF_FAILED(SetXamlInlines(adaptiveTextElement.Get(), renderContext, renderArgs, false, inlines.Get())); + + // Ensure left edge of text is consistent regardless of font size, so both small and large fonts + // are flush on the left edge of the card by enabling TrimSideBearings + ComPtr xamlTextBlock2; + RETURN_IF_FAILED(xamlTextBlock.As(&xamlTextBlock2)); + RETURN_IF_FAILED(xamlTextBlock2->put_OpticalMarginAlignment(OpticalMarginAlignment_TrimSideBearings)); + + ComPtr frameworkElement; + RETURN_IF_FAILED(xamlTextBlock.As(&frameworkElement)); + RETURN_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.TextBlock", frameworkElement.Get())); + + return xamlTextBlock.CopyTo(textBlockControl); } CATCH_RETURN; @@ -36,7 +68,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.h b/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.h index 58a4cb67b3..80e07aa00f 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveTextBlockRenderer.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "TextBlock.h" - namespace AdaptiveNamespace { class AdaptiveTextBlockRenderer diff --git a/source/uwp/Renderer/lib/AdaptiveTextConfig.cpp b/source/uwp/Renderer/lib/AdaptiveTextConfig.cpp index c542a978ba..48a49c76ec 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextConfig.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTextConfig.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "Util.h" + #include "AdaptiveTextConfig.h" using namespace Microsoft::WRL; @@ -9,7 +9,8 @@ using namespace ABI::AdaptiveNamespace; namespace AdaptiveNamespace { - HRESULT AdaptiveTextConfig::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveTextConfig::RuntimeClassInitialize() noexcept + try { TextConfig textConfig; return RuntimeClassInitialize(textConfig); diff --git a/source/uwp/Renderer/lib/AdaptiveTextConfig.h b/source/uwp/Renderer/lib/AdaptiveTextConfig.h index eddb5b3cd8..0a58e6686e 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextConfig.h +++ b/source/uwp/Renderer/lib/AdaptiveTextConfig.h @@ -2,10 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" -#include "HostConfig.h" - namespace AdaptiveNamespace { class AdaptiveTextConfig diff --git a/source/uwp/Renderer/lib/AdaptiveTextElement.cpp b/source/uwp/Renderer/lib/AdaptiveTextElement.cpp index 10afcfdbbc..8d5af88f4f 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextElement.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTextElement.cpp @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveTextElement.h" -#include "Util.h" #include "DateTimeParser.h" -#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; diff --git a/source/uwp/Renderer/lib/AdaptiveTextElement.h b/source/uwp/Renderer/lib/AdaptiveTextElement.h index 90d35fbce7..49e3728bea 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextElement.h +++ b/source/uwp/Renderer/lib/AdaptiveTextElement.h @@ -2,9 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" - namespace AdaptiveNamespace { class DECLSPEC_UUID("4BC6640A-8FBE-4DE0-81FD-119BC10877F1") AdaptiveTextElement : public IUnknown @@ -34,9 +31,8 @@ namespace AdaptiveNamespace IFACEMETHODIMP get_Underline(_Out_ boolean* underline); IFACEMETHODIMP put_Underline(_In_ boolean underline); - protected : template - HRESULT - InitializeTextElement(const std::shared_ptr& sharedModel) + protected: + template HRESULT InitializeTextElement(const std::shared_ptr& sharedModel) { m_subtle = sharedModel->GetIsSubtle(); m_fontType = static_cast(sharedModel->GetFontType()); diff --git a/source/uwp/Renderer/lib/AdaptiveTextInput.cpp b/source/uwp/Renderer/lib/AdaptiveTextInput.cpp index c519f41486..796528e732 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextInput.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTextInput.cpp @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveTextInput.h" -#include "Util.h" -#include +#include "AdaptiveTextInput.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -15,14 +13,16 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveTextInput::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveTextInput::RuntimeClassInitialize() noexcept + try { std::shared_ptr textInput = std::make_shared(); return RuntimeClassInitialize(textInput); } CATCH_RETURN; - HRESULT AdaptiveTextInput::RuntimeClassInitialize(const std::shared_ptr& sharedTextInput) try + HRESULT AdaptiveTextInput::RuntimeClassInitialize(const std::shared_ptr& sharedTextInput) + try { if (sharedTextInput == nullptr) { @@ -111,7 +111,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveTextInput::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveTextInput::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr textInput = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveTextInput.h b/source/uwp/Renderer/lib/AdaptiveTextInput.h index 94043b088a..1f934b7c5a 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextInput.h +++ b/source/uwp/Renderer/lib/AdaptiveTextInput.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "TextInput.h" #include "AdaptiveInputElement.h" diff --git a/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.cpp index 603d89841b..83453d9875 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.cpp @@ -5,29 +5,130 @@ #include "AdaptiveElementParserRegistration.h" #include "AdaptiveTextInput.h" #include "AdaptiveTextInputRenderer.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" +#include "ActionHelpers.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Input; namespace AdaptiveNamespace { - HRESULT AdaptiveTextInputRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveTextInputRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveTextInputRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveTextInputRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ IUIElement** textInputControl) noexcept + try { - return XamlBuilder::BuildTextInput(cardElement, renderContext, renderArgs, result); + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning( + ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"Text Input was stripped from card because interactivity is not supported").Get()); + return S_OK; + } + + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveTextInput; + RETURN_IF_FAILED(cardElement.As(&adaptiveTextInput)); + + ComPtr textBox = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBox)); + + boolean isMultiLine; + RETURN_IF_FAILED(adaptiveTextInput->get_IsMultiline(&isMultiLine)); + RETURN_IF_FAILED(textBox->put_AcceptsReturn(isMultiLine)); + + HString textValue; + RETURN_IF_FAILED(adaptiveTextInput->get_Value(textValue.GetAddressOf())); + RETURN_IF_FAILED(textBox->put_Text(textValue.Get())); + + UINT32 maxLength; + RETURN_IF_FAILED(adaptiveTextInput->get_MaxLength(&maxLength)); + RETURN_IF_FAILED(textBox->put_MaxLength(maxLength)); + + ComPtr textBox2; + RETURN_IF_FAILED(textBox.As(&textBox2)); + + HString placeHolderText; + RETURN_IF_FAILED(adaptiveTextInput->get_Placeholder(placeHolderText.GetAddressOf())); + RETURN_IF_FAILED(textBox2->put_PlaceholderText(placeHolderText.Get())); + + ABI::AdaptiveNamespace::TextInputStyle textInputStyle; + RETURN_IF_FAILED(adaptiveTextInput->get_TextInputStyle(&textInputStyle)); + + ComPtr inputScopeName = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Input_InputScopeName)); + switch (textInputStyle) + { + case ABI::AdaptiveNamespace::TextInputStyle::Email: + RETURN_IF_FAILED(inputScopeName->put_NameValue(InputScopeNameValue::InputScopeNameValue_EmailSmtpAddress)); + break; + + case ABI::AdaptiveNamespace::TextInputStyle::Tel: + RETURN_IF_FAILED(inputScopeName->put_NameValue(InputScopeNameValue::InputScopeNameValue_TelephoneNumber)); + break; + + case ABI::AdaptiveNamespace::TextInputStyle::Url: + RETURN_IF_FAILED(inputScopeName->put_NameValue(InputScopeNameValue::InputScopeNameValue_Url)); + break; + } + + ComPtr inputScope = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Input_InputScope)); + ComPtr> names; + RETURN_IF_FAILED(inputScope->get_Names(names.GetAddressOf())); + RETURN_IF_FAILED(names->Append(inputScopeName.Get())); + + RETURN_IF_FAILED(textBox->put_InputScope(inputScope.Get())); + + ComPtr textBoxAsUIElement; + textBox.As(&textBoxAsUIElement); + XamlHelpers::AddInputValueToContext(renderContext, adaptiveCardElement, textBoxAsUIElement.Get()); + + ComPtr inlineAction; + RETURN_IF_FAILED(adaptiveTextInput->get_InlineAction(&inlineAction)); + + ComPtr textBoxAsFrameworkElement; + RETURN_IF_FAILED(textBox.As(&textBoxAsFrameworkElement)); + RETURN_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.Input.Text", textBoxAsFrameworkElement.Get())); + + if (inlineAction != nullptr) + { + ComPtr textBoxWithInlineAction; + ActionHelpers::HandleInlineAction(renderContext, renderArgs, textBox.Get(), inlineAction.Get(), &textBoxWithInlineAction); + if (!isMultiLine) + { + RETURN_IF_FAILED(textBoxWithInlineAction.As(&textBoxAsFrameworkElement)); + RETURN_IF_FAILED(textBoxAsFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + } + + RETURN_IF_FAILED(textBoxWithInlineAction.CopyTo(textInputControl)); + } + else + { + if (!isMultiLine) + { + RETURN_IF_FAILED(textBoxAsFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + } + + RETURN_IF_FAILED(textBox.CopyTo(textInputControl)); + } + return S_OK; } CATCH_RETURN; @@ -36,7 +137,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.h b/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.h index 3ff97a3c3a..521d60b1a4 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveTextInputRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "TextInput.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveTextRun.cpp b/source/uwp/Renderer/lib/AdaptiveTextRun.cpp index d168a394e5..d2aef56e9f 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextRun.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTextRun.cpp @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveTextRun.h" -#include "Util.h" -#include using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -14,14 +13,16 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveTextRun::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveTextRun::RuntimeClassInitialize() noexcept + try { RuntimeClassInitialize(std::make_shared()); return S_OK; } CATCH_RETURN; - HRESULT AdaptiveTextRun::RuntimeClassInitialize(const std::shared_ptr& sharedTextRun) noexcept try + HRESULT AdaptiveTextRun::RuntimeClassInitialize(const std::shared_ptr& sharedTextRun) noexcept + try { m_highlight = sharedTextRun->GetHighlight(); m_italic = sharedTextRun->GetItalic(); @@ -93,7 +94,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveTextRun::GetSharedModel(std::shared_ptr& sharedModel) noexcept try + HRESULT AdaptiveTextRun::GetSharedModel(std::shared_ptr& sharedModel) noexcept + try { std::shared_ptr textRun = std::make_shared(); RETURN_IF_FAILED(AdaptiveTextElement::SetTextElementProperties(textRun)); diff --git a/source/uwp/Renderer/lib/AdaptiveTextRun.h b/source/uwp/Renderer/lib/AdaptiveTextRun.h index b60953de9a..206e4f0cac 100644 --- a/source/uwp/Renderer/lib/AdaptiveTextRun.h +++ b/source/uwp/Renderer/lib/AdaptiveTextRun.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "TextRun.h" #include "AdaptiveTextElement.h" diff --git a/source/uwp/Renderer/lib/AdaptiveTimeInput.cpp b/source/uwp/Renderer/lib/AdaptiveTimeInput.cpp index 0fb046e4d2..41f395244a 100644 --- a/source/uwp/Renderer/lib/AdaptiveTimeInput.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTimeInput.cpp @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveTimeInput.h" -#include "Util.h" -#include +#include "AdaptiveTimeInput.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -15,14 +13,16 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveTimeInput::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveTimeInput::RuntimeClassInitialize() noexcept + try { std::shared_ptr timeInput = std::make_shared(); return RuntimeClassInitialize(timeInput); } CATCH_RETURN; - HRESULT AdaptiveTimeInput::RuntimeClassInitialize(const std::shared_ptr& sharedTimeInput) try + HRESULT AdaptiveTimeInput::RuntimeClassInitialize(const std::shared_ptr& sharedTimeInput) + try { if (sharedTimeInput == nullptr) { @@ -65,7 +65,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveTimeInput::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveTimeInput::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr timeInput = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveTimeInput.h b/source/uwp/Renderer/lib/AdaptiveTimeInput.h index 6d575d6d20..b90ea43fbf 100644 --- a/source/uwp/Renderer/lib/AdaptiveTimeInput.h +++ b/source/uwp/Renderer/lib/AdaptiveTimeInput.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "TimeInput.h" #include "AdaptiveInputElement.h" diff --git a/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.cpp index 901593b979..b43bc05cbe 100644 --- a/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.cpp @@ -5,29 +5,68 @@ #include "AdaptiveElementParserRegistration.h" #include "AdaptiveTimeInput.h" #include "AdaptiveTimeInputRenderer.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveTimeInputRenderer::RuntimeClassInitialize() noexcept try - { - return S_OK; - } - CATCH_RETURN; + HRESULT AdaptiveTimeInputRenderer::RuntimeClassInitialize() noexcept { return S_OK; } - HRESULT AdaptiveTimeInputRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveTimeInputRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, - _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _In_ IAdaptiveRenderArgs* /*renderArgs*/, + _COM_Outptr_ IUIElement** timeInputControl) noexcept + try { - return XamlBuilder::BuildTimeInput(cardElement, renderContext, renderArgs, result); + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning( + ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"Time Input was stripped from card because interactivity is not supported").Get()); + return S_OK; + } + + ComPtr timePicker = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TimePicker)); + + // Make the picker stretch full width + ComPtr timePickerAsFrameworkElement; + RETURN_IF_FAILED(timePicker.As(&timePickerAsFrameworkElement)); + RETURN_IF_FAILED(timePickerAsFrameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment_Stretch)); + RETURN_IF_FAILED(timePickerAsFrameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + + RETURN_IF_FAILED(XamlHelpers::SetStyleFromResourceDictionary(renderContext, + L"Adaptive.Input.Time", + timePickerAsFrameworkElement.Get())); + + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveTimeInput; + RETURN_IF_FAILED(cardElement.As(&adaptiveTimeInput)); + + // Set initial value + HString hstringValue; + RETURN_IF_FAILED(adaptiveTimeInput->get_Value(hstringValue.GetAddressOf())); + std::string value = HStringToUTF8(hstringValue.Get()); + unsigned int hours, minutes; + if (DateTimePreparser::TryParseSimpleTime(value, hours, minutes)) + { + TimeSpan initialTime{(INT64)(hours * 60 + minutes) * 10000000 * 60}; + RETURN_IF_FAILED(timePicker->put_Time(initialTime)); + } + + // Note: Placeholder text and min/max are not supported by ITimePicker + + RETURN_IF_FAILED(timePicker.CopyTo(timeInputControl)); + XamlHelpers::AddInputValueToContext(renderContext, adaptiveCardElement, *timeInputControl); + return S_OK; } CATCH_RETURN; @@ -36,7 +75,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.h b/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.h index 1341204607..8d767c9f05 100644 --- a/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveTimeInputRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "TimeInput.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveToggleInput.cpp b/source/uwp/Renderer/lib/AdaptiveToggleInput.cpp index 3bf5d4230c..18da289825 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleInput.cpp +++ b/source/uwp/Renderer/lib/AdaptiveToggleInput.cpp @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" -#include "AdaptiveToggleInput.h" -#include "Util.h" -#include +#include "AdaptiveToggleInput.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -15,7 +13,8 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveToggleInput::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveToggleInput::RuntimeClassInitialize() noexcept + try { std::shared_ptr toggleInput = std::make_shared(); @@ -23,7 +22,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveToggleInput::RuntimeClassInitialize(const std::shared_ptr& sharedToggleInput) try + HRESULT AdaptiveToggleInput::RuntimeClassInitialize(const std::shared_ptr& sharedToggleInput) + try { if (sharedToggleInput == nullptr) { @@ -75,7 +75,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveToggleInput::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveToggleInput::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr toggleInput = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveToggleInput.h b/source/uwp/Renderer/lib/AdaptiveToggleInput.h index bccda9595d..8a467aea23 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleInput.h +++ b/source/uwp/Renderer/lib/AdaptiveToggleInput.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ToggleInput.h" #include "AdaptiveInputElement.h" diff --git a/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.cpp index 86e2fff100..4af51a19b2 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.cpp @@ -5,29 +5,80 @@ #include "AdaptiveElementParserRegistration.h" #include "AdaptiveToggleInput.h" #include "AdaptiveToggleInputRenderer.h" -#include "enums.h" -#include "Util.h" -#include "XamlBuilder.h" using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; +using namespace ABI::Windows::UI::Xaml::Controls::Primitives; namespace AdaptiveNamespace { - HRESULT AdaptiveToggleInputRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveToggleInputRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } CATCH_RETURN; - HRESULT AdaptiveToggleInputRenderer::Render(_In_ IAdaptiveCardElement* cardElement, + HRESULT AdaptiveToggleInputRenderer::Render(_In_ IAdaptiveCardElement* adaptiveCardElement, _In_ IAdaptiveRenderContext* renderContext, - _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _In_ IAdaptiveRenderArgs* /*renderArgs*/, + _COM_Outptr_ IUIElement** toggleInputControl) noexcept + try { - return XamlBuilder::BuildToggleInput(cardElement, renderContext, renderArgs, result); + ComPtr hostConfig; + RETURN_IF_FAILED(renderContext->get_HostConfig(&hostConfig)); + if (!XamlHelpers::SupportsInteractivity(hostConfig.Get())) + { + renderContext->AddWarning( + ABI::AdaptiveNamespace::WarningStatusCode::InteractivityNotSupported, + HStringReference(L"Toggle Input was stripped from card because interactivity is not supported").Get()); + return S_OK; + } + + ComPtr cardElement(adaptiveCardElement); + ComPtr adaptiveToggleInput; + RETURN_IF_FAILED(cardElement.As(&adaptiveToggleInput)); + + ComPtr checkBox = + XamlHelpers::CreateXamlClass(HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_CheckBox)); + + HString title; + RETURN_IF_FAILED(adaptiveToggleInput->get_Title(title.GetAddressOf())); + + boolean wrap; + adaptiveToggleInput->get_Wrap(&wrap); + + XamlHelpers::SetContent(checkBox.Get(), title.Get(), wrap); + + HString value; + RETURN_IF_FAILED(adaptiveToggleInput->get_Value(value.GetAddressOf())); + + HString valueOn; + RETURN_IF_FAILED(adaptiveToggleInput->get_ValueOn(valueOn.GetAddressOf())); + + INT32 compareValueOn; + RETURN_IF_FAILED(WindowsCompareStringOrdinal(value.Get(), valueOn.Get(), &compareValueOn)); + + XamlHelpers::SetToggleValue(checkBox.Get(), (compareValueOn == 0)); + + ComPtr checkboxAsUIElement; + RETURN_IF_FAILED(checkBox.As(&checkboxAsUIElement)); + RETURN_IF_FAILED(XamlHelpers::AddHandledTappedEvent(checkboxAsUIElement.Get())); + + ComPtr frameworkElement; + RETURN_IF_FAILED(checkBox.As(&frameworkElement)); + RETURN_IF_FAILED(frameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment_Top)); + RETURN_IF_FAILED( + XamlHelpers::SetStyleFromResourceDictionary(renderContext, L"Adaptive.Input.Toggle", frameworkElement.Get())); + + RETURN_IF_FAILED(checkboxAsUIElement.CopyTo(toggleInputControl)); + XamlHelpers::AddInputValueToContext(renderContext, adaptiveCardElement, *toggleInputControl); + return S_OK; } CATCH_RETURN; @@ -36,7 +87,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveCardElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.h b/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.h index 6c00c89410..49ac2feab6 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.h +++ b/source/uwp/Renderer/lib/AdaptiveToggleInputRenderer.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ToggleInput.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.cpp b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.cpp index db9d4df968..5bee2ca457 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.cpp +++ b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.cpp @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveToggleVisibilityAction.h" -#include "Util.h" -#include "Vector.h" using namespace Microsoft::WRL; using namespace ABI::AdaptiveNamespace; @@ -12,7 +11,8 @@ using namespace ABI::Windows::Foundation::Collections; namespace AdaptiveNamespace { - HRESULT AdaptiveToggleVisibilityAction::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveToggleVisibilityAction::RuntimeClassInitialize() noexcept + try { std::shared_ptr toggleVisibilityAction = std::make_shared(); @@ -20,8 +20,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveToggleVisibilityAction::RuntimeClassInitialize( - const std::shared_ptr& sharedToggleVisibilityAction) try + HRESULT AdaptiveToggleVisibilityAction::RuntimeClassInitialize(const std::shared_ptr& sharedToggleVisibilityAction) + try { if (sharedToggleVisibilityAction == nullptr) { @@ -47,7 +47,8 @@ namespace AdaptiveNamespace return m_targetElements.CopyTo(targetElements); } - HRESULT AdaptiveToggleVisibilityAction::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveToggleVisibilityAction::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr toggleVisibilityAction = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.h b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.h index a74841fc9e..bc9e7c7d9d 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.h +++ b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityAction.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ToggleVisibilityAction.h" #include "AdaptiveActionElement.h" @@ -65,14 +63,8 @@ namespace AdaptiveNamespace } IFACEMETHODIMP put_IconUrl(_In_ HSTRING iconUrl) { return AdaptiveActionElementBase::put_IconUrl(iconUrl); } - IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) - { - return AdaptiveActionElementBase::get_Style(style); - } - IFACEMETHODIMP put_Style(_In_ HSTRING style) - { - return AdaptiveActionElementBase::put_Style(style); - } + IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) { return AdaptiveActionElementBase::get_Style(style); } + IFACEMETHODIMP put_Style(_In_ HSTRING style) { return AdaptiveActionElementBase::put_Style(style); } IFACEMETHODIMP get_AdditionalProperties(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result) { diff --git a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityActionRenderer.cpp b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityActionRenderer.cpp index b4a81db52e..4a38f97afd 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityActionRenderer.cpp +++ b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityActionRenderer.cpp @@ -4,16 +4,16 @@ #include "AdaptiveToggleVisibilityAction.h" #include "AdaptiveToggleVisibilityActionRenderer.h" -#include "Util.h" #include "AdaptiveElementParserRegistration.h" -#include "XamlBuilder.h" +#include "ActionHelpers.h" using namespace ABI::AdaptiveNamespace; using namespace Microsoft::WRL; namespace AdaptiveNamespace { - HRESULT AdaptiveToggleVisibilityActionRenderer::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveToggleVisibilityActionRenderer::RuntimeClassInitialize() noexcept + try { return S_OK; } @@ -22,9 +22,10 @@ namespace AdaptiveNamespace HRESULT AdaptiveToggleVisibilityActionRenderer::Render(_In_ IAdaptiveActionElement* action, _In_ IAdaptiveRenderContext* renderContext, _In_ IAdaptiveRenderArgs* renderArgs, - _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept try + _COM_Outptr_ ABI::Windows::UI::Xaml::IUIElement** result) noexcept + try { - return XamlBuilder::BuildAction(action, renderContext, renderArgs, result); + return ActionHelpers::BuildAction(action, renderContext, renderArgs, result); } CATCH_RETURN; @@ -33,7 +34,8 @@ namespace AdaptiveNamespace _In_ ABI::AdaptiveNamespace::IAdaptiveElementParserRegistration* elementParserRegistration, _In_ ABI::AdaptiveNamespace::IAdaptiveActionParserRegistration* actionParserRegistration, _In_ ABI::Windows::Foundation::Collections::IVector* adaptiveWarnings, - _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept try + _COM_Outptr_ ABI::AdaptiveNamespace::IAdaptiveActionElement** element) noexcept + try { return AdaptiveNamespace::FromJson( jsonObject, elementParserRegistration, actionParserRegistration, adaptiveWarnings, element); diff --git a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.cpp b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.cpp index 0a81a2509e..7d29e82642 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.cpp +++ b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.cpp @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" + #include "AdaptiveToggleVisibilityTarget.h" -#include "Util.h" -#include #include "ToggleVisibilityTarget.h" using namespace Microsoft::WRL; @@ -15,7 +14,8 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveToggleVisibilityTarget::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveToggleVisibilityTarget::RuntimeClassInitialize() noexcept + try { RuntimeClassInitialize(std::make_shared()); return S_OK; @@ -45,7 +45,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveToggleVisibilityTarget::GetSharedModel(std::shared_ptr& sharedModel) try + HRESULT AdaptiveToggleVisibilityTarget::GetSharedModel(std::shared_ptr& sharedModel) + try { std::shared_ptr toggleTarget = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.h b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.h index 5dc2276409..1fd170baed 100644 --- a/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.h +++ b/source/uwp/Renderer/lib/AdaptiveToggleVisibilityTarget.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "ToggleVisibilityTarget.h" namespace AdaptiveNamespace diff --git a/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.cpp b/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.cpp index b43a4f7e61..eadcf2e3ff 100644 --- a/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.cpp +++ b/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.cpp @@ -3,13 +3,13 @@ #include "pch.h" #include "AdaptiveUnsupportedAction.h" -#include "Util.h" using namespace Microsoft::WRL::Wrappers; namespace AdaptiveNamespace { - HRESULT AdaptiveUnsupportedAction::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveUnsupportedAction::RuntimeClassInitialize() noexcept + try { std::shared_ptr unknownAction = std::make_shared(); @@ -17,7 +17,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveUnsupportedAction::RuntimeClassInitialize(const std::shared_ptr& sharedUnknown) try + HRESULT AdaptiveUnsupportedAction::RuntimeClassInitialize(const std::shared_ptr& sharedUnknown) + try { if (sharedUnknown == nullptr) { @@ -35,7 +36,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveUnsupportedAction::GetSharedModel(std::shared_ptr& sharedUnknown) try + HRESULT AdaptiveUnsupportedAction::GetSharedModel(std::shared_ptr& sharedUnknown) + try { std::shared_ptr unknownAction = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.h b/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.h index 88b0d8799a..c9c5292a8c 100644 --- a/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.h +++ b/source/uwp/Renderer/lib/AdaptiveUnsupportedAction.h @@ -2,8 +2,6 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "UnknownAction.h" #include "AdaptiveActionElement.h" @@ -60,14 +58,8 @@ namespace AdaptiveNamespace } IFACEMETHODIMP put_IconUrl(_In_ HSTRING iconUrl) { return AdaptiveActionElementBase::put_IconUrl(iconUrl); } - IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) - { - return AdaptiveActionElementBase::get_Style(style); - } - IFACEMETHODIMP put_Style(_In_ HSTRING style) - { - return AdaptiveActionElementBase::put_Style(style); - } + IFACEMETHODIMP get_Style(_Outptr_ HSTRING* style) { return AdaptiveActionElementBase::get_Style(style); } + IFACEMETHODIMP put_Style(_In_ HSTRING style) { return AdaptiveActionElementBase::put_Style(style); } IFACEMETHODIMP get_AdditionalProperties(_COM_Outptr_ ABI::Windows::Data::Json::IJsonObject** result) { diff --git a/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.cpp b/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.cpp index d57d339485..a7ba4d905d 100644 --- a/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.cpp +++ b/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.cpp @@ -4,9 +4,6 @@ #include "AdaptiveUnsupportedElement.h" -#include "Util.h" -#include - using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::AdaptiveNamespace; @@ -16,7 +13,8 @@ using namespace ABI::Windows::UI::Xaml::Controls; namespace AdaptiveNamespace { - HRESULT AdaptiveUnsupportedElement::RuntimeClassInitialize() noexcept try + HRESULT AdaptiveUnsupportedElement::RuntimeClassInitialize() noexcept + try { std::shared_ptr unknownElement = std::make_shared(); @@ -24,7 +22,8 @@ namespace AdaptiveNamespace } CATCH_RETURN; - HRESULT AdaptiveUnsupportedElement::RuntimeClassInitialize(const std::shared_ptr& sharedUnknown) try + HRESULT AdaptiveUnsupportedElement::RuntimeClassInitialize(const std::shared_ptr& sharedUnknown) + try { if (sharedUnknown == nullptr) { @@ -43,7 +42,8 @@ namespace AdaptiveNamespace return S_OK; } - HRESULT AdaptiveUnsupportedElement::GetSharedModel(std::shared_ptr& sharedUnknown) try + HRESULT AdaptiveUnsupportedElement::GetSharedModel(std::shared_ptr& sharedUnknown) + try { std::shared_ptr unknownElement = std::make_shared(); diff --git a/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.h b/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.h index a753576e7c..b9d9b31790 100644 --- a/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.h +++ b/source/uwp/Renderer/lib/AdaptiveUnsupportedElement.h @@ -2,10 +2,7 @@ // Licensed under the MIT License. #pragma once -#include "AdaptiveCards.Rendering.Uwp.h" -#include "Enums.h" #include "UnknownElement.h" -#include "AdaptiveCardElement.h" namespace AdaptiveNamespace { diff --git a/source/uwp/Renderer/lib/AsyncOperations.h b/source/uwp/Renderer/lib/AsyncOperations.h index ff72a507d2..38a6670e0d 100644 --- a/source/uwp/Renderer/lib/AsyncOperations.h +++ b/source/uwp/Renderer/lib/AsyncOperations.h @@ -40,7 +40,7 @@ class RenderAsyncBase bool explicitDimensions = m_renderer->GetFixedDimensions(&width, &height); if (explicitDimensions) { - THROW_IF_FAILED(m_renderer->GetXamlBuilder()->SetFixedDimensions(width, height)); + m_renderer->GetXamlBuilder()->SetFixedDimensions(width, height); } } @@ -104,9 +104,9 @@ class RenderAsyncBase m_renderResult.Get())); AdaptiveNamespace::XamlBuilder::BuildXamlTreeFromAdaptiveCard(m_card.Get(), - &m_rootXamlElement, - renderContext.Get(), - m_renderer->GetXamlBuilder()); + &m_rootXamlElement, + renderContext.Get(), + m_renderer->GetXamlBuilder()); } catch (...) { @@ -114,8 +114,7 @@ class RenderAsyncBase return XamlBuilderHadError(); } return S_OK; - }) - .Get(), + }).Get(), &dispatcherAsyncAction); dispatcherAsyncAction->put_Completed( diff --git a/source/uwp/Renderer/lib/DefaultResourceDictionary.h b/source/uwp/Renderer/lib/DefaultResourceDictionary.h index 5edfdd2ead..bb62118816 100644 --- a/source/uwp/Renderer/lib/DefaultResourceDictionary.h +++ b/source/uwp/Renderer/lib/DefaultResourceDictionary.h @@ -68,7 +68,6 @@ const PCWSTR c_defaultResourceDictionary = L"\ \ " - "