diff --git a/support/hololens/ServoApp/App.xaml b/support/hololens/ServoApp/App.xaml index 015f637b3df8..333b37f88b74 100644 --- a/support/hololens/ServoApp/App.xaml +++ b/support/hololens/ServoApp/App.xaml @@ -4,4 +4,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:ServoApp"> + + + + diff --git a/support/hololens/ServoApp/Assets/UI/stop.png b/support/hololens/ServoApp/Assets/UI/cross.png similarity index 100% rename from support/hololens/ServoApp/Assets/UI/stop.png rename to support/hololens/ServoApp/Assets/UI/cross.png diff --git a/support/hololens/ServoApp/BrowserPage.cpp b/support/hololens/ServoApp/BrowserPage.cpp index e8ba12ba2b30..a2b13bf60b95 100644 --- a/support/hololens/ServoApp/BrowserPage.cpp +++ b/support/hololens/ServoApp/BrowserPage.cpp @@ -8,6 +8,11 @@ #include "BrowserPage.g.cpp" #include "DefaultUrl.h" +#include "winrt/Microsoft.UI.Xaml.Controls.h" +#include "winrt/Microsoft.UI.Xaml.XamlTypeInfo.h" +#include "winrt/Windows.UI.Text.h" +#include "winrt/Windows.UI.Xaml.Documents.h" // For Run.Text() + using namespace std::placeholders; using namespace winrt::Windows::Foundation; using namespace winrt::Windows::UI::Xaml; @@ -18,6 +23,7 @@ using namespace winrt::Windows::UI::Notifications; using namespace winrt::Windows::Data::Xml::Dom; namespace winrt::ServoApp::implementation { + BrowserPage::BrowserPage() { InitializeComponent(); BindServoEvents(); @@ -84,13 +90,12 @@ void BrowserPage::BindServoEvents() { }); } -void BrowserPage::OnURLFocused(Windows::Foundation::IInspectable const &) { +void BrowserPage::OnURLFocused(IInspectable const &) { urlTextbox().SelectAll(); } void BrowserPage::OnURLKeyboardAccelerator( - Windows::Foundation::IInspectable const &, - Windows::UI::Xaml::Input::KeyboardAcceleratorInvokedEventArgs const &) { + IInspectable const &, Input::KeyboardAcceleratorInvokedEventArgs const &) { urlTextbox().Focus(FocusState::Programmatic); } @@ -116,10 +121,7 @@ void BrowserPage::SetTransientMode(bool transient) { void BrowserPage::SetArgs(hstring args) { servoControl().SetArgs(args); } -void BrowserPage::Shutdown() { - ToastNotificationManager::History().Clear(); - servoControl().Shutdown(); -} +void BrowserPage::Shutdown() { servoControl().Shutdown(); } /**** USER INTERACTIONS WITH UI ****/ @@ -148,23 +150,153 @@ void BrowserPage::OnHomeButtonClicked(IInspectable const &, servoControl().LoadURIOrSearch(DEFAULT_URL); } +// Given a pref, update its associated UI control. +void BrowserPage::UpdatePref(ServoApp::Pref pref, Controls::Control ctrl) { + auto value = pref.Value(); + auto type = value.as().Type(); + if (type == PropertyType::Boolean) { + ctrl.as().IsChecked(unbox_value(value)); + } else if (type == PropertyType::Double) { + ctrl.as().Value( + unbox_value(value)); + } else if (type == PropertyType::Int64) { + ctrl.as().Value( + (double)unbox_value(value)); + } else if (type == PropertyType::String) { + ctrl.as().Text(unbox_value(value)); + } + auto stack = ctrl.Parent().as(); + auto font = winrt::Windows::UI::Text::FontWeights::Normal(); + if (!pref.IsDefault()) { + font = winrt::Windows::UI::Text::FontWeights::Bold(); + } + stack.Children().GetAt(0).as().FontWeight(font); + stack.Children().GetAt(2).as().IsEnabled(!pref.IsDefault()); +} + +// Retrieve the preference list from Servo and build the preference table. +void BrowserPage::BuildPrefList() { + // It would be better to use a template and bindings, but the + // takes too long to generate all the items, and + // it's pretty difficiult to have different controls depending + // on the pref type. + prefList().Children().Clear(); + for (auto pref : ServoControl().Preferences()) { + auto value = pref.Value(); + auto type = value.as().Type(); + std::optional ctrl; + if (type == PropertyType::Boolean) { + auto checkbox = Controls::CheckBox(); + checkbox.IsChecked(unbox_value(value)); + checkbox.Click([=](const auto &, auto const &) { + auto upref = ServoControl().SetBoolPref( + pref.Key(), checkbox.IsChecked().GetBoolean()); + UpdatePref(upref, checkbox); + }); + ctrl = checkbox; + } else if (type == PropertyType::String) { + auto textbox = Controls::TextBox(); + textbox.Text(unbox_value(value)); + textbox.KeyUp([=](const auto &, Input::KeyRoutedEventArgs const &e) { + if (e.Key() == Windows::System::VirtualKey::Enter) { + auto upref = ServoControl().SetStringPref(pref.Key(), textbox.Text()); + UpdatePref(upref, textbox); + } + }); + ctrl = textbox; + } else if (type == PropertyType::Int64) { + // Note: These are *not* under Windows::UI:Xaml namespace. + auto nbox = Microsoft::UI::Xaml::Controls::NumberBox(); + nbox.Value((double)unbox_value(value)); + nbox.SpinButtonPlacementMode( + Microsoft::UI::Xaml::Controls::NumberBoxSpinButtonPlacementMode:: + Inline); + nbox.ValueChanged([=](const auto &, const auto &) { + int val = (int)nbox.Value(); + auto upref = ServoControl().SetIntPref(pref.Key(), val); + UpdatePref(upref, nbox); + }); + ctrl = nbox; + } else if (type == PropertyType::Double) { + auto nbox = Microsoft::UI::Xaml::Controls::NumberBox(); + nbox.Value(unbox_value(value)); + nbox.ValueChanged([=](const auto &, const auto &) { + auto upref = + ServoControl().SetIntPref(pref.Key(), (int64_t)nbox.Value()); + UpdatePref(upref, (Controls::Control &)nbox); + }); + ctrl = nbox; + } + if (ctrl.has_value()) { + auto stack = Controls::StackPanel(); + stack.Tag(winrt::box_value(pref.Key())); + stack.Padding({4, 4, 4, 4}); + stack.Orientation(Controls::Orientation::Horizontal); + auto key = Controls::TextBlock(); + key.Text(pref.Key()); + key.Width(350); + if (!pref.IsDefault()) { + auto font = winrt::Windows::UI::Text::FontWeights::Bold(); + key.FontWeight(font); + } + stack.Children().Append(key); + ctrl->Width(300); + ctrl->Margin({4, 0, 40, 0}); + stack.Children().Append(*ctrl); + auto reset = Controls::Button(); + reset.Content(winrt::box_value(L"reset")); + reset.IsEnabled(!pref.IsDefault()); + reset.Click([=](const auto &, auto const &) { + auto upref = ServoControl().ResetPref(pref.Key()); + UpdatePref(upref, *ctrl); + }); + stack.Children().Append(reset); + prefList().Children().Append(stack); + } + } +} + +void BrowserPage::OnPrefererenceSearchboxEdited( + IInspectable const &, Input::KeyRoutedEventArgs const &) { + auto input = preferenceSearchbox().Text(); + for (auto element : prefList().Children()) { + auto ctrl = (Controls::Control &)element; + if (input.size() == 0) { + ctrl.Visibility(Visibility::Visible); + } else { + auto tag = ctrl.Tag(); + std::wstring key = static_cast(unbox_value(tag)); + bool not_found = key.find(input) == std::wstring::npos; + ctrl.Visibility(not_found ? Visibility::Collapsed : Visibility::Visible); + } + } +} + void BrowserPage::OnDevtoolsButtonClicked(IInspectable const &, RoutedEventArgs const &) { - auto toastTemplate = ToastTemplateType::ToastText01; - auto toastXml = ToastNotificationManager::GetTemplateContent(toastTemplate); - auto toastTextElements = toastXml.GetElementsByTagName(L"text"); - std::wstring message; - if (mDevtoolsStatus == DevtoolsStatus::Stopped) { - message = L"Devtools server hasn't started"; - } else if (mDevtoolsStatus == DevtoolsStatus::Running) { - message = L"DevTools server has started on port " + - std::to_wstring(mDevtoolsPort); - } else if (mDevtoolsStatus == DevtoolsStatus::Failed) { - message = L"Error: could not start DevTools"; + if (toolbox().Visibility() == Visibility::Visible) { + prefList().Children().Clear(); + toolbox().Visibility(Visibility::Collapsed); + return; + } + + toolbox().Visibility(Visibility::Visible); + + BuildPrefList(); + + // FIXME: we could use template + binding for this. + auto ok = mDevtoolsStatus == DevtoolsStatus::Running ? Visibility::Visible + : Visibility::Collapsed; + auto ko = mDevtoolsStatus == DevtoolsStatus::Failed ? Visibility::Visible + : Visibility::Collapsed; + auto wip = mDevtoolsStatus == DevtoolsStatus::Stopped ? Visibility::Visible + : Visibility::Collapsed; + DevtoolsStatusOK().Visibility(ok); + DevtoolsStatusKO().Visibility(ko); + DevtoolsStatusWIP().Visibility(wip); + if (mDevtoolsStatus == DevtoolsStatus::Running) { + DevtoolsPort().Text(std::to_wstring(mDevtoolsPort)); } - toastTextElements.Item(0).InnerText(message); - auto toast = ToastNotification(toastXml); - ToastNotificationManager::CreateToastNotifier().Show(toast); } void BrowserPage::OnURLEdited(IInspectable const &, @@ -177,15 +309,13 @@ void BrowserPage::OnURLEdited(IInspectable const &, } } -void BrowserPage::OnMediaControlsPlayClicked( - Windows::Foundation::IInspectable const &, - Windows::UI::Xaml::RoutedEventArgs const &) { +void BrowserPage::OnMediaControlsPlayClicked(IInspectable const &, + RoutedEventArgs const &) { servoControl().SendMediaSessionAction( static_cast(servo::Servo::MediaSessionActionType::Play)); } -void BrowserPage::OnMediaControlsPauseClicked( - Windows::Foundation::IInspectable const &, - Windows::UI::Xaml::RoutedEventArgs const &) { +void BrowserPage::OnMediaControlsPauseClicked(IInspectable const &, + RoutedEventArgs const &) { servoControl().SendMediaSessionAction( static_cast(servo::Servo::MediaSessionActionType::Pause)); } diff --git a/support/hololens/ServoApp/BrowserPage.h b/support/hololens/ServoApp/BrowserPage.h index bb57afad68ae..1455c1f5a9bd 100644 --- a/support/hololens/ServoApp/BrowserPage.h +++ b/support/hololens/ServoApp/BrowserPage.h @@ -9,6 +9,8 @@ namespace winrt::ServoApp::implementation { +using namespace winrt::Windows::Foundation; + static const hstring SERVO_SCHEME = L"fxr"; static const hstring SERVO_SCHEME_SLASH_SLASH = L"fxr://"; @@ -42,9 +44,14 @@ struct BrowserPage : BrowserPageT { Windows::UI::Xaml::RoutedEventArgs const &); void OnMediaControlsPauseClicked(Windows::Foundation::IInspectable const &, Windows::UI::Xaml::RoutedEventArgs const &); + void OnPrefererenceSearchboxEdited( + Windows::Foundation::IInspectable const &, + Windows::UI::Xaml::Input::KeyRoutedEventArgs const &); private: + void UpdatePref(ServoApp::Pref, Windows::UI::Xaml::Controls::Control); void BindServoEvents(); + void BuildPrefList(); DevtoolsStatus mDevtoolsStatus = DevtoolsStatus::Stopped; unsigned int mDevtoolsPort = 0; }; diff --git a/support/hololens/ServoApp/BrowserPage.xaml b/support/hololens/ServoApp/BrowserPage.xaml index 3fa6cf849829..da4ea5c97920 100644 --- a/support/hololens/ServoApp/BrowserPage.xaml +++ b/support/hololens/ServoApp/BrowserPage.xaml @@ -6,7 +6,11 @@ xmlns:local="using:ServoApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:muxc="using:Microsoft.UI.Xaml.Controls" mc:Ignorable="d"> + + +