-
Notifications
You must be signed in to change notification settings - Fork 677
/
AutoSuggestBoxHelper.cpp
145 lines (124 loc) · 5.84 KB
/
AutoSuggestBoxHelper.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#include <pch.h>
#include <common.h>
#include "AutoSuggestBoxHelper.h"
#include "CornerRadiusFilterConverter.h"
#include "ResourceAccessor.h"
static constexpr auto c_popupName = L"SuggestionsPopup"sv;
static constexpr auto c_popupBorderName = L"SuggestionsContainer"sv;
static constexpr auto c_textBoxName = L"TextBox"sv;
static constexpr auto c_textBoxBorderName = L"BorderElement"sv;
static constexpr auto c_overlayCornerRadiusKey = L"OverlayCornerRadius"sv;
GlobalDependencyProperty AutoSuggestBoxHelper::s_AutoSuggestEventRevokersProperty{ nullptr };
AutoSuggestBoxHelper::AutoSuggestBoxHelper()
{
EnsureProperties();
}
void AutoSuggestBoxHelper::EnsureProperties()
{
if (!s_AutoSuggestEventRevokersProperty)
{
s_AutoSuggestEventRevokersProperty =
InitializeDependencyProperty(
L"AutoSuggestEventRevokers",
winrt::name_of<winrt::IInspectable>(),
winrt::name_of<winrt::AutoSuggestBoxHelper>(),
true /* isAttached */,
ValueHelper<winrt::IInspectable>::BoxedDefaultValue(),
nullptr);
}
AutoSuggestBoxHelperProperties::EnsureProperties();
}
void AutoSuggestBoxHelper::ClearProperties()
{
s_AutoSuggestEventRevokersProperty = nullptr;
AutoSuggestBoxHelperProperties::ClearProperties();
}
// The corner radius needs to be updated dynamically depending on whether the suggestion list is opening up or down.
// Xaml is not lifted yet when we implementing this feature so we don't have access to AutoSuggestBox code.
// Creating this attached property to help us plug in some extra logic without touching the actual code.
void AutoSuggestBoxHelper::OnKeepInteriorCornersSquarePropertyChanged(
const winrt::DependencyObject& sender,
const winrt::DependencyPropertyChangedEventArgs& args)
{
if (auto autoSuggestBox = sender.try_as<winrt::AutoSuggestBox>())
{
bool shouldMonitorAutoSuggestEvents = unbox_value<bool>(args.NewValue());
if (shouldMonitorAutoSuggestEvents)
{
auto revokersInspectable = winrt::make<AutoSuggestEventRevokers>();
auto revokers = revokersInspectable.as<AutoSuggestEventRevokers>();
revokers->m_autoSuggestBoxLoadedRevoker = autoSuggestBox.Loaded(winrt::auto_revoke, AutoSuggestBoxHelper::OnAutoSuggestBoxLoaded);
autoSuggestBox.SetValue(AutoSuggestEventRevokersProperty(), revokersInspectable);
}
else
{
autoSuggestBox.SetValue(AutoSuggestEventRevokersProperty(), nullptr);
}
}
}
void AutoSuggestBoxHelper::OnAutoSuggestBoxLoaded(const winrt::IInspectable& sender, const winrt::IInspectable& args)
{
auto autoSuggestBox = sender.as<winrt::AutoSuggestBox>();
auto revokers = autoSuggestBox.GetValue(AutoSuggestEventRevokersProperty()).as<AutoSuggestEventRevokers>();
if (!revokers->m_popupOpenedRevoker || !revokers->m_popupClosedRevoker)
{
if (auto popup = GetTemplateChildT<winrt::Popup>(c_popupName, autoSuggestBox))
{
auto autoSuggestBoxWeakRef = winrt::make_weak(autoSuggestBox);
revokers->m_popupOpenedRevoker = popup.Opened(winrt::auto_revoke,
[autoSuggestBoxWeakRef](const winrt::IInspectable& sender, const winrt::IInspectable& args)
{
if (auto autoSuggestBox = autoSuggestBoxWeakRef.get())
{
UpdateCornerRadius(autoSuggestBox, /*IsDropDownOpen=*/true);
}
});
revokers->m_popupClosedRevoker = popup.Closed(winrt::auto_revoke,
[autoSuggestBoxWeakRef](const winrt::IInspectable& sender, const winrt::IInspectable& args)
{
if (auto autoSuggestBox = autoSuggestBoxWeakRef.get())
{
UpdateCornerRadius(autoSuggestBox, /*IsDropDownOpen=*/false);
}
});
}
}
}
void AutoSuggestBoxHelper::UpdateCornerRadius(const winrt::AutoSuggestBox& autoSuggestBox, bool isPopupOpen)
{
auto popupRadius = unbox_value<winrt::CornerRadius>(ResourceAccessor::ResourceLookup(autoSuggestBox, box_value(c_overlayCornerRadiusKey)));
auto textBoxRadius = autoSuggestBox.CornerRadius();
if (isPopupOpen)
{
auto const isOpenDown = IsPopupOpenDown(autoSuggestBox);
auto cornerRadiusConverter = winrt::make_self<CornerRadiusFilterConverter>();
const auto popupRadiusFilter = isOpenDown ? winrt::CornerRadiusFilterKind::Bottom : winrt::CornerRadiusFilterKind::Top;
popupRadius = cornerRadiusConverter->Convert(popupRadius, popupRadiusFilter);
const auto textBoxRadiusFilter = isOpenDown ? winrt::CornerRadiusFilterKind::Top : winrt::CornerRadiusFilterKind::Bottom;
textBoxRadius = cornerRadiusConverter->Convert(textBoxRadius, textBoxRadiusFilter);
}
if (auto popupBorder = GetTemplateChildT<winrt::Border>(c_popupBorderName, autoSuggestBox))
{
popupBorder.CornerRadius(popupRadius);
}
if (auto textBox = GetTemplateChildT<winrt::TextBox>(c_textBoxName, autoSuggestBox))
{
textBox.CornerRadius(textBoxRadius);
}
}
bool AutoSuggestBoxHelper::IsPopupOpenDown(const winrt::AutoSuggestBox& autoSuggestBox)
{
double verticalOffset = 0;
if (auto popupBorder = GetTemplateChildT<winrt::Border>(c_popupBorderName, autoSuggestBox))
{
if (auto textBox = GetTemplateChildT<winrt::TextBox>(c_textBoxName, autoSuggestBox))
{
const auto transform = popupBorder.TransformToVisual(textBox);
const auto popupTop = transform.TransformPoint(winrt::Point(0, 0));
verticalOffset = popupTop.Y;
}
}
return verticalOffset >= 0;
}