diff --git a/src/CalcViewModel/StandardCalculatorViewModel.cpp b/src/CalcViewModel/StandardCalculatorViewModel.cpp index 944b8d1a..8b55299e 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.cpp +++ b/src/CalcViewModel/StandardCalculatorViewModel.cpp @@ -66,6 +66,7 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() : m_BinaryDisplayValue(L"0"), m_OctalDisplayValue(L"0"), m_standardCalculatorManager(&m_calculatorDisplay, &m_resourceProvider), + m_ExpressionTokens(ref new Vector()), m_MemorizedNumbers(ref new Vector()), m_IsMemoryEmpty(true), m_IsFToEChecked(false), @@ -314,59 +315,67 @@ void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr(); - } - else - { - m_ExpressionTokens->Clear(); - } - unsigned int nTokens = 0; tokens->GetSize(&nTokens); + + if (nTokens == 0) + { + m_ExpressionTokens->Clear(); + return; + } + pair currentToken; const auto& localizer = LocalizationSettings::GetInstance(); + const wstring separator = L" "; for (unsigned int i = 0; i < nTokens; ++i) { if (SUCCEEDED(tokens->GetAt(i, ¤tToken))) { Common::TokenType type; - const wstring separator = L" "; bool isEditable = (currentToken.second == -1) ? false : true; localizer.LocalizeDisplayValue(&(currentToken.first)); if (!isEditable) { - if (currentToken.first == separator) - { - type = TokenType::Separator; - } - else - { - type = TokenType::Operator; - } + type = currentToken.first == separator ? TokenType::Separator : TokenType::Operator; } - else { shared_ptr command; IFTPlatformException(m_commands->GetAt(static_cast(currentToken.second), &command)); + type = command->GetCommandType() == CommandType::OperandCommand ? TokenType::Operand : TokenType::Operator; + } - if (command->GetCommandType() == CommandType::OperandCommand) + auto currentTokenString = ref new String(currentToken.first.c_str()); + if (i < m_ExpressionTokens->Size) + { + auto existingItem = m_ExpressionTokens->GetAt(i); + if (type == existingItem->Type && existingItem->Token->Equals(currentTokenString)) { - type = TokenType::Operand; + existingItem->TokenPosition = i; + existingItem->IsTokenEditable = isEditable; + existingItem->CommandIndex = 0; } else { - type = TokenType::Operator; + auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); + m_ExpressionTokens->InsertAt(i, expressionToken); } + + } + else + { + auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); + m_ExpressionTokens->Append(expressionToken); } - DisplayExpressionToken^ expressionToken = ref new DisplayExpressionToken(ref new String(currentToken.first.c_str()), i, isEditable, type); - m_ExpressionTokens->Append(expressionToken); } } + + while (m_ExpressionTokens->Size != nTokens) + { + m_ExpressionTokens->RemoveAtEnd(); + } } String^ StandardCalculatorViewModel::GetCalculatorExpressionAutomationName() @@ -524,7 +533,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) { if (commandIndex == 0) { - delete [] temp; + delete[] temp; return; } @@ -545,7 +554,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) length = m_selectedExpressionLastData->Length() + 1; if (length > 50) { - delete [] temp; + delete[] temp; return; } for (; i < length; ++i) diff --git a/src/CalcViewModel/StandardCalculatorViewModel.h b/src/CalcViewModel/StandardCalculatorViewModel.h index 42d025c4..f8140a75 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.h +++ b/src/CalcViewModel/StandardCalculatorViewModel.h @@ -48,7 +48,7 @@ namespace CalculatorApp OBSERVABLE_NAMED_PROPERTY_RW(bool, IsInError); OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand); OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayStringExpression); - OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector^, ExpressionTokens); + OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector^, ExpressionTokens); OBSERVABLE_PROPERTY_RW(Platform::String^, DecimalDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, OctalDisplayValue); diff --git a/src/Calculator/Calculator.vcxproj b/src/Calculator/Calculator.vcxproj index 64e4ad06..d4023eda 100644 --- a/src/Calculator/Calculator.vcxproj +++ b/src/Calculator/Calculator.vcxproj @@ -243,7 +243,6 @@ - @@ -375,7 +374,6 @@ - diff --git a/src/Calculator/Calculator.vcxproj.filters b/src/Calculator/Calculator.vcxproj.filters index a888b192..4b8b9ed8 100644 --- a/src/Calculator/Calculator.vcxproj.filters +++ b/src/Calculator/Calculator.vcxproj.filters @@ -243,9 +243,6 @@ Converters - - Converters - Converters @@ -333,9 +330,6 @@ Converters - - Converters - Converters diff --git a/src/Calculator/Controls/OverflowTextBlock.cpp b/src/Calculator/Controls/OverflowTextBlock.cpp index 85baebc4..a31a13af 100644 --- a/src/Calculator/Controls/OverflowTextBlock.cpp +++ b/src/Calculator/Controls/OverflowTextBlock.cpp @@ -30,25 +30,38 @@ DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TokensUpdated); void OverflowTextBlock::OnApplyTemplate() { - assert(((m_scrollLeft == nullptr) && (m_scrollRight == nullptr)) || ((m_scrollLeft != nullptr) && (m_scrollRight != nullptr))); + UnregisterEventHandlers(); - m_expressionContainer = safe_cast(GetTemplateChild("expressionContainer")); - m_expressionContainer->ChangeView(m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth, nullptr, nullptr); + auto uiElement = GetTemplateChild("expressionContainer"); + if (uiElement != nullptr) + { + m_expressionContainer = safe_cast(uiElement); + m_expressionContainer->ChangeView(m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth, nullptr, nullptr); + m_containerViewChangedToken = m_expressionContainer->ViewChanged += ref new EventHandler(this, &OverflowTextBlock::OnViewChanged); + } - m_scrollLeft = safe_cast(GetTemplateChild("scrollLeft")); - m_scrollRight = safe_cast(GetTemplateChild("scrollRight")); + uiElement = GetTemplateChild("scrollLeft"); + if (uiElement != nullptr) + { + m_scrollLeft = safe_cast(uiElement); + m_scrollLeftClickEventToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick); + } - m_scrollLeftClickEventToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick); - m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick); + uiElement = GetTemplateChild("scrollRight"); + if (uiElement != nullptr) + { + m_scrollRight = safe_cast(GetTemplateChild("scrollRight")); + m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick); + } m_scrollingLeft = false; m_scrollingRight = false; - auto borderContainer = safe_cast(GetTemplateChild("expressionborder")); - m_pointerEnteredEventToken = borderContainer->PointerEntered += ref new PointerEventHandler(this, &OverflowTextBlock::OnPointerEntered); - m_pointerExitedEventToken = borderContainer->PointerExited += ref new PointerEventHandler(this, &OverflowTextBlock::OnPointerExited); - - m_listView = safe_cast(GetTemplateChild("TokenList")); + uiElement = GetTemplateChild("TokenList"); + if (uiElement != nullptr) + { + m_itemsControl = safe_cast(uiElement); + } UpdateAllState(); } @@ -60,18 +73,19 @@ AutomationPeer^ OverflowTextBlock::OnCreateAutomationPeer() void OverflowTextBlock::OnTokensUpdatedPropertyChanged(bool /*oldValue*/, bool newValue) { - if ((m_listView != nullptr) && (newValue)) + if (m_expressionContainer != nullptr && newValue) { - unsigned int tokenCount = m_listView->Items->Size; - if (tokenCount > 0) - { - m_listView->UpdateLayout(); - m_listView->ScrollIntoView(m_listView->Items->GetAt(tokenCount - 1)); - m_expressionContainer->ChangeView(m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth, nullptr, nullptr); - } + m_expressionContainer->UpdateLayout(); + m_expressionContainer->ChangeView(m_expressionContainer->ScrollableWidth, nullptr, nullptr, true); } - AutomationProperties::SetAccessibilityView(this, - m_listView != nullptr && m_listView->Items->Size > 0 ? AccessibilityView::Control : AccessibilityView::Raw); + auto newIsAccessibilityViewControl = m_itemsControl != nullptr && m_itemsControl->Items->Size > 0; + if (m_isAccessibilityViewControl != newIsAccessibilityViewControl) + { + m_isAccessibilityViewControl = newIsAccessibilityViewControl; + AutomationProperties::SetAccessibilityView(this, + newIsAccessibilityViewControl ? AccessibilityView::Control : AccessibilityView::Raw); + } + UpdateScrollButtons(); } void OverflowTextBlock::UpdateAllState() @@ -93,7 +107,7 @@ void OverflowTextBlock::UpdateVisualState() void OverflowTextBlock::ScrollLeft() { - if (m_expressionContainer->HorizontalOffset > 0) + if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset > 0) { m_scrollingLeft = true; double offset = m_expressionContainer->HorizontalOffset - (scrollRatio * m_expressionContainer->ViewportWidth); @@ -105,7 +119,7 @@ void OverflowTextBlock::ScrollLeft() void OverflowTextBlock::ScrollRight() { - if (m_expressionContainer->HorizontalOffset < m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth) + if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset < m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth) { m_scrollingRight = true; double offset = m_expressionContainer->HorizontalOffset + (scrollRatio * m_expressionContainer->ViewportWidth); @@ -128,26 +142,15 @@ void OverflowTextBlock::OnScrollClick(_In_ Object^ sender, _In_ RoutedEventArgs^ } } -void OverflowTextBlock::OnPointerEntered(_In_ Object^, _In_ PointerRoutedEventArgs^ e) -{ - if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse) - { - UpdateScrollButtons(); - } -} - -void OverflowTextBlock::OnPointerExited(_In_ Object^, _In_ PointerRoutedEventArgs^ e) -{ - if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse) - { - UpdateScrollButtons(); - } -} - void OverflowTextBlock::UpdateScrollButtons() { + if (m_itemsControl == nullptr || m_expressionContainer == nullptr) + { + return; + } + // When the width is smaller than the container, don't show any - if (m_listView->ActualWidth <= m_expressionContainer->ActualWidth) + if (m_itemsControl->ActualWidth <= m_expressionContainer->ActualWidth) { ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed); } @@ -163,7 +166,10 @@ void OverflowTextBlock::UpdateScrollButtons() if (m_scrollingLeft) { m_scrollingLeft = false; - m_scrollRight->Focus(::FocusState::Programmatic); + if (m_scrollRight != nullptr) + { + m_scrollRight->Focus(::FocusState::Programmatic); + } } } else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left. @@ -172,7 +178,10 @@ void OverflowTextBlock::UpdateScrollButtons() if (m_scrollingRight) { m_scrollingRight = false; - m_scrollLeft->Focus(::FocusState::Programmatic); + if (m_scrollLeft != nullptr) + { + m_scrollLeft->Focus(::FocusState::Programmatic); + } } } } @@ -199,12 +208,13 @@ void OverflowTextBlock::UnregisterEventHandlers() m_scrollRight->Click -= m_scrollRightClickEventToken; } - auto borderContainer = safe_cast(GetTemplateChild("expressionborder")); - - // Adding an extra check, in case the returned template is null - if (borderContainer != nullptr) + if (m_expressionContainer != nullptr) { - borderContainer->PointerEntered -= m_pointerEnteredEventToken; - borderContainer->PointerExited -= m_pointerExitedEventToken; + m_expressionContainer->ViewChanged -= m_containerViewChangedToken; } } + +void OverflowTextBlock::OnViewChanged(_In_opt_ Object^ /*sender*/, _In_opt_ ScrollViewerViewChangedEventArgs^ /*args*/) +{ + UpdateScrollButtons(); +} diff --git a/src/Calculator/Controls/OverflowTextBlock.h b/src/Calculator/Controls/OverflowTextBlock.h index 13b2e828..d4102091 100644 --- a/src/Calculator/Controls/OverflowTextBlock.h +++ b/src/Calculator/Controls/OverflowTextBlock.h @@ -34,6 +34,7 @@ namespace CalculatorApp void OnPointerExited(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e); void ShowHideScrollButtons(Windows::UI::Xaml::Visibility vLeft, Windows::UI::Xaml::Visibility vRight); void OnTokensUpdatedPropertyChanged(bool oldValue, bool newValue); + void OnViewChanged(_In_opt_ Platform::Object ^sender, _In_opt_ Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^args); void UpdateVisualState(); void UpdateExpressionState(); @@ -44,15 +45,15 @@ namespace CalculatorApp double scrollRatio = 0.7; bool m_scrollingLeft; bool m_scrollingRight; - Windows::UI::Xaml::Controls::ListView^ m_listView; + bool m_isAccessibilityViewControl; + Windows::UI::Xaml::Controls::ItemsControl^ m_itemsControl; Windows::UI::Xaml::Controls::ScrollViewer^ m_expressionContainer; Windows::UI::Xaml::Controls::Button^ m_scrollLeft; Windows::UI::Xaml::Controls::Button^ m_scrollRight; Windows::Foundation::EventRegistrationToken m_scrollLeftClickEventToken; Windows::Foundation::EventRegistrationToken m_scrollRightClickEventToken; - Windows::Foundation::EventRegistrationToken m_pointerEnteredEventToken; - Windows::Foundation::EventRegistrationToken m_pointerExitedEventToken; + Windows::Foundation::EventRegistrationToken m_containerViewChangedToken; }; } } diff --git a/src/Calculator/Converters/ExpressionItemContainerStyle.cpp b/src/Calculator/Converters/ExpressionItemContainerStyle.cpp deleted file mode 100644 index d99332c1..00000000 --- a/src/Calculator/Converters/ExpressionItemContainerStyle.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "pch.h" -#include "ExpressionItemContainerStyle.h" -#include "CalcViewModel/Common/DisplayExpressionToken.h" - -using namespace CalculatorApp::Common; - -namespace CalculatorApp -{ - namespace Converters - { - Windows::UI::Xaml::Style^ ExpressionItemContainerStyle::SelectStyleCore(Platform::Object^ item, Windows::UI::Xaml::DependencyObject^ container) - { - DisplayExpressionToken^ token = dynamic_cast(item); - if (token != nullptr) - { - Common::TokenType type = token->Type; - - switch (type) - { - case TokenType::Operator: - if (token->IsTokenEditable) - { - return m_editableOperatorStyle; - } - else - { - return m_nonEditableOperatorStyle; - } - case TokenType::Operand: - return m_operandStyle; - case TokenType::Separator: - return m_separatorStyle; - default: - throw ref new Platform::Exception(E_FAIL, L"Invalid token type"); - } - } - - return m_separatorStyle; - } - } -} diff --git a/src/Calculator/Converters/ExpressionItemContainerStyle.h b/src/Calculator/Converters/ExpressionItemContainerStyle.h deleted file mode 100644 index e42ecc6a..00000000 --- a/src/Calculator/Converters/ExpressionItemContainerStyle.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -namespace CalculatorApp -{ - namespace Converters - { - [Windows::UI::Xaml::Data::Bindable] - public ref class ExpressionItemContainerStyle sealed : public Windows::UI::Xaml::Controls::StyleSelector - { - public: - virtual Windows::UI::Xaml::Style^ SelectStyleCore(Platform::Object^ item, Windows::UI::Xaml::DependencyObject^ container) override; - - property Windows::UI::Xaml::Style^ EditableOperatorStyle - { - Windows::UI::Xaml::Style^ get() - { - return m_editableOperatorStyle; - } - void set(Windows::UI::Xaml::Style^ val) - { - m_editableOperatorStyle = val; - } - } - - property Windows::UI::Xaml::Style^ OperandStyle - { - Windows::UI::Xaml::Style^ get() - { - return m_operandStyle; - } - void set(Windows::UI::Xaml::Style^ val) - { - m_operandStyle = val; - } - } - - property Windows::UI::Xaml::Style^ SeparatorStyle - { - Windows::UI::Xaml::Style^ get() - { - return m_separatorStyle; - } - void set(Windows::UI::Xaml::Style^ val) - { - m_separatorStyle = val; - } - } - - property Windows::UI::Xaml::Style^ NonEditableOperatorStyle - { - Windows::UI::Xaml::Style^ get() - { - return m_nonEditableOperatorStyle; - } - void set(Windows::UI::Xaml::Style^ val) - { - m_nonEditableOperatorStyle = val; - } - } - - private: - Windows::UI::Xaml::Style^ m_editableOperatorStyle; - Windows::UI::Xaml::Style^ m_nonEditableOperatorStyle; - Windows::UI::Xaml::Style^ m_operandStyle; - Windows::UI::Xaml::Style^ m_separatorStyle; - }; - } -} diff --git a/src/Calculator/Views/Calculator.xaml b/src/Calculator/Views/Calculator.xaml index c58bcdfb..c5566ead 100644 --- a/src/Calculator/Views/Calculator.xaml +++ b/src/Calculator/Views/Calculator.xaml @@ -8,7 +8,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:CalculatorApp" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:model="using:CalculatorApp.ViewModel" Loaded="OnLoaded" mc:Ignorable="d"> @@ -19,20 +18,20 @@ + Text="{x:Bind Token, Mode=OneWay}"/> + Text="{x:Bind Token, Mode=OneWay}"/> + Text="{x:Bind Token, Mode=OneWay}"/> @@ -42,119 +41,59 @@ - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - + ItemsSource="{Binding ExpressionTokens}"> + + + + + + + + + + - - - - - - - -