From 15944fcd10e650efe94d319599767fe3ead4617f Mon Sep 17 00:00:00 2001 From: Rudy Huyn Date: Tue, 24 Mar 2020 11:39:59 -0700 Subject: [PATCH] Add dual-screen support to Calculator (#1027) --- src/CalcViewModel/CalcViewModel.vcxproj | 2 + .../CalcViewModel.vcxproj.filters | 9 + .../Utils/DeviceFamilyHelper.cpp | 54 + src/CalcViewModel/Utils/DeviceFamilyHelper.h | 31 + src/Calculator/App.xaml | 125 +- src/Calculator/Calculator.vcxproj | 8 +- src/Calculator/Calculator.vcxproj.filters | 13 +- src/Calculator/Controls/TwoPaneViewCX.cpp | 487 ++++++ src/Calculator/Controls/TwoPaneViewCX.h | 116 ++ src/Calculator/MultiTrigger.cpp | 0 src/Calculator/MultiTrigger.h | 0 src/Calculator/Package.appxmanifest | 2 +- src/Calculator/Views/Calculator.xaml | 1508 +++++++++-------- src/Calculator/Views/Calculator.xaml.cpp | 5 + src/Calculator/Views/Calculator.xaml.h | 1 + .../GraphingCalculator/EquationInputArea.xaml | 15 - .../GraphingCalculator.xaml | 536 +++--- .../GraphingCalculator.xaml.cpp | 12 +- .../GraphingCalculator.xaml.h | 6 +- .../ApplicationViewModeTrigger.cpp | 80 + .../ApplicationViewModeTrigger.h | 40 + src/Calculator/Views/TitleBar.xaml.cpp | 33 +- src/Calculator/Views/TitleBar.xaml.h | 1 + src/Calculator/Views/UnitConverter.xaml | 602 +++---- src/Calculator/Views/UnitConverter.xaml.h | 1 + src/Calculator/packages.config | 2 +- src/Calculator/pch.h | 1 + 27 files changed, 2411 insertions(+), 1279 deletions(-) create mode 100644 src/CalcViewModel/Utils/DeviceFamilyHelper.cpp create mode 100644 src/CalcViewModel/Utils/DeviceFamilyHelper.h create mode 100644 src/Calculator/Controls/TwoPaneViewCX.cpp create mode 100644 src/Calculator/Controls/TwoPaneViewCX.h create mode 100644 src/Calculator/MultiTrigger.cpp create mode 100644 src/Calculator/MultiTrigger.h create mode 100644 src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.cpp create mode 100644 src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.h diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj index c2a69b5c..41d46c5a 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj +++ b/src/CalcViewModel/CalcViewModel.vcxproj @@ -334,6 +334,7 @@ + @@ -374,6 +375,7 @@ + diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters index 7a0619ee..c9408c82 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj.filters +++ b/src/CalcViewModel/CalcViewModel.vcxproj.filters @@ -13,6 +13,9 @@ {cf7dca32-9727-4f98-83c3-1c0ca7dd1e0c} + + {68bb415f-fcb1-4759-b0a7-c5caf9d72396} + @@ -86,6 +89,9 @@ GraphingCalculator + + Utils + @@ -199,6 +205,9 @@ Common + + Utils + diff --git a/src/CalcViewModel/Utils/DeviceFamilyHelper.cpp b/src/CalcViewModel/Utils/DeviceFamilyHelper.cpp new file mode 100644 index 00000000..49fd51be --- /dev/null +++ b/src/CalcViewModel/Utils/DeviceFamilyHelper.cpp @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "DeviceFamilyHelper.h" + +using namespace CalculatorApp::ViewModel::Utils; +using namespace Windows::System::Profile; + +bool DeviceFamilyHelper::m_isInit{ false }; +DeviceFamily DeviceFamilyHelper::m_deviceFamily{ DeviceFamily::Unknown }; + +DeviceFamily DeviceFamilyHelper::GetDeviceFamily() +{ + if (!m_isInit) + { + InitDeviceFamily(); + m_isInit = true; + } + return m_deviceFamily; +} + +void DeviceFamilyHelper::InitDeviceFamily() +{ + auto deviceFamily = AnalyticsInfo::VersionInfo->DeviceFamily; + if (deviceFamily == L"Windows.Desktop") + { + m_deviceFamily = DeviceFamily::Desktop; + } + else if (deviceFamily == L"Windows.Core") + { + m_deviceFamily = DeviceFamily::WindowsCore; + } + else if (deviceFamily == L"Windows.Xbox") + { + m_deviceFamily = DeviceFamily::Xbox; + } + else if (deviceFamily == L"Windows.Team") + { + m_deviceFamily = DeviceFamily::SurfaceHub; + } + else if (deviceFamily == L"Windows.Holographic") + { + m_deviceFamily = DeviceFamily::HoloLens; + } + else if (deviceFamily == L"Windows.Mobile") + { + m_deviceFamily = DeviceFamily::Mobile; + } + else + { + m_deviceFamily = DeviceFamily::Unknown; + } +} diff --git a/src/CalcViewModel/Utils/DeviceFamilyHelper.h b/src/CalcViewModel/Utils/DeviceFamilyHelper.h new file mode 100644 index 00000000..4811cd3b --- /dev/null +++ b/src/CalcViewModel/Utils/DeviceFamilyHelper.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +namespace CalculatorApp::ViewModel::Utils +{ + public enum class DeviceFamily + { + Unknown, + Desktop, + Mobile, + Xbox, + SurfaceHub, + HoloLens, + WindowsCore, + }; + + public ref class DeviceFamilyHelper sealed + { + private: + DeviceFamilyHelper() {} + public: + static DeviceFamily GetDeviceFamily(); + private: + static void InitDeviceFamily(); + private: + static bool m_isInit; + static DeviceFamily m_deviceFamily; + }; +} diff --git a/src/Calculator/App.xaml b/src/Calculator/App.xaml index 50472efd..f12d0921 100644 --- a/src/Calculator/App.xaml +++ b/src/Calculator/App.xaml @@ -3,6 +3,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Controls="using:CalculatorApp.Controls" xmlns:common="using:CalculatorApp.Common" + xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)" + xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)" xmlns:local="using:CalculatorApp"> @@ -84,7 +86,7 @@ - + 0,0,0,0 @@ -163,6 +165,7 @@ + 0,1,0,0 @@ -197,6 +200,7 @@ + @@ -1764,6 +1768,125 @@ + + diff --git a/src/Calculator/Calculator.vcxproj b/src/Calculator/Calculator.vcxproj index eb39777f..6bca12fc 100644 --- a/src/Calculator/Calculator.vcxproj +++ b/src/Calculator/Calculator.vcxproj @@ -252,6 +252,7 @@ + @@ -329,6 +330,7 @@ Views\OperatorsPanel.xaml + @@ -422,6 +424,7 @@ + @@ -505,6 +508,7 @@ Views\OperatorsPanel.xaml + @@ -976,7 +980,7 @@ - + @@ -984,6 +988,6 @@ - + diff --git a/src/Calculator/Calculator.vcxproj.filters b/src/Calculator/Calculator.vcxproj.filters index 7782ca13..7803c6c5 100644 --- a/src/Calculator/Calculator.vcxproj.filters +++ b/src/Calculator/Calculator.vcxproj.filters @@ -329,6 +329,12 @@ + + Controls + + + Views\StateTriggers + @@ -437,6 +443,12 @@ + + Controls + + + Views\StateTriggers + @@ -522,7 +534,6 @@ Views\GraphingCalculator - diff --git a/src/Calculator/Controls/TwoPaneViewCX.cpp b/src/Calculator/Controls/TwoPaneViewCX.cpp new file mode 100644 index 00000000..d117ce2b --- /dev/null +++ b/src/Calculator/Controls/TwoPaneViewCX.cpp @@ -0,0 +1,487 @@ +// 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 "TwoPaneViewCX.h" +#include "Utils/VisualTree.h" +#include + +using namespace std; +using namespace Platform; +using namespace CalculatorApp::Controls; +using namespace Calculator::Utils; +using namespace Windows::Foundation; +using namespace Windows::UI::ViewManagement; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using Windows::Foundation::Metadata::ApiInformation; +namespace MUXC = Microsoft::UI::Xaml::Controls; + +StringReference c_pane1ScrollViewerName(L"PART_Pane1ScrollViewer"); +StringReference c_pane2ScrollViewerName(L"PART_Pane2ScrollViewer"); +StringReference c_columnLeftName(L"PART_ColumnLeft"); +StringReference c_columnMiddleName(L"PART_ColumnMiddle"); +StringReference c_columnRightName(L"PART_ColumnRight"); +StringReference c_rowTopName(L"PART_RowTop"); +StringReference c_rowMiddleName(L"PART_RowMiddle"); +StringReference c_rowBottomName(L"PART_RowBottom"); + +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane1); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane2); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane1Length); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane2Length); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane1MinLength); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane2MinLength); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane1MaxLength); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Pane2MaxLength); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, PanePriority); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, Mode); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, WideModeConfiguration); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, TallModeConfiguration); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, MinWideModeWidth); +DEPENDENCY_PROPERTY_INITIALIZATION(TwoPaneViewCX, MinTallModeHeight); + +TwoPaneViewCX::TwoPaneViewCX() +{ + this->DefaultStyleKey = L"CalculatorApp.Controls.TwoPaneViewCX"; + this->SizeChanged += ref new Windows::UI::Xaml::SizeChangedEventHandler(this, &TwoPaneViewCX::OnSizeChanged); + m_windowSizeChangedToken = Window::Current->SizeChanged += + ref new Windows::UI::Xaml::WindowSizeChangedEventHandler(this, &TwoPaneViewCX::OnWindowSizeChanged); +} + +TwoPaneViewCX::~TwoPaneViewCX() +{ + Window::Current->SizeChanged -= m_windowSizeChangedToken; +} + +void TwoPaneViewCX::OnApplyTemplate() +{ + m_loaded = true; + this->SetScrollViewerProperties(c_pane1ScrollViewerName); + this->SetScrollViewerProperties(c_pane2ScrollViewerName); + + if (auto column = dynamic_cast(this->GetTemplateChild(c_columnLeftName))) + { + m_columnLeft = column; + } + if (auto column = dynamic_cast(this->GetTemplateChild(c_columnMiddleName))) + { + m_columnMiddle = column; + } + if (auto column = dynamic_cast(this->GetTemplateChild(c_columnRightName))) + { + m_columnRight = column; + } + if (auto row = dynamic_cast(this->GetTemplateChild(c_rowTopName))) + { + m_rowTop = row; + } + if (auto row = dynamic_cast(this->GetTemplateChild(c_rowMiddleName))) + { + m_rowMiddle = row; + } + if (auto row = dynamic_cast(this->GetTemplateChild(c_rowBottomName))) + { + m_rowBottom = row; + } +} + +void TwoPaneViewCX::UpdateMode() +{ + // Don't bother running this logic until after we hit OnApplyTemplate. + if (!m_loaded) + return; + + double controlWidth = this->ActualWidth; + double controlHeight = this->ActualHeight; + + ViewMode newMode = (this->PanePriority == MUXC::TwoPaneViewPriority::Pane1) ? ViewMode::Pane1Only : ViewMode::Pane2Only; + + // Calculate new mode + Rect rcControl = GetControlRect(); + auto info = this->GetDisplayRegionHelperInfo(); + bool isInMultipleRegions = IsInMultipleRegions(info, rcControl); + + if (isInMultipleRegions) + { + if (info.Mode == MUXC::TwoPaneViewMode::Wide) + { + // Regions are laid out horizontally + if (this->WideModeConfiguration != MUXC::TwoPaneViewWideModeConfiguration::SinglePane) + { + newMode = (this->WideModeConfiguration == MUXC::TwoPaneViewWideModeConfiguration::LeftRight) ? ViewMode::LeftRight : ViewMode::RightLeft; + } + } + else if (info.Mode == MUXC::TwoPaneViewMode::Tall) + { + // Regions are laid out vertically + if (this->TallModeConfiguration != MUXC::TwoPaneViewTallModeConfiguration::SinglePane) + { + newMode = (this->TallModeConfiguration == MUXC::TwoPaneViewTallModeConfiguration::TopBottom) ? ViewMode::TopBottom : ViewMode::BottomTop; + } + } + } + else + { + // One region + if (controlWidth > this->MinWideModeWidth && this->WideModeConfiguration != MUXC::TwoPaneViewWideModeConfiguration::SinglePane) + { + // Split horizontally + newMode = (this->WideModeConfiguration == MUXC::TwoPaneViewWideModeConfiguration::LeftRight) ? ViewMode::LeftRight : ViewMode::RightLeft; + } + else if (controlHeight > this->MinTallModeHeight && this->TallModeConfiguration != MUXC::TwoPaneViewTallModeConfiguration::SinglePane) + { + // Split vertically + newMode = (this->TallModeConfiguration == MUXC::TwoPaneViewTallModeConfiguration::TopBottom) ? ViewMode::TopBottom : ViewMode::BottomTop; + } + } + + // Update row/column sizes (this may need to happen even if the mode doesn't change) + UpdateRowsColumns(newMode, info, rcControl); + + // Update mode if necessary + if (newMode != m_currentMode) + { + m_currentMode = newMode; + + auto newViewMode = MUXC::TwoPaneViewMode::SinglePane; + + switch (m_currentMode) + { + case ViewMode::Pane1Only: + VisualStateManager::GoToState(this, L"ViewMode_OneOnly", true); + break; + case ViewMode::Pane2Only: + VisualStateManager::GoToState(this, L"ViewMode_TwoOnly", true); + break; + case ViewMode::LeftRight: + VisualStateManager::GoToState(this, L"ViewMode_LeftRight", true); + newViewMode = MUXC::TwoPaneViewMode::Wide; + break; + case ViewMode::RightLeft: + VisualStateManager::GoToState(this, L"ViewMode_RightLeft", true); + newViewMode = MUXC::TwoPaneViewMode::Wide; + break; + case ViewMode::TopBottom: + VisualStateManager::GoToState(this, L"ViewMode_TopBottom", true); + newViewMode = MUXC::TwoPaneViewMode::Tall; + break; + case ViewMode::BottomTop: + VisualStateManager::GoToState(this, L"ViewMode_BottomTop", true); + newViewMode = MUXC::TwoPaneViewMode::Tall; + break; + } + + if (newViewMode != this->Mode) + { + SetValue(s_ModeProperty, newViewMode); + this->ModeChanged(this, this); + } + } +} + +void TwoPaneViewCX::UpdateRowsColumns(ViewMode newMode, DisplayRegionHelperInfo info, Rect rcControl) +{ + if (m_columnLeft && m_columnMiddle && m_columnRight && m_rowTop && m_rowMiddle && m_rowBottom) + { + // Reset split lengths + this->m_columnMiddle->Width = GridLengthHelper::FromPixels(0); + this->m_rowMiddle->Height = GridLengthHelper::FromPixels(0); + + // Set columns lengths + if (newMode == ViewMode::LeftRight || newMode == ViewMode::RightLeft) + { + if (newMode == ViewMode::LeftRight) + { + this->m_columnLeft->MinWidth = this->Pane1MinLength; + this->m_columnLeft->MaxWidth = this->Pane1MaxLength; + this->m_columnLeft->Width = this->Pane1Length; + this->m_columnRight->MinWidth = this->Pane2MinLength; + this->m_columnRight->MaxWidth = this->Pane2MaxLength; + this->m_columnRight->Width = this->Pane2Length; + } + else + { + this->m_columnLeft->MinWidth = this->Pane2MinLength; + this->m_columnLeft->MaxWidth = this->Pane2MaxLength; + this->m_columnLeft->Width = this->Pane2Length; + this->m_columnRight->MinWidth = this->Pane1MinLength; + this->m_columnRight->MaxWidth = this->Pane1MaxLength; + this->m_columnRight->Width = this->Pane1Length; + } + } + else + { + this->m_columnLeft->MinWidth = 0.0; + this->m_columnRight->MinWidth = 0.0; + this->m_columnLeft->MaxWidth = std::numeric_limits::max(); + this->m_columnRight->MaxWidth = std::numeric_limits::max(); + this->m_columnLeft->Width = GridLengthHelper::FromValueAndType(1, GridUnitType::Star); + this->m_columnRight->Width = GridLengthHelper::FromPixels(0); + } + + // Set row lengths + if (newMode == ViewMode::TopBottom || newMode == ViewMode::BottomTop) + { + if (newMode == ViewMode::TopBottom) + { + this->m_rowTop->MinHeight = this->Pane1MinLength; + this->m_rowTop->MaxHeight = this->Pane1MaxLength; + this->m_rowTop->Height = this->Pane1Length; + this->m_rowBottom->MinHeight = this->Pane2MinLength; + this->m_rowBottom->MaxHeight = this->Pane2MaxLength; + this->m_rowBottom->Height = this->Pane2Length; + } + else + { + this->m_rowTop->MinHeight = this->Pane2MinLength; + this->m_rowTop->MaxHeight = this->Pane2MaxLength; + this->m_rowTop->Height = this->Pane2Length; + this->m_rowBottom->MinHeight = this->Pane1MinLength; + this->m_rowBottom->MaxHeight = this->Pane1MaxLength; + this->m_rowBottom->Height = this->Pane1Length; + } + } + else + { + this->m_rowTop->MinHeight = 0.0; + this->m_rowBottom->MinHeight = 0.0; + this->m_rowTop->MaxHeight = std::numeric_limits::max(); + this->m_rowBottom->MaxHeight = std::numeric_limits::max(); + this->m_rowTop->Height = GridLengthHelper::FromValueAndType(1, GridUnitType::Star); + this->m_rowBottom->Height = GridLengthHelper::FromPixels(0); + } + + // Handle regions + if (IsInMultipleRegions(info, rcControl) && newMode != ViewMode::Pane1Only && newMode != ViewMode::Pane2Only) + { + Rect rc1 = info.Regions[0]; + Rect rc2 = info.Regions[1]; + Rect rcWindow = Window::Current->Bounds; + + if (info.Mode == MUXC::TwoPaneViewMode::Wide) + { + this->m_columnMiddle->Width = GridLengthHelper::FromPixels(rc2.X - rc1.Width); + + this->m_columnLeft->MinWidth = 0.0; + this->m_columnRight->MinWidth = 0.0; + this->m_columnLeft->MaxWidth = std::numeric_limits::max(); + this->m_columnRight->MaxWidth = std::numeric_limits::max(); + this->m_columnLeft->Width = GridLengthHelper::FromPixels(rc1.Width - rcControl.X); + this->m_columnRight->Width = GridLengthHelper::FromPixels(rc2.Width - ((rcWindow.Width - rcControl.Width) - rcControl.X)); + } + else + { + this->m_rowMiddle->Height = GridLengthHelper::FromPixels(rc2.Y - rc1.Height); + + this->m_rowTop->MinHeight = 0.0; + this->m_rowBottom->MinHeight = 0.0; + this->m_rowTop->MaxHeight = std::numeric_limits::max(); + this->m_rowBottom->MaxHeight = std::numeric_limits::max(); + this->m_rowTop->Height = GridLengthHelper::FromPixels(rc1.Height - rcControl.Y); + this->m_rowBottom->Height = GridLengthHelper::FromPixels(rc2.Height - ((rcWindow.Height - rcControl.Height) - rcControl.Y)); + } + } + } +} + +Rect TwoPaneViewCX::GetControlRect() +{ + // Find out where this control is in the window + auto transform = TransformToVisual(Window::Current->Content); + return transform->TransformBounds(RectHelper::FromCoordinatesAndDimensions(0, 0, (float)this->ActualWidth, (float)this->ActualHeight)); +} + +bool TwoPaneViewCX::IsInMultipleRegions(DisplayRegionHelperInfo info, Rect rcControl) +{ + bool isInMultipleRegions = false; + + if (info.Mode != MUXC::TwoPaneViewMode::SinglePane) + { + Rect rc1 = info.Regions[0]; + Rect rc2 = info.Regions[1]; + + if (info.Mode == MUXC::TwoPaneViewMode::Wide) + { + // Check that the control is over the split + if (rcControl.X < rc1.Width && rcControl.X + rcControl.Width > rc2.X) + { + isInMultipleRegions = true; + } + } + else if (info.Mode == MUXC::TwoPaneViewMode::Tall) + { + // Check that the control is over the split + if (rcControl.Y < rc1.Height && rcControl.Y + rcControl.Height > rc2.Y) + { + isInMultipleRegions = true; + } + } + } + + return isInMultipleRegions; +} + +void TwoPaneViewCX::OnSizeChanged(Platform::Object ^ /*sender*/, Windows::UI::Xaml::SizeChangedEventArgs ^ /*e*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnWindowSizeChanged(Platform::Object ^ /*sender*/, Windows::UI::Core::WindowSizeChangedEventArgs ^ /*e*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnPane1LengthPropertyChanged(GridLength /*oldValue*/, GridLength /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnPane2LengthPropertyChanged(GridLength /*oldValue*/, GridLength /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnPane1MinLengthPropertyChanged(double /*oldValue*/, double /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnPane2MinLengthPropertyChanged(double /*oldValue*/, double /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnPane1MaxLengthPropertyChanged(double /*oldValue*/, double /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnPane2MaxLengthPropertyChanged(double /*oldValue*/, double /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnMinTallModeHeightPropertyChanged(double /*oldValue*/, double newValue) +{ + auto clampedValue = max(0.0, newValue); + if (clampedValue != newValue) + { + this->MinTallModeHeight = clampedValue; + return; + } + this->UpdateMode(); +} + +void TwoPaneViewCX::OnMinWideModeWidthPropertyChanged(double /*oldValue*/, double newValue) +{ + auto clampedValue = max(0.0, newValue); + if (clampedValue != newValue) + { + this->MinWideModeWidth = clampedValue; + return; + } + this->UpdateMode(); +} + +void TwoPaneViewCX::OnWideModeConfigurationPropertyChanged( + MUXC::TwoPaneViewWideModeConfiguration /*oldValue*/, + MUXC::TwoPaneViewWideModeConfiguration /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnTallModeConfigurationPropertyChanged( + MUXC::TwoPaneViewTallModeConfiguration /*oldValue*/, + MUXC::TwoPaneViewTallModeConfiguration /*newValue*/) +{ + this->UpdateMode(); +} + +void TwoPaneViewCX::OnPanePriorityPropertyChanged(MUXC::TwoPaneViewPriority /*oldValue*/, MUXC::TwoPaneViewPriority /*newValue*/) +{ + this->UpdateMode(); +} + +TwoPaneViewCX::DisplayRegionHelperInfo TwoPaneViewCX::GetDisplayRegionHelperInfo() +{ + DisplayRegionHelperInfo info; + info.Mode = MUXC::TwoPaneViewMode::SinglePane; + + if (!Windows::Foundation::Metadata::ApiInformation::IsMethodPresent(L"Windows.UI.ViewManagement.ApplicationView", L"GetDisplayRegions")) + { + return info; + } + + // ApplicationView::GetForCurrentView throws on failure; in that case we just won't do anything. + ApplicationView ^ view; + try + { + view = ApplicationView::GetForCurrentView(); + } + catch (...) + { + } + + if (view && (int)view->ViewMode == 2 /*ApplicationViewMode::Spanning*/) + { + auto regions = view->GetDisplayRegions(); + if (regions->Size == 2) + { + auto region1 = regions->GetAt(0); + auto region2 = regions->GetAt(1); + info.Regions = ref new Array(2); + info.Regions[0] = RectHelper::FromCoordinatesAndDimensions( + region1->WorkAreaOffset.X, region1->WorkAreaOffset.Y, region1->WorkAreaSize.Width, region1->WorkAreaSize.Height); + info.Regions[1] = RectHelper::FromCoordinatesAndDimensions( + region2->WorkAreaOffset.X, region2->WorkAreaOffset.Y, region2->WorkAreaSize.Width, region2->WorkAreaSize.Height); + + // Determine orientation. If neither of these are true, default to doing nothing. + if (info.Regions[0].X < info.Regions[1].X && info.Regions[0].Y == info.Regions[1].Y) + { + // Double portrait + info.Mode = MUXC::TwoPaneViewMode::Wide; + } + else if (info.Regions[0].X == info.Regions[1].X && info.Regions[0].Y < info.Regions[1].Y) + { + // Double landscape + info.Mode = MUXC::TwoPaneViewMode::Tall; + } + } + } + return info; +} + +void TwoPaneViewCX::SetScrollViewerProperties(String ^ scrollViewerName) +{ + if (ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 7)) + { + if (auto scrollViewer = dynamic_cast(this->GetTemplateChild(scrollViewerName))) + { + if (ApiInformation::IsPropertyPresent(L"Windows.UI.Xaml.Controls.ScrollContentPresenter", L"SizesContentToTemplatedParent")) + { + scrollViewer->Loaded += ref new RoutedEventHandler(this, &TwoPaneViewCX::OnScrollViewerLoaded); + } + + if (ApiInformation::IsPropertyPresent(L"Windows.UI.Xaml.Controls.ScrollViewer", L"ReduceViewportForCoreInputViewOcclusions")) + { + scrollViewer->ReduceViewportForCoreInputViewOcclusions = true; + } + } + } +} + +void TwoPaneViewCX::OnScrollViewerLoaded(Object ^ sender, RoutedEventArgs ^ e) +{ + if (auto scrollViewer = dynamic_cast(sender)) + { + auto scrollContentPresenterFE = VisualTree::FindDescendantByName(scrollViewer, L"ScrollContentPresenter"); + if (scrollContentPresenterFE) + { + if (auto scrollContentPresenter = dynamic_cast(scrollContentPresenterFE)) + { + scrollContentPresenter->SizesContentToTemplatedParent = true; + } + } + } +} diff --git a/src/Calculator/Controls/TwoPaneViewCX.h b/src/Calculator/Controls/TwoPaneViewCX.h new file mode 100644 index 00000000..d3f79326 --- /dev/null +++ b/src/Calculator/Controls/TwoPaneViewCX.h @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#pragma once +#include "CalcViewModel/Common/Utils.h" + +namespace CalculatorApp::Controls +{ + ref class TwoPaneViewCX; +public + interface class ITwoPaneViewCX + { + event Windows::Foundation::TypedEventHandler ^ ModeChanged; + }; + + // We can't use the TwoPaneView control from the SDK or from Microsoft.UI.Xaml because of a bug with C++ apps. + // (see this issue: https://github.com/microsoft/microsoft-ui-xaml/pull/2045) + // This class is a C++/CX port of the C++/WinRT version of Microsoft.UI.Xaml (commit b3a2e45) which include the patch to fix the crash. + // This fork adds also 4 new properties Pane1MinLength, Pane2MinLength, Pane1MaxLength, Pane2MaxLength +public + ref class TwoPaneViewCX sealed : public Windows::UI::Xaml::Controls::Control, [Windows::Foundation::Metadata::Default] ITwoPaneViewCX + { + enum class ViewMode + { + Pane1Only, + Pane2Only, + LeftRight, + RightLeft, + TopBottom, + BottomTop, + None + }; + + struct DisplayRegionHelperInfo + { + Microsoft::UI::Xaml::Controls::TwoPaneViewMode Mode = Microsoft::UI::Xaml::Controls::TwoPaneViewMode::SinglePane; + Platform::Array ^ Regions; + }; + + public: + DEPENDENCY_PROPERTY_OWNER(TwoPaneViewCX); + DEPENDENCY_PROPERTY(Windows::UI::Xaml::UIElement ^, Pane1); + DEPENDENCY_PROPERTY(Windows::UI::Xaml::UIElement ^, Pane2); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK( + Windows::UI::Xaml::GridLength, + Pane1Length, + Windows::UI::Xaml::GridLengthHelper::FromValueAndType(1, Windows::UI::Xaml::GridUnitType::Auto)); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK( + Windows::UI::Xaml::GridLength, + Pane2Length, + Windows::UI::Xaml::GridLengthHelper::FromValueAndType(1, Windows::UI::Xaml::GridUnitType::Star)); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, Pane1MinLength, 0.0); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, Pane2MinLength, 0.0); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, Pane1MaxLength, std::numeric_limits::max()); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, Pane2MaxLength, std::numeric_limits::max()); + + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(Microsoft::UI::Xaml::Controls::TwoPaneViewPriority, + PanePriority, + Microsoft::UI::Xaml::Controls::TwoPaneViewPriority::Pane1); + DEPENDENCY_PROPERTY(Microsoft::UI::Xaml::Controls::TwoPaneViewMode, Mode); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK( + Microsoft::UI::Xaml::Controls::TwoPaneViewWideModeConfiguration, + WideModeConfiguration, + Microsoft::UI::Xaml::Controls::TwoPaneViewWideModeConfiguration::LeftRight); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK( + Microsoft::UI::Xaml::Controls::TwoPaneViewTallModeConfiguration, + TallModeConfiguration, + Microsoft::UI::Xaml::Controls::TwoPaneViewTallModeConfiguration::TopBottom); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, MinWideModeWidth, 641); + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, MinTallModeHeight, 641); + + TwoPaneViewCX(); + virtual ~TwoPaneViewCX(); + void OnApplyTemplate() override; + virtual event Windows::Foundation::TypedEventHandler ^ ModeChanged; + + private: + void UpdateRowsColumns(ViewMode newMode, DisplayRegionHelperInfo info, Windows::Foundation::Rect rcControl); + void UpdateMode(); + bool IsInMultipleRegions(DisplayRegionHelperInfo info, Windows::Foundation::Rect rcControl); + void SetScrollViewerProperties(Platform::String ^ scrollViewerName); + Windows::Foundation::Rect GetControlRect(); + DisplayRegionHelperInfo GetDisplayRegionHelperInfo(); + + void OnSizeChanged(Platform::Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e); + void OnWindowSizeChanged(Platform::Object ^ sender, Windows::UI::Core::WindowSizeChangedEventArgs ^ e); + void OnPane1LengthPropertyChanged(Windows::UI::Xaml::GridLength oldValue, Windows::UI::Xaml::GridLength newValue); + void OnPane2LengthPropertyChanged(Windows::UI::Xaml::GridLength oldValue, Windows::UI::Xaml::GridLength newValue); + void OnPane1MinLengthPropertyChanged(double oldValue, double newValue); + void OnPane2MinLengthPropertyChanged(double oldValue, double newValue); + void OnPane1MaxLengthPropertyChanged(double oldValue, double newValue); + void OnPane2MaxLengthPropertyChanged(double oldValue, double newValue); + void + OnPanePriorityPropertyChanged(Microsoft::UI::Xaml::Controls::TwoPaneViewPriority oldValue, Microsoft::UI::Xaml::Controls::TwoPaneViewPriority newValue); + void OnMinTallModeHeightPropertyChanged(double oldValue, double newValue); + void OnMinWideModeWidthPropertyChanged(double oldValue, double newValue); + void OnWideModeConfigurationPropertyChanged( + Microsoft::UI::Xaml::Controls::TwoPaneViewWideModeConfiguration oldValue, + Microsoft::UI::Xaml::Controls::TwoPaneViewWideModeConfiguration newValue); + void OnTallModeConfigurationPropertyChanged( + Microsoft::UI::Xaml::Controls::TwoPaneViewTallModeConfiguration oldValue, + Microsoft::UI::Xaml::Controls::TwoPaneViewTallModeConfiguration newValue); + void OnScrollViewerLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + + private: + Windows::UI::Xaml::Controls::ColumnDefinition ^ m_columnLeft; + Windows::UI::Xaml::Controls::ColumnDefinition ^ m_columnMiddle; + Windows::UI::Xaml::Controls::ColumnDefinition ^ m_columnRight; + Windows::UI::Xaml::Controls::RowDefinition ^ m_rowTop; + Windows::UI::Xaml::Controls::RowDefinition ^ m_rowMiddle; + Windows::UI::Xaml::Controls::RowDefinition ^ m_rowBottom; + Windows::Foundation::EventRegistrationToken m_windowSizeChangedToken; + ViewMode m_currentMode{ ViewMode::None }; + bool m_loaded{ false }; + }; +} diff --git a/src/Calculator/MultiTrigger.cpp b/src/Calculator/MultiTrigger.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/Calculator/MultiTrigger.h b/src/Calculator/MultiTrigger.h new file mode 100644 index 00000000..e69de29b diff --git a/src/Calculator/Package.appxmanifest b/src/Calculator/Package.appxmanifest index 76d1c97f..db28a967 100644 --- a/src/Calculator/Package.appxmanifest +++ b/src/Calculator/Package.appxmanifest @@ -8,7 +8,7 @@ Assets\CalculatorStoreLogo.png - + diff --git a/src/Calculator/Views/Calculator.xaml b/src/Calculator/Views/Calculator.xaml index 71dddefa..274ee6ea 100644 --- a/src/Calculator/Views/Calculator.xaml +++ b/src/Calculator/Views/Calculator.xaml @@ -8,6 +8,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:CalculatorApp" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:triggers="using:CalculatorApp.Views.StateTriggers" Loaded="OnLoaded" mc:Ignorable="d"> @@ -382,15 +383,7 @@ Icon="Paste"/> - - - - - - @@ -415,18 +408,13 @@ - + - + - - - - - @@ -460,12 +448,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -476,7 +496,7 @@ - + @@ -487,8 +507,8 @@ - - + + @@ -516,11 +536,18 @@ - + + + + + + + + - + @@ -529,7 +556,7 @@ - + @@ -539,8 +566,6 @@ - - @@ -574,704 +599,751 @@ - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4,4,0,0 + 0,0,4,4 + 4,0,0,4 + 0,4,4,0 + + + + 4,4,0,0 + 0,0,4,4 + 4,0,0,4 + 0,4,4,0 + + + + 0 + 0 + 0 + 0 + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - - - + + - - - - - - - - - - + + - - - - - - + - - - - - - - - - + + + diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp index 1a2096f4..8619f1e5 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp @@ -49,8 +49,9 @@ using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Media::Imaging; using namespace Windows::UI::Popups; using namespace Windows::UI::ViewManagement; +namespace MUXC = Microsoft::UI::Xaml::Controls; -constexpr auto sc_ViewModelPropertyName = L"ViewModel"; + constexpr auto sc_ViewModelPropertyName = L"ViewModel"; DEPENDENCY_PROPERTY_INITIALIZATION(GraphingCalculator, IsSmallState); DEPENDENCY_PROPERTY_INITIALIZATION(GraphingCalculator, GraphControlAutomationName); @@ -434,9 +435,9 @@ void GraphingCalculator::OnKeyGraphFeaturesClosed(Object ^ sender, RoutedEventAr ViewModel->SelectedEquation->GraphEquation->IsSelected = false; } -Visibility GraphingCalculator::ShouldDisplayPanel(bool isSmallState, bool isEquationModeActivated, bool isGraphPanel) +MUXC::TwoPaneViewPriority GraphingCalculator::GetPanePriority(bool isEquationModeActivated) { - return (!isSmallState || isEquationModeActivated ^ isGraphPanel) ? ::Visibility::Visible : ::Visibility::Collapsed; + return isEquationModeActivated ? MUXC::TwoPaneViewPriority::Pane2 : MUXC::TwoPaneViewPriority::Pane1; } Platform::String ^ GraphingCalculator::GetInfoForSwitchModeToggleButton(bool isChecked) @@ -573,7 +574,10 @@ void GraphingCalculator::DisplayGraphSettings() auto flyoutGraphSettings = ref new Flyout(); flyoutGraphSettings->Content = graphSettings; flyoutGraphSettings->Closing += ref new TypedEventHandler(this, &GraphingCalculator::OnSettingsFlyout_Closing); - flyoutGraphSettings->ShowAt(GraphSettingsButton); + + auto options = ref new FlyoutShowOptions(); + options->Placement = FlyoutPlacementMode::BottomEdgeAlignedRight; + flyoutGraphSettings->ShowAt(GraphSettingsButton, options); } void CalculatorApp::GraphingCalculator::AddTracePointerShadow() diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h index 9810ce88..5e1988a2 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h @@ -9,7 +9,9 @@ #include "Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml.h" #include "Views\GraphingCalculator\GraphingNumPad.xaml.h" #include "Views\GraphingCalculator\GraphingSettings.xaml.h" -#include "CalcViewModel/Common/TraceLogger.h" +#include "Views\StateTriggers\ApplicationViewModeTrigger.h" +#include "Controls\TwoPaneViewCX.h" +#include "CalcViewModel\Common\TraceLogger.h" namespace CalculatorApp { @@ -36,7 +38,7 @@ public ref class GraphingCalculator sealed : public Windows::UI::Xaml::Data::INo void set(CalculatorApp::ViewModel::GraphingCalculatorViewModel^ vm); } - static Windows::UI::Xaml::Visibility ShouldDisplayPanel(bool isSmallState, bool isEquationModeActivated, bool isGraphPanel); + static Microsoft::UI::Xaml::Controls::TwoPaneViewPriority GetPanePriority(bool isEquationModeActivated); static Platform::String ^ GetInfoForSwitchModeToggleButton(bool isChecked); static Windows::UI::Xaml::Visibility ManageEditVariablesButtonVisibility(unsigned int numberOfVariables); static Platform::String ^ GetTracingLegend(Platform::IBox ^ isTracing); diff --git a/src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.cpp b/src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.cpp new file mode 100644 index 00000000..fb7c947a --- /dev/null +++ b/src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.cpp @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "ApplicationViewModeTrigger.h" +using namespace CalculatorApp::Views::StateTriggers; +using namespace Windows::System::Profile; +using namespace Windows::UI::ViewManagement; +using namespace Windows::UI::Xaml; + +DEPENDENCY_PROPERTY_INITIALIZATION(ApplicationViewModeTrigger, ViewMode); +DEPENDENCY_PROPERTY_INITIALIZATION(ApplicationViewModeTrigger, MinWindowHeight); +DEPENDENCY_PROPERTY_INITIALIZATION(ApplicationViewModeTrigger, MinWindowWidth); + +ApplicationViewModeTrigger::ApplicationViewModeTrigger() +{ + m_windowSizeEventToken = Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &ApplicationViewModeTrigger::WindowSizeChanged); + UpdateTrigger(); +} + +void ApplicationViewModeTrigger::WindowSizeChanged(_In_ Platform::Object ^ /*sender*/, _In_ Windows::UI::Core::WindowSizeChangedEventArgs ^ /*e*/) +{ + // We don't use layout aware page's view states, we have our own + UpdateTrigger(); +} +void ApplicationViewModeTrigger::OnViewModePropertyChanged(_In_ AppViewMode /*oldValue*/, _In_ AppViewMode /*newValue*/) +{ + UpdateTrigger(); +} +void ApplicationViewModeTrigger::OnMinWindowHeightPropertyChanged(double /*oldValue*/, double /*newValue*/) +{ + UpdateTrigger(); +} + +void ApplicationViewModeTrigger::OnMinWindowWidthPropertyChanged(double /*oldValue*/, double /*newValue*/) +{ + UpdateTrigger(); +} + +void ApplicationViewModeTrigger::UpdateTrigger() +{ + auto applicationView = ApplicationView::GetForCurrentView(); + auto viewMode = applicationView->ViewMode; + if (applicationView->VisibleBounds.Width < this->MinWindowWidth || applicationView->VisibleBounds.Height < this->MinWindowHeight) + { + SetActive(false); + return; + } + + switch (static_cast(viewMode)) + { + case 0 /*ApplicationViewMode::Default*/: + SetActive(this->ViewMode == AppViewMode::Normal); + break; + case 1 /*ApplicationViewMode::CompactOverlay*/: + SetActive(this->ViewMode == AppViewMode::CompactOverlay); + break; + case 2 /*ApplicationViewMode::Spanning*/: + + // We will need to update this code to use new SpanningRects API instead of DisplayRegions when the app will use the SDK for windows 10 2004. + auto displayRegions = applicationView->GetDisplayRegions(); + if (displayRegions->Size == 2) + { + auto display1 = displayRegions->GetAt(0); + auto display2 = displayRegions->GetAt(1); + if (display1->WorkAreaOffset.X < display2->WorkAreaOffset.X && display1->WorkAreaOffset.Y == display2->WorkAreaOffset.Y) + { + this->SetActive(this->ViewMode == AppViewMode::DoublePortrait); + return; + } + else if (display1->WorkAreaOffset.X == display2->WorkAreaOffset.X && display1->WorkAreaOffset.Y < display2->WorkAreaOffset.Y) + { + this->SetActive(this->ViewMode == AppViewMode::DoubleLandscape); + return; + } + } + SetActive(this->ViewMode == AppViewMode::Normal); + break; + } +} diff --git a/src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.h b/src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.h new file mode 100644 index 00000000..a708ea1b --- /dev/null +++ b/src/Calculator/Views/StateTriggers/ApplicationViewModeTrigger.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "CalcViewModel/Common/Utils.h" + +namespace CalculatorApp::Views::StateTriggers +{ +public + enum class AppViewMode + { + Normal = 0, + CompactOverlay = 1, + DoublePortrait = 2, + DoubleLandscape = 3 + }; + +public + ref class ApplicationViewModeTrigger sealed : public Windows::UI::Xaml::StateTriggerBase + { + public: + ApplicationViewModeTrigger(); + DEPENDENCY_PROPERTY_OWNER(ApplicationViewModeTrigger); + + /* The view mode that will cause the trigger to fire. */ + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(AppViewMode, ViewMode, AppViewMode::Normal); + + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, MinWindowHeight, -1); + + DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(double, MinWindowWidth, -1); + private: + void OnViewModePropertyChanged(AppViewMode oldValue, AppViewMode newValue); + void OnMinWindowHeightPropertyChanged(double oldValue, double newValue); + void OnMinWindowWidthPropertyChanged(double oldValue, double newValue); + void WindowSizeChanged(_In_ Platform::Object ^ sender, _In_ Windows::UI::Core::WindowSizeChangedEventArgs ^ e); + void UpdateTrigger(); + private: + Windows::Foundation::EventRegistrationToken m_windowSizeEventToken; + }; +} diff --git a/src/Calculator/Views/TitleBar.xaml.cpp b/src/Calculator/Views/TitleBar.xaml.cpp index 44f4a8c4..99958823 100644 --- a/src/Calculator/Views/TitleBar.xaml.cpp +++ b/src/Calculator/Views/TitleBar.xaml.cpp @@ -5,9 +5,11 @@ #include "TitleBar.xaml.h" #include "CalcViewModel/Common/AppResourceProvider.h" #include "CalcViewModel/Common/Utils.h" +#include "CalcViewModel/Utils/DeviceFamilyHelper.h" using namespace std; using namespace Platform; +using namespace CalculatorApp::ViewModel::Utils; using namespace Windows::ApplicationModel; using namespace Windows::ApplicationModel::Core; using namespace Windows::Foundation; @@ -50,7 +52,7 @@ namespace CalculatorApp [this](CoreApplicationViewTitleBar ^ cTitleBar, Object ^) { this->SetTitleBarVisibility(); }); m_layoutChangedToken = m_coreTitleBar->LayoutMetricsChanged += ref new TypedEventHandler([this](CoreApplicationViewTitleBar ^ cTitleBar, Object ^) { - this->LayoutRoot->Height = cTitleBar->Height; + this->SetTitleBarHeight(); this->SetTitleBarPadding(); }); @@ -60,11 +62,10 @@ namespace CalculatorApp m_windowActivatedToken = Window::Current->Activated += ref new Windows::UI::Xaml::WindowActivatedEventHandler(this, &CalculatorApp::TitleBar::OnWindowActivated); // Set properties - LayoutRoot->Height = m_coreTitleBar->Height; - SetTitleBarControlColors(); - - SetTitleBarVisibility(); - SetTitleBarPadding(); + this->SetTitleBarHeight(); + this->SetTitleBarControlColors(); + this->SetTitleBarVisibility(); + this->SetTitleBarPadding(); } void TitleBar::OnUnloaded(_In_ Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/) @@ -84,7 +85,25 @@ namespace CalculatorApp void TitleBar::SetTitleBarVisibility() { - this->LayoutRoot->Visibility = m_coreTitleBar->IsVisible || IsAlwaysOnTopMode ? ::Visibility::Visible : ::Visibility::Collapsed; + // CoreApplication::GetCurrentView()->TitleBar->IsVisible currently returns False instead of True on Windows 10X. + // This issue is already tracked and will be fixed in a future preview version of 10X. + this->LayoutRoot->Visibility = m_coreTitleBar->IsVisible || DeviceFamilyHelper::GetDeviceFamily() == DeviceFamily::WindowsCore || IsAlwaysOnTopMode + ? ::Visibility::Visible + : ::Visibility::Collapsed; + } + + void TitleBar::SetTitleBarHeight() + { + if (m_coreTitleBar->Height == 0 && DeviceFamilyHelper::GetDeviceFamily() == DeviceFamily::WindowsCore) + { + // CoreApplication::GetCurrentView()->TitleBar doesn't return the correct height on Windows 10X. + // This issue is already tracked and will be fixed in a future preview version of 10X. + this->LayoutRoot->Height = 32; + } + else + { + this->LayoutRoot->Height = m_coreTitleBar->Height; + } } void TitleBar::SetTitleBarPadding() diff --git a/src/Calculator/Views/TitleBar.xaml.h b/src/Calculator/Views/TitleBar.xaml.h index 53bf6ff7..98325c18 100644 --- a/src/Calculator/Views/TitleBar.xaml.h +++ b/src/Calculator/Views/TitleBar.xaml.h @@ -29,6 +29,7 @@ public void SetTitleBarText(Platform::String ^ text); void SetTitleBarVisibility(); + void SetTitleBarHeight(); void SetTitleBarPadding(); void SetTitleBarControlColors(); void ColorValuesChanged(_In_ Windows::UI::ViewManagement::UISettings ^ sender, _In_ Platform::Object ^ e); diff --git a/src/Calculator/Views/UnitConverter.xaml b/src/Calculator/Views/UnitConverter.xaml index 60fd7248..31b13705 100644 --- a/src/Calculator/Views/UnitConverter.xaml +++ b/src/Calculator/Views/UnitConverter.xaml @@ -277,36 +277,47 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + - - - - - + + @@ -400,7 +409,6 @@ - @@ -437,8 +445,8 @@ - - + + @@ -506,259 +514,287 @@ - - - - - - - + + + + + + + + + + + - + Grid.RowSpan="5" + Visibility="Collapsed"> + + + + + + + - - - - - - - - - + + + + + + + + + - + - - - - - - - - - + + + + + + + + + - + - - - - - + + + + + - - + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + diff --git a/src/Calculator/Views/UnitConverter.xaml.h b/src/Calculator/Views/UnitConverter.xaml.h index 16c669c0..21a69219 100644 --- a/src/Calculator/Views/UnitConverter.xaml.h +++ b/src/Calculator/Views/UnitConverter.xaml.h @@ -13,6 +13,7 @@ #include "Converters/VisibilityNegationConverter.h" #include "CalcViewModel/UnitConverterViewModel.h" #include "Views/StateTriggers/AspectRatioTrigger.h" +#include "Views/StateTriggers/ApplicationViewModeTrigger.h" namespace CalculatorApp { diff --git a/src/Calculator/packages.config b/src/Calculator/packages.config index a33d8464..ef1db862 100644 --- a/src/Calculator/packages.config +++ b/src/Calculator/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/src/Calculator/pch.h b/src/Calculator/pch.h index 13812fec..0ae56d8d 100644 --- a/src/Calculator/pch.h +++ b/src/Calculator/pch.h @@ -41,6 +41,7 @@ #include "winrt/Windows.System.UserProfile.h" #include "winrt/Windows.UI.ViewManagement.h" #include "winrt/Windows.UI.Xaml.h" +#include "winrt/Windows.System.Profile.h" #include "winrt/Windows.Foundation.h" // Project Headers