Skip to content

Commit 90fed17

Browse files
authored
User/niklasb/drawingisland text2 (#339)
* Add TextElement and TextRenderer classes. * Hook up the text element to the drawing island. * Rename VisualElement to VisualItem. * Add a margin around text. * Address code review feedback.
1 parent 1faffb9 commit 90fed17

File tree

11 files changed

+491
-46
lines changed

11 files changed

+491
-46
lines changed

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.cpp

Lines changed: 100 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace winrt::DrawingIslandComponents::implementation
1414
const winrt::Compositor& compositor)
1515
{
1616
m_output.Compositor = compositor;
17+
m_output.TextRenderer = std::make_shared<TextRenderer>(m_output.Compositor);
1718

1819
// Create the Compositor and the Content:
1920
// - The Bridge's connection to the Window will keep everything alive, and perform an
@@ -75,7 +76,8 @@ namespace winrt::DrawingIslandComponents::implementation
7576
m_background.Visual = nullptr;
7677

7778
m_items.Visuals = nullptr;
78-
m_items.SelectedVisual = nullptr;
79+
m_items.Items.clear();
80+
m_items.SelectedItem = nullptr;
7981

8082
// TODO: Enable Mica on Win 11
8183
#if FALSE
@@ -234,11 +236,13 @@ namespace winrt::DrawingIslandComponents::implementation
234236
winrt::Windows::Graphics::RectInt32 screenRect{ static_cast<int>(x + 0.5), static_cast<int>(y + 0.5), 0, 0 };
235237
auto logicalRect = m_island.CoordinateConverter().ConvertScreenToLocal(screenRect);
236238
float2 localPoint{ logicalRect.X, logicalRect.Y };
237-
auto hitTestVisual = HitTestVisual(localPoint);
239+
auto hitTestElement = HitTestItem(localPoint);
238240

239241
// Find the automation peer for the hit test visual if any.
240-
if (nullptr != hitTestVisual)
242+
if (nullptr != hitTestElement)
241243
{
244+
auto& hitTestVisual = hitTestElement->GetVisual();
245+
242246
auto iterator = std::find_if(
243247
m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [&hitTestVisual](auto const& automationPeer)
244248
{
@@ -259,30 +263,36 @@ namespace winrt::DrawingIslandComponents::implementation
259263
winrt::com_ptr<IRawElementProviderFragment>
260264
DrawingIsland::GetFragmentInFocus() const
261265
{
262-
// Find the currently selected visual's automation peer.
263-
auto iterator = std::find_if(
264-
m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual = m_items.SelectedVisual](auto const& automationPeer)
265-
{
266-
return automationPeer.Match(visual);
267-
});
268-
269-
if (m_uia.AutomationPeers.end() != iterator)
266+
if (m_items.SelectedItem != nullptr)
270267
{
271-
// Return the automation provider if we found an automation peer for the selected visual.
272-
return iterator->GetAutomationProvider().as<IRawElementProviderFragment>();
268+
auto& visual = m_items.SelectedItem->GetVisual();
269+
270+
// Find the currently selected visual's automation peer.
271+
auto iterator = std::find_if(
272+
m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual](auto const& automationPeer)
273+
{
274+
return automationPeer.Match(visual);
275+
});
276+
277+
if (m_uia.AutomationPeers.end() != iterator)
278+
{
279+
// Return the automation provider if we found an automation peer for the selected visual.
280+
return iterator->GetAutomationProvider().as<IRawElementProviderFragment>();
281+
}
273282
}
274283

275284
return nullptr;
276285
}
277286

278287

279-
winrt::Visual
280-
DrawingIsland::HitTestVisual(
281-
float2 const& point) const
288+
Item* DrawingIsland::HitTestItem(float2 const& point) const
282289
{
283-
winrt::Visual selectedVisual{ nullptr };
284-
for (winrt::Visual visual : m_items.Visuals)
290+
// Iterate from the end of the vector, i.e., from front to back.
291+
for (size_t i = m_items.Items.size(); i != 0; i--)
285292
{
293+
Item* item = m_items.Items[i - 1].get();
294+
auto& visual = item->GetVisual();
295+
286296
winrt::float3 const offset = visual.Offset();
287297
float2 const size = visual.Size();
288298

@@ -291,11 +301,10 @@ namespace winrt::DrawingIslandComponents::implementation
291301
point.y >= offset.y &&
292302
point.y < offset.y + size.y)
293303
{
294-
selectedVisual = visual;
304+
return item;
295305
}
296306
}
297-
298-
return selectedVisual;
307+
return nullptr;
299308
}
300309

301310

@@ -507,6 +516,7 @@ namespace winrt::DrawingIslandComponents::implementation
507516
case winrt::Windows::System::VirtualKey::Escape:
508517
{
509518
m_items.Visuals.RemoveAll();
519+
m_items.Items.clear();
510520

511521
// Update accessibility.
512522
m_uia.FragmentRoot->RemoveAllChildren();
@@ -581,7 +591,7 @@ namespace winrt::DrawingIslandComponents::implementation
581591
void
582592
DrawingIsland::Input_OnPointerReleased()
583593
{
584-
m_items.SelectedVisual = nullptr;
594+
m_items.SelectedItem = nullptr;
585595
}
586596

587597

@@ -608,22 +618,39 @@ namespace winrt::DrawingIslandComponents::implementation
608618
const float2 point,
609619
bool controlPressed)
610620
{
611-
m_items.SelectedVisual = HitTestVisual(point);
621+
m_items.SelectedItem = HitTestItem(point);
612622

613-
if (m_items.SelectedVisual)
623+
if (m_items.SelectedItem != nullptr)
614624
{
615-
winrt::float3 const offset = m_items.SelectedVisual.Offset();
625+
Item* item = m_items.SelectedItem;
626+
auto& visual = m_items.SelectedItem->GetVisual();
627+
winrt::float3 const offset = visual.Offset();
616628

617629
m_items.Offset.x = offset.x - point.x;
618630
m_items.Offset.y = offset.y - point.y;
619631

620-
m_items.Visuals.Remove(m_items.SelectedVisual);
621-
m_items.Visuals.InsertAtTop(m_items.SelectedVisual);
632+
// Move the visual to the top.
633+
m_items.Visuals.Remove(visual);
634+
m_items.Visuals.InsertAtTop(visual);
635+
636+
// Move the VisualElement to the end of the vector if it isn't already.
637+
if (!m_items.Items.empty() && m_items.Items.back().get() != item)
638+
{
639+
auto i = std::find_if(
640+
m_items.Items.begin(),
641+
m_items.Items.end(),
642+
[item](auto& elem) { return elem.get() == item; }
643+
);
644+
if (i != m_items.Items.end())
645+
{
646+
std::rotate(i, i + 1, m_items.Items.end());
647+
}
648+
}
622649

623650
// Update automation.
624651
// First find the existing automation peer.
625652
auto iterator = std::find_if(
626-
m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual = m_items.SelectedVisual](auto const& automationPeer)
653+
m_uia.AutomationPeers.begin(), m_uia.AutomationPeers.end(), [visual](auto const& automationPeer)
627654
{
628655
return automationPeer.Match(visual);
629656
});
@@ -651,18 +678,21 @@ namespace winrt::DrawingIslandComponents::implementation
651678
void
652679
DrawingIsland::OnRightClick(const float2 point)
653680
{
654-
winrt::Visual selectedVisual = HitTestVisual(point);
681+
// TODO - what is the purpose of this?
682+
UNREFERENCED_PARAMETER(point);
683+
// VisualElement* selectedVisual = HitTestVisual(point);
655684
}
656685

657686
void
658687
DrawingIsland::Input_OnPointerMoved(
659688
const winrt::PointerEventArgs& args)
660689
{
661-
if (m_items.SelectedVisual)
690+
if (m_items.SelectedItem)
662691
{
692+
auto& visual = m_items.SelectedItem->GetVisual();
663693
float2 const point = args.CurrentPoint().Position();
664694

665-
m_items.SelectedVisual.Offset(
695+
visual.Offset(
666696
{ point.x + m_items.Offset.x,
667697
point.y + m_items.Offset.y,
668698
0.0f });
@@ -682,7 +712,16 @@ namespace winrt::DrawingIslandComponents::implementation
682712
{
683713
if (m_prevState.RasterizationScale != m_island.RasterizationScale())
684714
{
685-
m_prevState.RasterizationScale = m_island.RasterizationScale();
715+
float newScale = m_island.RasterizationScale();
716+
717+
m_prevState.RasterizationScale = newScale;
718+
719+
m_output.TextRenderer->SetDpiScale(newScale);
720+
721+
for (auto& item : m_items.Items)
722+
{
723+
item->OnDpiScaleChanged();
724+
}
686725
}
687726

688727
if (m_prevState.LayoutDirection != m_island.LayoutDirection())
@@ -746,20 +785,39 @@ namespace winrt::DrawingIslandComponents::implementation
746785
float2 const point,
747786
bool halfTransparent)
748787
{
749-
winrt::SpriteVisual visual = m_output.Compositor.CreateSpriteVisual();
750-
visual.Brush(halfTransparent ?
751-
m_output.HalfTransparentColorBrushes[m_output.CurrentColorIndex] :
752-
m_output.ColorBrushes[m_output.CurrentColorIndex]);
788+
// Determine the visual background and text colors.
789+
Color backgroundColor = s_colors[m_output.CurrentColorIndex];
790+
Color textColor = { 0xFF, 0, 0, 0 };
791+
if (halfTransparent)
792+
{
793+
backgroundColor.A /= 2;
794+
textColor.A /= 2;
795+
}
796+
797+
// Create a TextElement object.
798+
auto textItem = std::make_unique<TextItem>(
799+
m_output.TextRenderer,
800+
backgroundColor,
801+
textColor,
802+
s_colorNames[m_output.CurrentColorIndex]
803+
);
804+
805+
// Get the visual and its size in DIPs.
806+
auto& visual = textItem->GetVisual();
807+
float2 size = visual.Size();
808+
809+
// Set the visual's offset.
810+
visual.Offset({ point.x - size.x / 2.0f, point.y - size.y / 2.0f, 0.0f });
753811

754-
float const BlockSize = 30.0f;
755-
visual.Size({ BlockSize, BlockSize });
756-
visual.Offset({ point.x - BlockSize / 2.0f, point.y - BlockSize / 2.0f, 0.0f });
812+
// Add the new text element to the vector.
813+
m_items.Items.push_back(std::move(textItem));
757814

815+
// Add the visual as a child of the container visual.
758816
m_items.Visuals.InsertAtTop(visual);
759817

760-
m_items.SelectedVisual = visual;
761-
m_items.Offset.x = -BlockSize / 2.0f;
762-
m_items.Offset.y = -BlockSize / 2.0f;
818+
m_items.SelectedItem = m_items.Items.back().get();
819+
m_items.Offset.x = -size.x / 2.0f;
820+
m_items.Offset.y = -size.y / 2.0f;
763821

764822
Accessibility_CreateItemFragment(visual);
765823
}

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIsland.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#include "DrawingIsland.g.h"
77
#include "IslandFragmentRoot.h"
8+
#include "TextRenderer.h"
9+
#include "TextItem.h"
810

911
namespace winrt::DrawingIslandComponents::implementation
1012
{
@@ -90,8 +92,7 @@ namespace winrt::DrawingIslandComponents::implementation
9092
winrt::com_ptr<IRawElementProviderFragment> GetFragmentInFocus() const override;
9193

9294
private:
93-
winrt::Visual HitTestVisual(
94-
float2 const& point) const;
95+
Item* HitTestItem(float2 const& point) const;
9596

9697
void Accessibility_Initialize();
9798

@@ -194,6 +195,8 @@ namespace winrt::DrawingIslandComponents::implementation
194195
{
195196
winrt::Compositor Compositor{ nullptr };
196197

198+
std::shared_ptr<TextRenderer> TextRenderer;
199+
197200
// Current color used for new items
198201
unsigned int CurrentColorIndex = 0;
199202

@@ -243,10 +246,22 @@ namespace winrt::DrawingIslandComponents::implementation
243246
// Drawing items being manipulated.
244247
struct
245248
{
249+
// The container visual's Children collection. Each Item's visual must be
250+
// added to this collection to be rendered.
246251
winrt::VisualCollection Visuals{ nullptr };
247-
winrt::Visual SelectedVisual{ nullptr };
248-
winrt::SpriteVisual CurrentColorVisual{ nullptr };
252+
253+
// Vector of Item objects representing items that can be manipulated, in
254+
// back-to-front order. Each item has an associated Visual.
255+
std::vector<std::unique_ptr<Item>> Items;
256+
257+
// Pointer to the currently-selected item, if any.
258+
Item* SelectedItem{ nullptr };
259+
260+
// Offset from the top-left corner of the selected item to the pointer.
249261
float2 Offset{};
262+
263+
// Visual that shows the current color.
264+
winrt::SpriteVisual CurrentColorVisual{ nullptr };
250265
} m_items;
251266

252267
struct

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@
131131
<ClInclude Include="DrawingIsland.h">
132132
<DependentUpon>Components.idl</DependentUpon>
133133
</ClInclude>
134+
<ClInclude Include="TextItem.h" />
135+
<ClInclude Include="TextRenderer.h" />
136+
<ClInclude Include="Item.h" />
134137
</ItemGroup>
135138
<ItemGroup>
136139
<ClCompile Include="IslandFragmentRoot.cpp" />
@@ -142,6 +145,9 @@
142145
<DependentUpon>Components.idl</DependentUpon>
143146
</ClCompile>
144147
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
148+
<ClCompile Include="TextItem.cpp" />
149+
<ClCompile Include="TextRenderer.cpp" />
150+
<ClCompile Include="Item.cpp" />
145151
</ItemGroup>
146152
<ItemGroup>
147153
<Midl Include="Components.idl" />

Samples/Islands/DrawingIsland/DrawingIslandComponents/DrawingIslandComponents.vcxproj.filters

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@
2424
<ClCompile Include="NodeSimpleFragment.cpp">
2525
<Filter>Source Files</Filter>
2626
</ClCompile>
27+
<ClCompile Include="TextItem.cpp">
28+
<Filter>Source Files</Filter>
29+
</ClCompile>
30+
<ClCompile Include="TextRenderer.cpp">
31+
<Filter>Source Files</Filter>
32+
</ClCompile>
33+
<ClCompile Include="Item.cpp">
34+
<Filter>Source Files</Filter>
35+
</ClCompile>
2736
</ItemGroup>
2837
<ItemGroup>
2938
<ClInclude Include="pch.h" />
@@ -33,6 +42,15 @@
3342
<ClInclude Include="IslandFragmentRoot.h">
3443
<Filter>Header Files</Filter>
3544
</ClInclude>
45+
<ClInclude Include="TextItem.h">
46+
<Filter>Header Files</Filter>
47+
</ClInclude>
48+
<ClInclude Include="TextRenderer.h">
49+
<Filter>Header Files</Filter>
50+
</ClInclude>
51+
<ClInclude Include="Item.h">
52+
<Filter>Header Files</Filter>
53+
</ClInclude>
3654
</ItemGroup>
3755
<ItemGroup>
3856
<Midl Include="Components.idl" />
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#include "pch.h"
5+
#include "Item.h"
6+
7+
namespace winrt::DrawingIslandComponents::implementation
8+
{
9+
Item::Item(winrt::Compositor const& compositor) :
10+
m_visual(compositor.CreateSpriteVisual())
11+
{
12+
}
13+
}

0 commit comments

Comments
 (0)