mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-22 14:13:30 -07:00
Refactor SupplementaryItemsControl to improve performance, not rely on parents and not force the parent element to be HorizonAlignment="stretch"
This commit is contained in:
parent
0f1d6c29cf
commit
c62340b6bf
8 changed files with 121 additions and 71 deletions
|
@ -257,6 +257,7 @@
|
||||||
<ClInclude Include="Converters\ItemSizeToVisibilityConverter.h" />
|
<ClInclude Include="Converters\ItemSizeToVisibilityConverter.h" />
|
||||||
<ClInclude Include="Converters\RadixToStringConverter.h" />
|
<ClInclude Include="Converters\RadixToStringConverter.h" />
|
||||||
<ClInclude Include="Converters\VisibilityNegationConverter.h" />
|
<ClInclude Include="Converters\VisibilityNegationConverter.h" />
|
||||||
|
<ClInclude Include="Controls\HorizontalNoOverflowStackPanel.h" />
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
<ClInclude Include="App.xaml.h">
|
<ClInclude Include="App.xaml.h">
|
||||||
<DependentUpon>App.xaml</DependentUpon>
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
@ -390,6 +391,7 @@
|
||||||
<ClCompile Include="Converters\ItemSizeToVisibilityConverter.cpp" />
|
<ClCompile Include="Converters\ItemSizeToVisibilityConverter.cpp" />
|
||||||
<ClCompile Include="Converters\RadixToStringConverter.cpp" />
|
<ClCompile Include="Converters\RadixToStringConverter.cpp" />
|
||||||
<ClCompile Include="Converters\VisibilityNegationConverter.cpp" />
|
<ClCompile Include="Converters\VisibilityNegationConverter.cpp" />
|
||||||
|
<ClCompile Include="Controls\HorizontalNoOverflowStackPanel.cpp" />
|
||||||
<ClCompile Include="pch.cpp">
|
<ClCompile Include="pch.cpp">
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
|
66
src/Calculator/Controls/HorizontalNoOverflowStackPanel.cpp
Normal file
66
src/Calculator/Controls/HorizontalNoOverflowStackPanel.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
//
|
||||||
|
// HorizontalNoOverflowStackPanel.xaml.cpp
|
||||||
|
// Implementation of the HorizontalNoOverflowStackPanel class
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include "HorizontalNoOverflowStackPanel.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace CalculatorApp::Controls;
|
||||||
|
using namespace Windows::Foundation;
|
||||||
|
|
||||||
|
Size HorizontalNoOverflowStackPanel::MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
float maxHeight = 0;
|
||||||
|
float width = 0;
|
||||||
|
for (auto child : Children)
|
||||||
|
{
|
||||||
|
child->Measure(Size(numeric_limits<float>::infinity(), numeric_limits<float>::infinity()));
|
||||||
|
maxHeight = max(maxHeight, child->DesiredSize.Height);
|
||||||
|
width += child->DesiredSize.Width;
|
||||||
|
}
|
||||||
|
return Size(min(width, availableSize.Width), min(availableSize.Height, maxHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HorizontalNoOverflowStackPanel::ShouldPrioritizeLastItem()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size HorizontalNoOverflowStackPanel::ArrangeOverride(Size finalSize)
|
||||||
|
{
|
||||||
|
float posX = 0;
|
||||||
|
if (Children->Size == 0)
|
||||||
|
return finalSize;
|
||||||
|
|
||||||
|
auto lastChild = Children->GetAt(Children->Size - 1);
|
||||||
|
float lastChildWidth = 0;
|
||||||
|
if (Children->Size > 2 && ShouldPrioritizeLastItem())
|
||||||
|
lastChildWidth = lastChild->DesiredSize.Width;
|
||||||
|
for (auto item : Children)
|
||||||
|
{
|
||||||
|
auto widthAvailable = finalSize.Width - posX;
|
||||||
|
if (item != lastChild)
|
||||||
|
{
|
||||||
|
widthAvailable -= lastChildWidth;
|
||||||
|
}
|
||||||
|
float itemWidth = item->DesiredSize.Width;
|
||||||
|
if (widthAvailable > 0 && itemWidth <= widthAvailable)
|
||||||
|
{
|
||||||
|
//stack the items horizontally (left to right)
|
||||||
|
item->Arrange(Rect(posX, 0, itemWidth, finalSize.Height));
|
||||||
|
posX += item->DesiredSize.Width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Not display the item
|
||||||
|
item->Arrange(Rect(0, 0, 0, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return finalSize;
|
||||||
|
}
|
||||||
|
|
28
src/Calculator/Controls/HorizontalNoOverflowStackPanel.h
Normal file
28
src/Calculator/Controls/HorizontalNoOverflowStackPanel.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
//
|
||||||
|
// HorizontalNoOverflowStackPanel.h
|
||||||
|
// Declaration of the HorizontalNoOverflowStackPanel class
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "CalcViewModel/Common/Utils.h"
|
||||||
|
|
||||||
|
namespace CalculatorApp
|
||||||
|
{
|
||||||
|
namespace Controls
|
||||||
|
{
|
||||||
|
public ref class HorizontalNoOverflowStackPanel : public Windows::UI::Xaml::Controls::Panel
|
||||||
|
{
|
||||||
|
DEPENDENCY_PROPERTY_OWNER(HorizontalNoOverflowStackPanel);
|
||||||
|
//Prioritize the last item over all other items (except the first one)
|
||||||
|
internal:
|
||||||
|
HorizontalNoOverflowStackPanel() {}
|
||||||
|
protected:
|
||||||
|
virtual Windows::Foundation::Size MeasureOverride(Windows::Foundation::Size availableSize) override;
|
||||||
|
virtual Windows::Foundation::Size ArrangeOverride(Windows::Foundation::Size finalSize) override;
|
||||||
|
virtual bool ShouldPrioritizeLastItem();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,5 +38,3 @@ void SupplementaryItemsControl::PrepareContainerForItemOverride(DependencyObject
|
||||||
{
|
{
|
||||||
return ref new SupplementaryContentPresenterAP(this);
|
return ref new SupplementaryContentPresenterAP(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
<Setter Property="ItemsPanel">
|
<Setter Property="ItemsPanel">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<StackPanel Orientation="Horizontal"/>
|
<local:SupplementaryResultNoOverflowStackPanel/>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
|
@ -102,6 +102,6 @@
|
||||||
Style="{ThemeResource SupplementaryValuesStyle}"
|
Style="{ThemeResource SupplementaryValuesStyle}"
|
||||||
IsTextScaleFactorEnabled="False"
|
IsTextScaleFactorEnabled="False"
|
||||||
ItemTemplateSelector="{StaticResource ResultTemplateSelector}"
|
ItemTemplateSelector="{StaticResource ResultTemplateSelector}"
|
||||||
LayoutUpdated="OnSupplementaryValuesLayoutUpdated"/>
|
ItemsSource="{x:Bind Results, Mode=OneWay}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
// Licensed under the MIT License.
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -27,6 +27,8 @@ using namespace Windows::UI::Xaml::Navigation;
|
||||||
|
|
||||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||||
|
|
||||||
|
DEPENDENCY_PROPERTY_INITIALIZATION(SupplementaryResults, Results);
|
||||||
|
|
||||||
Object^ DelighterUnitToStyleConverter::Convert(Object^ value, TypeName /*targetType*/, Object^ /*parameter*/, String^ /*language*/)
|
Object^ DelighterUnitToStyleConverter::Convert(Object^ value, TypeName /*targetType*/, Object^ /*parameter*/, String^ /*language*/)
|
||||||
{
|
{
|
||||||
Unit^ unit = safe_cast<Unit^>(value);
|
Unit^ unit = safe_cast<Unit^>(value);
|
||||||
|
@ -66,70 +68,17 @@ SupplementaryResults::SupplementaryResults() :
|
||||||
m_data(ref new Vector<SupplementaryResult^>)
|
m_data(ref new Vector<SupplementaryResult^>)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this->Loaded += ref new RoutedEventHandler(this, &SupplementaryResults::OnLoaded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SupplementaryResults::RefreshData()
|
bool SupplementaryResultNoOverflowStackPanel::ShouldPrioritizeLastItem()
|
||||||
{
|
{
|
||||||
// Copy the list so that when we chop stuff off, we don't modify the original
|
if (Children->Size == 0)
|
||||||
// complete list.
|
return false;
|
||||||
m_data->Clear();
|
auto lastChild = dynamic_cast<FrameworkElement^>(Children->GetAt(Children->Size - 1));
|
||||||
for(SupplementaryResult^ sr : safe_cast<UnitConverterViewModel^>(this->DataContext)->SupplementaryResults)
|
if (lastChild == nullptr)
|
||||||
{
|
return false;
|
||||||
m_data->Append(sr);
|
auto suppResult = dynamic_cast<SupplementaryResult^>(lastChild->DataContext);
|
||||||
}
|
if (suppResult == nullptr)
|
||||||
|
return false;
|
||||||
// Set as source
|
return suppResult->IsWhimsical();
|
||||||
SupplementaryValues->ItemsSource = m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SupplementaryResults::OnLoaded(Object^ sender, RoutedEventArgs^ e)
|
|
||||||
{
|
|
||||||
UnitConverterViewModel^ vm = safe_cast<UnitConverterViewModel^>(this->DataContext);
|
|
||||||
vm->PropertyChanged += ref new PropertyChangedEventHandler(this, &SupplementaryResults::OnConverterPropertyChanged);
|
|
||||||
Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &SupplementaryResults::OnWindowSizeChanged);
|
|
||||||
// We may be loaded into a state where we need to render (like rehydrate), so prepare data
|
|
||||||
RefreshData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SupplementaryResults::OnConverterPropertyChanged(Object^ /*sender*/, PropertyChangedEventArgs^ e)
|
|
||||||
{
|
|
||||||
if (e->PropertyName == UnitConverterViewModelProperties::SupplementaryResults)
|
|
||||||
{
|
|
||||||
RefreshData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SupplementaryResults::OnWindowSizeChanged(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e)
|
|
||||||
{
|
|
||||||
// to reload supplementary results every time the window is resized
|
|
||||||
RefreshData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SupplementaryResults::OnSupplementaryValuesLayoutUpdated(Platform::Object^ sender, Platform::Object^ e)
|
|
||||||
{
|
|
||||||
// This means we overflowed and are cutting off, or in a very rare case we fit exactly. Unfortunately
|
|
||||||
// the fitting exactly case will still have an item removed, as there is no other way for us to
|
|
||||||
// detect that we need to trim.
|
|
||||||
Grid^ parentGrid = dynamic_cast<Grid^>(VisualTreeHelper::GetParent(this));
|
|
||||||
if (parentGrid != nullptr)
|
|
||||||
{
|
|
||||||
double parentWidth = parentGrid->ActualWidth;
|
|
||||||
if (SupplementaryValues && SupplementaryValues->ActualWidth >= parentWidth)
|
|
||||||
{
|
|
||||||
if (m_data->Size > 0)
|
|
||||||
{
|
|
||||||
SupplementaryResult^ last = m_data->GetAt(m_data->Size - 1);
|
|
||||||
if (!last->IsWhimsical() || m_data->Size <= 2)
|
|
||||||
{
|
|
||||||
m_data->RemoveAtEnd();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_data->RemoveAt(m_data->Size - 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "Controls/SupplementaryItemsControl.h"
|
#include "Controls/SupplementaryItemsControl.h"
|
||||||
#include "Controls/OperandTextBox.h"
|
#include "Controls/OperandTextBox.h"
|
||||||
#include "Controls/OperatorTextBox.h"
|
#include "Controls/OperatorTextBox.h"
|
||||||
|
#include "Controls/HorizontalNoOverflowStackPanel.h"
|
||||||
#include "CalcViewModel/UnitConverterViewModel.h"
|
#include "CalcViewModel/UnitConverterViewModel.h"
|
||||||
|
|
||||||
namespace CalculatorApp
|
namespace CalculatorApp
|
||||||
|
@ -58,18 +59,23 @@ namespace CalculatorApp
|
||||||
Windows::UI::Xaml::DataTemplate^ m_delighterTemplate;
|
Windows::UI::Xaml::DataTemplate^ m_delighterTemplate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public ref class SupplementaryResultNoOverflowStackPanel sealed: public CalculatorApp::Controls::HorizontalNoOverflowStackPanel
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual bool ShouldPrioritizeLastItem() override;
|
||||||
|
};
|
||||||
|
|
||||||
[Windows::Foundation::Metadata::WebHostHidden]
|
[Windows::Foundation::Metadata::WebHostHidden]
|
||||||
public ref class SupplementaryResults sealed
|
public ref class SupplementaryResults sealed
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SupplementaryResults();
|
SupplementaryResults();
|
||||||
|
DEPENDENCY_PROPERTY_OWNER(SupplementaryResults);
|
||||||
|
DEPENDENCY_PROPERTY_WITH_DEFAULT(Windows::Foundation::Collections::IIterable<ViewModel::SupplementaryResult^>^, Results, nullptr);
|
||||||
private:
|
private:
|
||||||
void RefreshData();
|
void RefreshData();
|
||||||
void OnLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
void OnLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||||
void OnConverterPropertyChanged(Platform::Object^ sender, Windows::UI::Xaml::Data::PropertyChangedEventArgs^ e);
|
void OnConverterPropertyChanged(Platform::Object^ sender, Windows::UI::Xaml::Data::PropertyChangedEventArgs^ e);
|
||||||
void OnSupplementaryValuesLayoutUpdated(Platform::Object^ sender, Platform::Object^ e);
|
|
||||||
void OnWindowSizeChanged(Platform::Object^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ e);
|
|
||||||
Windows::Foundation::Collections::IObservableVector<ViewModel::SupplementaryResult^>^ m_data;
|
Windows::Foundation::Collections::IObservableVector<ViewModel::SupplementaryResult^>^ m_data;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -599,6 +599,7 @@
|
||||||
<local:SupplementaryResults x:Name="SupplementaryResults"
|
<local:SupplementaryResults x:Name="SupplementaryResults"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
Results="{x:Bind Model.SupplementaryResults, Mode=OneWay}"
|
||||||
Visibility="{x:Bind Model.SupplementaryVisibility, Mode=OneWay}"/>
|
Visibility="{x:Bind Model.SupplementaryVisibility, Mode=OneWay}"/>
|
||||||
<StackPanel Visibility="{x:Bind Model.IsCurrencyCurrentCategory, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
|
<StackPanel Visibility="{x:Bind Model.IsCurrencyCurrentCategory, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||||
<!-- Currency Ratio Equality -->
|
<!-- Currency Ratio Equality -->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue