diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.cpp b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.cpp index 592d7f3ea..a878329f1 100644 --- a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.cpp +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.cpp @@ -14,6 +14,7 @@ namespace winrt::DrawingIslandComponents::implementation const winrt::Compositor& compositor) { m_output.Compositor = compositor; + m_output.TextRenderer = std::make_shared(m_output.Compositor); // Create the Compositor and the Content: // - The Bridge's connection to the Window will keep everything alive, and perform an @@ -75,7 +76,8 @@ namespace winrt::DrawingIslandComponents::implementation m_background.Visual = nullptr; m_items.Visuals = nullptr; - m_items.SelectedVisual = nullptr; + m_items.Items.clear(); + m_items.SelectedItem = nullptr; // TODO: Enable Mica on Win 11 #if FALSE @@ -234,11 +236,13 @@ namespace winrt::DrawingIslandComponents::implementation winrt::Windows::Graphics::RectInt32 screenRect{ static_cast(x + 0.5), static_cast(y + 0.5), 0, 0 }; auto logicalRect = m_island.CoordinateConverter().ConvertScreenToLocal(screenRect); float2 localPoint{ logicalRect.X, logicalRect.Y }; - auto hitTestVisual = HitTestVisual(localPoint); + auto hitTestElement = HitTestItem(localPoint); // Find the automation peer for the hit test visual if any. - if (nullptr != hitTestVisual) + if (nullptr != hitTestElement) { + auto& hitTestVisual = hitTestElement->GetVisual(); + auto iterator = std::find_if( m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [&hitTestVisual](auto const& automationPeer) { @@ -259,30 +263,36 @@ namespace winrt::DrawingIslandComponents::implementation winrt::com_ptr DrawingIsland::GetFragmentInFocus() const { - // Find the currently selected visual's automation peer. - auto iterator = std::find_if( - m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual = m_items.SelectedVisual](auto const& automationPeer) - { - return automationPeer.Match(visual); - }); - - if (m_uia.AutomationPeers.end() != iterator) + if (m_items.SelectedItem != nullptr) { - // Return the automation provider if we found an automation peer for the selected visual. - return iterator->GetAutomationProvider().as(); + auto& visual = m_items.SelectedItem->GetVisual(); + + // Find the currently selected visual's automation peer. + auto iterator = std::find_if( + m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual](auto const& automationPeer) + { + return automationPeer.Match(visual); + }); + + if (m_uia.AutomationPeers.end() != iterator) + { + // Return the automation provider if we found an automation peer for the selected visual. + return iterator->GetAutomationProvider().as(); + } } return nullptr; } - winrt::Visual - DrawingIsland::HitTestVisual( - float2 const& point) const + Item* DrawingIsland::HitTestItem(float2 const& point) const { - winrt::Visual selectedVisual{ nullptr }; - for (winrt::Visual visual : m_items.Visuals) + // Iterate from the end of the vector, i.e., from front to back. + for (size_t i = m_items.Items.size(); i != 0; i--) { + Item* item = m_items.Items[i - 1].get(); + auto& visual = item->GetVisual(); + winrt::float3 const offset = visual.Offset(); float2 const size = visual.Size(); @@ -291,11 +301,10 @@ namespace winrt::DrawingIslandComponents::implementation point.y >= offset.y && point.y < offset.y + size.y) { - selectedVisual = visual; + return item; } } - - return selectedVisual; + return nullptr; } @@ -507,6 +516,7 @@ namespace winrt::DrawingIslandComponents::implementation case winrt::Windows::System::VirtualKey::Escape: { m_items.Visuals.RemoveAll(); + m_items.Items.clear(); // Update accessibility. m_uia.FragmentRoot->RemoveAllChildren(); @@ -581,7 +591,7 @@ namespace winrt::DrawingIslandComponents::implementation void DrawingIsland::Input_OnPointerReleased() { - m_items.SelectedVisual = nullptr; + m_items.SelectedItem = nullptr; } @@ -608,22 +618,39 @@ namespace winrt::DrawingIslandComponents::implementation const float2 point, bool controlPressed) { - m_items.SelectedVisual = HitTestVisual(point); + m_items.SelectedItem = HitTestItem(point); - if (m_items.SelectedVisual) + if (m_items.SelectedItem != nullptr) { - winrt::float3 const offset = m_items.SelectedVisual.Offset(); + Item* item = m_items.SelectedItem; + auto& visual = m_items.SelectedItem->GetVisual(); + winrt::float3 const offset = visual.Offset(); m_items.Offset.x = offset.x - point.x; m_items.Offset.y = offset.y - point.y; - m_items.Visuals.Remove(m_items.SelectedVisual); - m_items.Visuals.InsertAtTop(m_items.SelectedVisual); + // Move the visual to the top. + m_items.Visuals.Remove(visual); + m_items.Visuals.InsertAtTop(visual); + + // Move the VisualElement to the end of the vector if it isn't already. + if (!m_items.Items.empty() && m_items.Items.back().get() != item) + { + auto i = std::find_if( + m_items.Items.begin(), + m_items.Items.end(), + [item](auto& elem) { return elem.get() == item; } + ); + if (i != m_items.Items.end()) + { + std::rotate(i, i + 1, m_items.Items.end()); + } + } // Update automation. // First find the existing automation peer. auto iterator = std::find_if( - m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual = m_items.SelectedVisual](auto const& automationPeer) + m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual](auto const& automationPeer) { return automationPeer.Match(visual); }); @@ -651,18 +678,21 @@ namespace winrt::DrawingIslandComponents::implementation void DrawingIsland::OnRightClick(const float2 point) { - winrt::Visual selectedVisual = HitTestVisual(point); + // TODO - what is the purpose of this? + UNREFERENCED_PARAMETER(point); + // VisualElement* selectedVisual = HitTestVisual(point); } void DrawingIsland::Input_OnPointerMoved( const winrt::PointerEventArgs& args) { - if (m_items.SelectedVisual) + if (m_items.SelectedItem) { + auto& visual = m_items.SelectedItem->GetVisual(); float2 const point = args.CurrentPoint().Position(); - m_items.SelectedVisual.Offset( + visual.Offset( { point.x + m_items.Offset.x, point.y + m_items.Offset.y, 0.0f }); @@ -682,7 +712,16 @@ namespace winrt::DrawingIslandComponents::implementation { if (m_prevState.RasterizationScale != m_island.RasterizationScale()) { - m_prevState.RasterizationScale = m_island.RasterizationScale(); + float newScale = m_island.RasterizationScale(); + + m_prevState.RasterizationScale = newScale; + + m_output.TextRenderer->SetDpiScale(newScale); + + for (auto& item : m_items.Items) + { + item->OnDpiScaleChanged(); + } } if (m_prevState.LayoutDirection != m_island.LayoutDirection()) @@ -746,20 +785,39 @@ namespace winrt::DrawingIslandComponents::implementation float2 const point, bool halfTransparent) { - winrt::SpriteVisual visual = m_output.Compositor.CreateSpriteVisual(); - visual.Brush(halfTransparent ? - m_output.HalfTransparentColorBrushes[m_output.CurrentColorIndex] : - m_output.ColorBrushes[m_output.CurrentColorIndex]); + // Determine the visual background and text colors. + Color backgroundColor = s_colors[m_output.CurrentColorIndex]; + Color textColor = { 0xFF, 0, 0, 0 }; + if (halfTransparent) + { + backgroundColor.A /= 2; + textColor.A /= 2; + } + + // Create a TextElement object. + auto textItem = std::make_unique( + m_output.TextRenderer, + backgroundColor, + textColor, + s_colorNames[m_output.CurrentColorIndex] + ); + + // Get the visual and its size in DIPs. + auto& visual = textItem->GetVisual(); + float2 size = visual.Size(); + + // Set the visual's offset. + visual.Offset({ point.x - size.x / 2.0f, point.y - size.y / 2.0f, 0.0f }); - float const BlockSize = 30.0f; - visual.Size({ BlockSize, BlockSize }); - visual.Offset({ point.x - BlockSize / 2.0f, point.y - BlockSize / 2.0f, 0.0f }); + // Add the new text element to the vector. + m_items.Items.push_back(std::move(textItem)); + // Add the visual as a child of the container visual. m_items.Visuals.InsertAtTop(visual); - m_items.SelectedVisual = visual; - m_items.Offset.x = -BlockSize / 2.0f; - m_items.Offset.y = -BlockSize / 2.0f; + m_items.SelectedItem = m_items.Items.back().get(); + m_items.Offset.x = -size.x / 2.0f; + m_items.Offset.y = -size.y / 2.0f; Accessibility_CreateItemFragment(visual); } diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.h b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.h index 33aff4348..423267019 100644 --- a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.h +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.h @@ -5,6 +5,8 @@ #include "DrawingIsland.g.h" #include "IslandFragmentRoot.h" +#include "TextRenderer.h" +#include "TextItem.h" namespace winrt::DrawingIslandComponents::implementation { @@ -90,8 +92,7 @@ namespace winrt::DrawingIslandComponents::implementation winrt::com_ptr GetFragmentInFocus() const override; private: - winrt::Visual HitTestVisual( - float2 const& point) const; + Item* HitTestItem(float2 const& point) const; void Accessibility_Initialize(); @@ -194,6 +195,8 @@ namespace winrt::DrawingIslandComponents::implementation { winrt::Compositor Compositor{ nullptr }; + std::shared_ptr TextRenderer; + // Current color used for new items unsigned int CurrentColorIndex = 0; @@ -243,10 +246,22 @@ namespace winrt::DrawingIslandComponents::implementation // Drawing items being manipulated. struct { + // The container visual's Children collection. Each Item's visual must be + // added to this collection to be rendered. winrt::VisualCollection Visuals{ nullptr }; - winrt::Visual SelectedVisual{ nullptr }; - winrt::SpriteVisual CurrentColorVisual{ nullptr }; + + // Vector of Item objects representing items that can be manipulated, in + // back-to-front order. Each item has an associated Visual. + std::vector> Items; + + // Pointer to the currently-selected item, if any. + Item* SelectedItem{ nullptr }; + + // Offset from the top-left corner of the selected item to the pointer. float2 Offset{}; + + // Visual that shows the current color. + winrt::SpriteVisual CurrentColorVisual{ nullptr }; } m_items; struct diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj index b5adf9beb..0f425d9a0 100644 --- a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj @@ -131,6 +131,9 @@ Components.idl + + + @@ -142,6 +145,9 @@ Components.idl + + + diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj.filters b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj.filters index 0f4a66f97..876a50f7b 100644 --- a/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj.filters +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj.filters @@ -24,6 +24,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -33,6 +42,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/Item.cpp b/Samples/Islands/DrawingIsland/DrawingIslandComponents/Item.cpp new file mode 100644 index 000000000..4e28b475e --- /dev/null +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/Item.cpp @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "Item.h" + +namespace winrt::DrawingIslandComponents::implementation +{ + Item::Item(winrt::Compositor const& compositor) : + m_visual(compositor.CreateSpriteVisual()) + { + } +} diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/Item.h b/Samples/Islands/DrawingIsland/DrawingIslandComponents/Item.h new file mode 100644 index 000000000..0a05b3156 --- /dev/null +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/Item.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +namespace winrt::DrawingIslandComponents::implementation +{ + // Abstract base class for an item that owns a SpriteVisual and can + // re-rasterize the sprite if the DPI changes. + class Item + { + public: + Item(winrt::Compositor const& compositor); + + virtual ~Item() + { + } + + virtual void OnDpiScaleChanged() + { + } + + winrt::SpriteVisual const& GetVisual() const noexcept + { + return m_visual; + } + + private: + winrt::SpriteVisual m_visual; + }; +} diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.cpp b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.cpp new file mode 100644 index 000000000..cef6766b5 --- /dev/null +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.cpp @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "TextItem.h" + +namespace winrt::DrawingIslandComponents::implementation +{ + TextItem::TextItem( + std::shared_ptr const& textRenderer, + Windows::UI::Color backgroundColor, + Windows::UI::Color textColor, + std::wstring const& text) : + Item(textRenderer->GetCompositor()), + m_textRenderer(textRenderer), + m_backgroundColor(backgroundColor), + m_textColor(textColor), + m_text(text) + { + InitializeVisual(); + } + + void TextItem::InitializeVisual() + { + // Render the text to the sprite visual. + m_textRenderer->Render(m_text.c_str(), m_backgroundColor, m_textColor, GetVisual()); + } + + void TextItem::OnDpiScaleChanged() + { + // Re-render the text using the current DPI scale. + InitializeVisual(); + } +} diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.h b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.h new file mode 100644 index 000000000..6bd5a770f --- /dev/null +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextItem.h @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "TextRenderer.h" +#include "Item.h" + +namespace winrt::DrawingIslandComponents::implementation +{ + class TextItem final : public Item + { + public: + TextItem( + std::shared_ptr const& textRenderer, + Windows::UI::Color backgroundColor, + Windows::UI::Color textColor, + std::wstring const& text); + + void OnDpiScaleChanged() override; + + private: + void InitializeVisual(); + + std::shared_ptr m_textRenderer; + Windows::UI::Color m_backgroundColor; + Windows::UI::Color m_textColor; + std::wstring m_text; + }; +} diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextRenderer.cpp b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextRenderer.cpp new file mode 100644 index 000000000..32b6aa618 --- /dev/null +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextRenderer.cpp @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" +#include "TextRenderer.h" + +namespace winrt::DrawingIslandComponents::implementation +{ + TextRenderer::TextRenderer(winrt::Compositor compositor) : m_compositor(compositor) + { + // Create the DWrite factory object. + winrt::check_hresult(DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(decltype(*m_dwriteFactory)), + reinterpret_cast<::IUnknown**>(m_dwriteFactory.put()))); + + // Create an object that encapsulates text formatting properties. + constexpr float defaultFontSize = 16; + winrt::check_hresult(m_dwriteFactory->CreateTextFormat( + L"Segoe UI", + nullptr, + DWRITE_FONT_WEIGHT_NORMAL, + DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + defaultFontSize, + L"en-US", + m_textFormat.put())); + winrt::check_hresult(m_textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP)); + + // Create the D2D factory. + winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, m_d2dFactory.put())); + } + + void TextRenderer::ClearGraphicsDevice() + { + m_d2dDevice = nullptr; + m_compositionGraphicsDevice = nullptr; + } + + void TextRenderer::CreateGraphicsDevice() + { + uint32_t createDeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + + // Array with DirectX hardware feature levels in order of preference. + static const D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + // Create the Direct3D 11 API device object and a corresponding context. + winrt::com_ptr<::ID3D11Device> d3dDevice; + winrt::com_ptr<::ID3D11DeviceContext> d3dImmediateContext; + D3D_FEATURE_LEVEL d3dFeatureLevel{ D3D_FEATURE_LEVEL_9_1 }; + + winrt::check_hresult(D3D11CreateDevice( + nullptr, // Default adapter. + D3D_DRIVER_TYPE_HARDWARE, + 0, // Not asking for a software driver, so not passing a module to one. + createDeviceFlags, // Set debug and Direct2D compatibility flags. + featureLevels, + ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, + d3dDevice.put(), + &d3dFeatureLevel, + d3dImmediateContext.put())); + + // Initialize Direct2D resources. + D2D1_FACTORY_OPTIONS d2d1FactoryOptions{ D2D1_DEBUG_LEVEL_NONE }; + + // Create the Direct2D device object. + // Obtain the underlying DXGI device of the Direct3D device. + auto dxgiDevice = d3dDevice.as<::IDXGIDevice>(); + + winrt::com_ptr d2dDevice; + winrt::check_hresult(m_d2dFactory->CreateDevice(dxgiDevice.get(), d2dDevice.put())); + + // Create the composition graphics device. + auto compositorInterop = m_compositor.as(); + winrt::Microsoft::UI::Composition::ICompositionGraphicsDevice compositionGraphicsDevice; + winrt::check_hresult(compositorInterop->CreateGraphicsDevice(d2dDevice.get(), &compositionGraphicsDevice)); + + // Save the newly-created objects. + m_compositionGraphicsDevice = compositionGraphicsDevice.as(); + m_d2dDevice = std::move(d2dDevice); + } + + void TextRenderer::Render( + _In_z_ WCHAR const* text, + Windows::UI::Color backgroundColor, + Windows::UI::Color textColor, + SpriteVisual const& visual) + { + // Margins between the layout bounds of the text and the edges of the visual. + // These are in device-independent pixels (DIPs). + constexpr float marginLeft = 5; + constexpr float marginRight = 5; + constexpr float marginTop = 5; + constexpr float marginBottom = 5; + + // Create the IDWriteTextlayout object. This will be used to render the text + // and can also be used to get properties, such as the size. + winrt::com_ptr textLayout; + winrt::check_hresult(m_dwriteFactory->CreateTextLayout( + text, + static_cast(wcslen(text)), + m_textFormat.get(), + /*maxWidth*/ 0, + /*maxHeight*/ 0, + /*out*/ textLayout.put())); + + // Get the metrics from the text layout, and add the margins to compute the + // width and height of the visual. + DWRITE_TEXT_METRICS textMetrics; + winrt::check_hresult(textLayout->GetMetrics(/*out*/ &textMetrics)); + const float width = textMetrics.width + (marginLeft + marginRight); + const float height = textMetrics.height + (marginTop + marginBottom); + + visual.Size(float2(width, height)); + + // Initialize the graphics objects if we haven't already. + if (m_compositionGraphicsDevice == nullptr) + { + CreateGraphicsDevice(); + } + + // Create a composition surface to draw to. + CompositionDrawingSurface drawingSurface = m_compositionGraphicsDevice.CreateDrawingSurface( + winrt::Windows::Foundation::Size(width * m_dpiScale, height * m_dpiScale), + winrt::Microsoft::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized, + winrt::Microsoft::Graphics::DirectX::DirectXAlphaMode::Premultiplied); + auto drawingSurfaceInterop = drawingSurface.as(); + + // Begin drawing to get a Direct2D device context. + winrt::com_ptr deviceContext; + POINT pixelOffset; + winrt::check_hresult(drawingSurfaceInterop->BeginDraw( + nullptr, + __uuidof(ID2D1DeviceContext), + deviceContext.put_void(), + &pixelOffset)); + + // Set the DPI of the device context, where 96 DPI corresponds to a 1.0 scale factor. + deviceContext->SetDpi(m_dpiScale * 96, m_dpiScale * 96); + + // Compute the origin (top-left corner) of the text layout in DIPs by converting + // the drawing surface offset from pixels to DIPs and adding the margin. + D2D_POINT_2F origin{ + pixelOffset.x / m_dpiScale + marginLeft, + pixelOffset.y / m_dpiScale + marginTop }; + + // Clear the background and draw the text. + deviceContext->Clear(ToColorF(backgroundColor)); + + // Use ClearType antialiasing if rendering onto an opaque background. + // Otherwise use grayscale. + deviceContext->SetTextAntialiasMode( + backgroundColor.A == 255 ? + D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE : + D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); + + // Create the brush used to fill the text. + winrt::com_ptr textBrush; + winrt::check_hresult(deviceContext->CreateSolidColorBrush(ToColorF(textColor), textBrush.put())); + + // Draw the text layout object. + deviceContext->DrawTextLayout(origin, textLayout.get(), textBrush.get()); + + // End drawing. + winrt::check_hresult(drawingSurfaceInterop->EndDraw()); + + // Create the surface brush and set it as the visual's brush. + auto surfaceBrush = m_compositor.CreateSurfaceBrush(); + surfaceBrush.Surface(drawingSurface); + visual.Brush(surfaceBrush); + } +} diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextRenderer.h b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextRenderer.h new file mode 100644 index 000000000..66fb4d174 --- /dev/null +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/TextRenderer.h @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +namespace winrt::DrawingIslandComponents::implementation +{ + class TextRenderer final + { + public: + TextRenderer(winrt::Compositor compositor); + + void SetDpiScale(float scale) + { + m_dpiScale = scale; + } + + void Render( + _In_z_ WCHAR const* text, + Windows::UI::Color backgroundColor, + Windows::UI::Color textColor, + SpriteVisual const& visual); + + winrt::Compositor const& GetCompositor() const noexcept + { + return m_compositor; + } + + private: + static inline D2D_COLOR_F ToColorF(Windows::UI::Color color) + { + return D2D_COLOR_F{ color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f }; + } + + void ClearGraphicsDevice(); + void CreateGraphicsDevice(); + + winrt::Compositor m_compositor; + + // Device-independent resources. + winrt::com_ptr m_dwriteFactory; + winrt::com_ptr m_textFormat; + winrt::com_ptr m_d2dFactory; + + // Device-dependent resources. + winrt::com_ptr m_d2dDevice; + CompositionGraphicsDevice m_compositionGraphicsDevice{ nullptr }; + + float m_dpiScale = 1.0f; + }; +} diff --git a/Samples/Islands/DrawingIsland/DrawingIslandComponents/pch.h b/Samples/Islands/DrawingIsland/DrawingIslandComponents/pch.h index 36f4181b2..73801a8fd 100644 --- a/Samples/Islands/DrawingIsland/DrawingIslandComponents/pch.h +++ b/Samples/Islands/DrawingIsland/DrawingIslandComponents/pch.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,12 @@ #include +// DWriteWrite and Direct2D for rendering text +#include +#include +#include +#include + namespace winrt { using namespace winrt::Windows::Foundation;