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\RadixToStringConverter.h" />
|
||||
<ClInclude Include="Converters\VisibilityNegationConverter.h" />
|
||||
<ClInclude Include="Controls\HorizontalNoOverflowStackPanel.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="App.xaml.h">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
|
@ -390,6 +391,7 @@
|
|||
<ClCompile Include="Converters\ItemSizeToVisibilityConverter.cpp" />
|
||||
<ClCompile Include="Converters\RadixToStringConverter.cpp" />
|
||||
<ClCompile Include="Converters\VisibilityNegationConverter.cpp" />
|
||||
<ClCompile Include="Controls\HorizontalNoOverflowStackPanel.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal"/>
|
||||
<local:SupplementaryResultNoOverflowStackPanel/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
@ -102,6 +102,6 @@
|
|||
Style="{ThemeResource SupplementaryValuesStyle}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
ItemTemplateSelector="{StaticResource ResultTemplateSelector}"
|
||||
LayoutUpdated="OnSupplementaryValuesLayoutUpdated"/>
|
||||
ItemsSource="{x:Bind Results, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// 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
|
||||
|
||||
DEPENDENCY_PROPERTY_INITIALIZATION(SupplementaryResults, Results);
|
||||
|
||||
Object^ DelighterUnitToStyleConverter::Convert(Object^ value, TypeName /*targetType*/, Object^ /*parameter*/, String^ /*language*/)
|
||||
{
|
||||
Unit^ unit = safe_cast<Unit^>(value);
|
||||
|
@ -66,70 +68,17 @@ SupplementaryResults::SupplementaryResults() :
|
|||
m_data(ref new Vector<SupplementaryResult^>)
|
||||
{
|
||||
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
|
||||
// complete list.
|
||||
m_data->Clear();
|
||||
for(SupplementaryResult^ sr : safe_cast<UnitConverterViewModel^>(this->DataContext)->SupplementaryResults)
|
||||
{
|
||||
m_data->Append(sr);
|
||||
}
|
||||
|
||||
// Set as source
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Children->Size == 0)
|
||||
return false;
|
||||
auto lastChild = dynamic_cast<FrameworkElement^>(Children->GetAt(Children->Size - 1));
|
||||
if (lastChild == nullptr)
|
||||
return false;
|
||||
auto suppResult = dynamic_cast<SupplementaryResult^>(lastChild->DataContext);
|
||||
if (suppResult == nullptr)
|
||||
return false;
|
||||
return suppResult->IsWhimsical();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Controls/SupplementaryItemsControl.h"
|
||||
#include "Controls/OperandTextBox.h"
|
||||
#include "Controls/OperatorTextBox.h"
|
||||
#include "Controls/HorizontalNoOverflowStackPanel.h"
|
||||
#include "CalcViewModel/UnitConverterViewModel.h"
|
||||
|
||||
namespace CalculatorApp
|
||||
|
@ -58,18 +59,23 @@ namespace CalculatorApp
|
|||
Windows::UI::Xaml::DataTemplate^ m_delighterTemplate;
|
||||
};
|
||||
|
||||
public ref class SupplementaryResultNoOverflowStackPanel sealed: public CalculatorApp::Controls::HorizontalNoOverflowStackPanel
|
||||
{
|
||||
protected:
|
||||
virtual bool ShouldPrioritizeLastItem() override;
|
||||
};
|
||||
|
||||
[Windows::Foundation::Metadata::WebHostHidden]
|
||||
public ref class SupplementaryResults sealed
|
||||
{
|
||||
public:
|
||||
SupplementaryResults();
|
||||
|
||||
DEPENDENCY_PROPERTY_OWNER(SupplementaryResults);
|
||||
DEPENDENCY_PROPERTY_WITH_DEFAULT(Windows::Foundation::Collections::IIterable<ViewModel::SupplementaryResult^>^, Results, nullptr);
|
||||
private:
|
||||
void RefreshData();
|
||||
void OnLoaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ 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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -599,6 +599,7 @@
|
|||
<local:SupplementaryResults x:Name="SupplementaryResults"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Results="{x:Bind Model.SupplementaryResults, Mode=OneWay}"
|
||||
Visibility="{x:Bind Model.SupplementaryVisibility, Mode=OneWay}"/>
|
||||
<StackPanel Visibility="{x:Bind Model.IsCurrencyCurrentCategory, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<!-- Currency Ratio Equality -->
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue