merge with master

This commit is contained in:
Rudy Huyn
2019-12-02 19:36:54 -08:00
parent 39885668ae
commit 73d6a32add
247 changed files with 27860 additions and 8218 deletions

View File

@@ -47,6 +47,11 @@ DEPENDENCY_PROPERTY_INITIALIZATION(CalculationResult, DisplayStringExpression);
#define WIDTHCUTOFF 50
#define FONTTOLERANCE 0.001
// We need a safety margin to guarantee we correctly always show/hide ScrollLeft and ScrollRight buttons when necessary.
// In rare cases, ScrollViewer::HorizontalOffset is a little low by a few (sub)pixels when users scroll to one of the extremity
// and no events are launched when they scroll again in the same direction
#define SCROLL_BUTTONS_APPROXIMATION_RANGE 4
StringReference CalculationResult::s_FocusedState(L"Focused");
StringReference CalculationResult::s_UnfocusedState(L"Unfocused");
@@ -58,58 +63,85 @@ CalculationResult::CalculationResult()
Platform::String ^ CalculationResult::GetRawDisplayValue()
{
std::wstring rawValue;
LocalizationSettings::GetInstance().RemoveGroupSeparators(DisplayValue->Data(), DisplayValue->Length(), &rawValue);
return ref new Platform::String(rawValue.c_str());
return LocalizationSettings::GetInstance().RemoveGroupSeparators(DisplayValue);
}
void CalculationResult::OnApplyTemplate()
{
assert((m_scrollLeft == nullptr && m_scrollRight == nullptr) || (m_scrollLeft != nullptr && m_scrollRight != nullptr));
if (m_textContainer)
{
m_textContainer->LayoutUpdated -= m_textContainerLayoutChangedToken;
if (m_textContainerLayoutChangedToken.Value != 0)
{
m_textContainer->LayoutUpdated -= m_textContainerLayoutChangedToken;
m_textContainerLayoutChangedToken.Value = 0;
}
if (m_textContainerSizeChangedToken.Value != 0)
{
m_textContainer->SizeChanged -= m_textContainerSizeChangedToken;
m_textContainerSizeChangedToken.Value = 0;
}
if (m_textContainerViewChangedToken.Value != 0)
{
m_textContainer->ViewChanged -= m_textContainerViewChangedToken;
m_textContainerViewChangedToken.Value = 0;
}
}
if (m_textBlock != nullptr && m_textBlockSizeChangedToken.Value != 0)
{
m_textBlock->SizeChanged -= m_textBlockSizeChangedToken;
m_textBlockSizeChangedToken.Value = 0;
}
if (m_scrollLeft != nullptr && m_scrollLeftClickToken.Value != 0)
{
m_scrollLeft->Click -= m_scrollLeftClickToken;
m_scrollLeftClickToken.Value = 0;
}
if (m_scrollRight != nullptr && m_scrollRightClickToken.Value != 0)
{
m_scrollRight->Click -= m_scrollRightClickToken;
m_scrollRightClickToken.Value = 0;
}
m_textContainer = dynamic_cast<ScrollViewer ^>(GetTemplateChild("TextContainer"));
if (m_textContainer)
{
m_textContainer->SizeChanged += ref new SizeChangedEventHandler(this, &CalculationResult::TextContainerSizeChanged);
// We want to know when the size of the container changes so
// we can rescale the textbox
m_textContainerSizeChangedToken = m_textContainer->SizeChanged += ref new SizeChangedEventHandler(this, &CalculationResult::OnTextContainerSizeChanged);
m_textContainerViewChangedToken = m_textContainer->ViewChanged +=
ref new Windows::Foundation::EventHandler<Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^>(
this, &CalculatorApp::Controls::CalculationResult::OnTextContainerOnViewChanged);
m_textContainerLayoutChangedToken = m_textContainer->LayoutUpdated +=
ref new EventHandler<Object ^>(this, &CalculationResult::OnTextContainerLayoutUpdated);
m_textContainer->ChangeView(m_textContainer->ExtentWidth - m_textContainer->ViewportWidth, nullptr, nullptr);
m_scrollLeft = dynamic_cast<HyperlinkButton ^>(GetTemplateChild("ScrollLeft"));
m_scrollRight = dynamic_cast<HyperlinkButton ^>(GetTemplateChild("ScrollRight"));
auto borderContainer = dynamic_cast<UIElement ^>(GetTemplateChild("Border"));
if (m_scrollLeft && m_scrollRight)
if (m_scrollLeft)
{
m_scrollLeft->Click += ref new RoutedEventHandler(this, &CalculationResult::OnScrollClick);
m_scrollRight->Click += ref new RoutedEventHandler(this, &CalculationResult::OnScrollClick);
borderContainer->PointerEntered += ref new PointerEventHandler(this, &CalculationResult::OnPointerEntered);
borderContainer->PointerExited += ref new PointerEventHandler(this, &CalculationResult::OnPointerExited);
m_scrollLeftClickToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &CalculationResult::OnScrollClick);
}
m_textBlock = dynamic_cast<TextBlock ^>(m_textContainer->FindName("NormalOutput"));
m_scrollRight = dynamic_cast<HyperlinkButton ^>(GetTemplateChild("ScrollRight"));
if (m_scrollRight)
{
m_scrollRightClickToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &CalculationResult::OnScrollClick);
}
m_textBlock = dynamic_cast<TextBlock ^>(GetTemplateChild("NormalOutput"));
if (m_textBlock)
{
m_textBlock->Visibility = ::Visibility::Visible;
m_textBlockSizeChangedToken = m_textBlock->SizeChanged += ref new SizeChangedEventHandler(this, &CalculationResult::OnTextBlockSizeChanged);
}
}
UpdateAllState();
UpdateVisualState();
UpdateTextState();
VisualStateManager::GoToState(this, s_UnfocusedState, false);
}
void CalculationResult::OnPointerPressed(PointerRoutedEventArgs ^ e)
{
if (m_scrollLeft && m_scrollRight && e->Pointer->PointerDeviceType == PointerDeviceType::Touch)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
}
}
void CalculationResult::OnTextContainerLayoutUpdated(Object ^ /*sender*/, Object ^ /*e*/)
{
if (m_isScalingText)
@@ -118,7 +150,7 @@ void CalculationResult::OnTextContainerLayoutUpdated(Object ^ /*sender*/, Object
}
}
void CalculationResult::TextContainerSizeChanged(Object ^ /*sender*/, SizeChangedEventArgs ^ /*e*/)
void CalculationResult::OnTextContainerSizeChanged(Object ^ /*sender*/, SizeChangedEventArgs ^ /*e*/)
{
UpdateTextState();
}
@@ -248,64 +280,46 @@ void CalculationResult::UpdateTextState()
{
m_textContainer->ChangeView(m_textContainer->ExtentWidth - m_textContainer->ViewportWidth, nullptr, nullptr);
}
if (m_scrollLeft && m_scrollRight)
{
if (m_textBlock->ActualWidth < containerSize)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
}
else
{
if (IsOperatorCommand)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Visible);
}
else
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Collapsed);
}
}
}
m_textBlock->InvalidateArrange();
}
}
void CalculationResult::ScrollLeft()
{
if (m_textContainer == nullptr)
{
return;
}
if (m_textContainer->HorizontalOffset > 0)
{
double offset = m_textContainer->HorizontalOffset - (scrollRatio * m_textContainer->ViewportWidth);
m_textContainer->ChangeView(offset, nullptr, nullptr);
m_textContainer->UpdateLayout();
UpdateScrollButtons();
}
}
void CalculationResult::ScrollRight()
{
if (m_textContainer == nullptr)
{
return;
}
if (m_textContainer->HorizontalOffset < m_textContainer->ExtentWidth - m_textContainer->ViewportWidth)
{
double offset = m_textContainer->HorizontalOffset + (scrollRatio * m_textContainer->ViewportWidth);
m_textContainer->ChangeView(offset, nullptr, nullptr);
m_textContainer->UpdateLayout();
UpdateScrollButtons();
}
}
void CalculationResult::OnKeyDown(KeyRoutedEventArgs ^ e)
{
if (m_scrollLeft != nullptr && m_scrollRight != nullptr)
switch (e->Key)
{
auto key = e->Key;
if (key == Windows::System::VirtualKey::Left)
{
this->ScrollLeft();
}
else if (key == Windows::System::VirtualKey::Right)
{
this->ScrollRight();
}
case Windows::System::VirtualKey::Left:
this->ScrollLeft();
break;
case Windows::System::VirtualKey::Right:
this->ScrollRight();
break;
}
}
@@ -322,48 +336,24 @@ void CalculationResult::OnScrollClick(Object ^ sender, RoutedEventArgs ^ /*e*/)
}
}
void CalculationResult::OnPointerEntered(Platform::Object ^ sender, PointerRoutedEventArgs ^ e)
{
if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse && m_textBlock->ActualWidth >= m_textContainer->ActualWidth)
{
UpdateScrollButtons();
}
}
void CalculationResult::ShowHideScrollButtons(::Visibility vLeft, ::Visibility vRight)
{
m_scrollLeft->Visibility = vLeft;
m_scrollRight->Visibility = vRight;
}
void CalculationResult::UpdateScrollButtons()
{
// When the width is smaller than the container, don't show any
if (m_textBlock->ActualWidth < m_textContainer->ActualWidth)
if (m_textContainer == nullptr)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
return;
}
// We have more number on both side. Show both arrows
else if (m_textContainer->HorizontalOffset > 0 && m_textContainer->HorizontalOffset < (m_textContainer->ExtentWidth - m_textContainer->ViewportWidth))
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Visible);
}
// Width is larger than the container and left most part of the number is shown. Should be able to scroll left.
else if (m_textContainer->HorizontalOffset == 0)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Visible);
}
else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left.
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Collapsed);
}
}
void CalculationResult::OnPointerExited(Platform::Object ^ sender, PointerRoutedEventArgs ^ e)
{
if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse)
if (m_scrollLeft != nullptr)
{
UpdateScrollButtons();
m_scrollLeft->Visibility = m_textContainer->HorizontalOffset > SCROLL_BUTTONS_APPROXIMATION_RANGE ? ::Visibility::Visible : ::Visibility::Collapsed;
}
if (m_scrollRight != nullptr)
{
m_scrollRight->Visibility =
m_textContainer->HorizontalOffset + m_textContainer->ViewportWidth + SCROLL_BUTTONS_APPROXIMATION_RANGE < m_textContainer->ExtentWidth
? ::Visibility::Visible
: ::Visibility::Collapsed;
}
}
@@ -382,12 +372,6 @@ void CalculationResult::ModifyFontAndMargin(TextBlock ^ textBox, double fontChan
textBox->FontSize = newFontSize;
}
void CalculationResult::UpdateAllState()
{
UpdateVisualState();
UpdateTextState();
}
void CalculationResult::OnTapped(TappedRoutedEventArgs ^ e)
{
this->Focus(::FocusState::Programmatic);
@@ -396,7 +380,16 @@ void CalculationResult::OnTapped(TappedRoutedEventArgs ^ e)
void CalculationResult::OnRightTapped(RightTappedRoutedEventArgs ^ e)
{
this->Focus(::FocusState::Programmatic);
auto requestedElement = e->OriginalSource;
if (requestedElement->Equals(dynamic_cast<Object ^>(m_textBlock)))
{
m_textBlock->Focus(::FocusState::Programmatic);
}
else
{
this->Focus(::FocusState::Programmatic);
}
}
void CalculationResult::OnGotFocus(RoutedEventArgs ^ e)
@@ -426,3 +419,13 @@ void CalculationResult::RaiseSelectedEvent()
{
Selected(this);
}
void CalculationResult::OnTextContainerOnViewChanged(Object ^ /*sender*/, ScrollViewerViewChangedEventArgs ^ e)
{
UpdateScrollButtons();
}
void CalculationResult::OnTextBlockSizeChanged(Object ^ /*sender*/, SizeChangedEventArgs ^ /*e*/)
{
UpdateScrollButtons();
}

View File

@@ -42,7 +42,6 @@ namespace CalculatorApp
virtual void OnKeyDown(Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) override;
virtual void OnApplyTemplate() override;
virtual void OnTapped(Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e) override;
virtual void OnPointerPressed(Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e) override;
virtual void OnRightTapped(Windows::UI::Xaml::Input::RightTappedRoutedEventArgs ^ e) override;
virtual void OnGotFocus(Windows::UI::Xaml::RoutedEventArgs ^ e) override;
virtual void OnLostFocus(Windows::UI::Xaml::RoutedEventArgs ^ e) override;
@@ -56,15 +55,13 @@ namespace CalculatorApp
void OnIsInErrorPropertyChanged(bool oldValue, bool newValue);
void OnMinFontSizePropertyChanged(double oldValue, double newValue);
void OnMaxFontSizePropertyChanged(double oldValue, double newValue);
void TextContainerSizeChanged(Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
void OnTextContainerSizeChanged(Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
void OnTextBlockSizeChanged(Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
void OnTextContainerLayoutUpdated(Object ^ sender, Object ^ e);
void OnTextContainerOnViewChanged(Object ^ sender, Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^ e);
void UpdateVisualState();
void UpdateAllState();
void OnScrollClick(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnPointerEntered(Platform::Object ^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
void OnPointerExited(Platform::Object ^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
void ModifyFontAndMargin(Windows::UI::Xaml::Controls::TextBlock ^ textBlock, double fontChange);
void ShowHideScrollButtons(Windows::UI::Xaml::Visibility vLeft, Windows::UI::Xaml::Visibility vRight);
void UpdateScrollButtons();
void ScrollLeft();
void ScrollRight();
@@ -82,6 +79,11 @@ namespace CalculatorApp
bool m_isScalingText;
bool m_haveCalculatedMax;
Windows::Foundation::EventRegistrationToken m_textContainerLayoutChangedToken;
Windows::Foundation::EventRegistrationToken m_textContainerViewChangedToken;
Windows::Foundation::EventRegistrationToken m_textContainerSizeChangedToken;
Windows::Foundation::EventRegistrationToken m_scrollRightClickToken;
Windows::Foundation::EventRegistrationToken m_scrollLeftClickToken;
Windows::Foundation::EventRegistrationToken m_textBlockSizeChangedToken;
};
}
}

View File

@@ -50,7 +50,7 @@ void EquationTextBox::OnApplyTemplate()
auto toolTip = ref new ToolTip();
auto resProvider = AppResourceProvider::GetInstance();
toolTip->Content = m_equationButton->IsChecked->Value ? resProvider.GetResourceString(L"showEquationButtonToolTip") : resProvider.GetResourceString(L"hideEquationButtonToolTip");
toolTip->Content = m_equationButton->IsChecked->Value ? resProvider->GetResourceString(L"showEquationButtonToolTip") : resProvider->GetResourceString(L"hideEquationButtonToolTip");
ToolTipService::SetToolTip(m_equationButton, toolTip);
}
@@ -190,7 +190,7 @@ void EquationTextBox::OnEquationButtonClicked(Object ^ sender, RoutedEventArgs ^
auto toolTip = ref new ToolTip();
auto resProvider = AppResourceProvider::GetInstance();
toolTip->Content = m_equationButton->IsChecked->Value ? resProvider.GetResourceString(L"showEquationButtonToolTip") : resProvider.GetResourceString(L"hideEquationButtonToolTip");
toolTip->Content = m_equationButton->IsChecked->Value ? resProvider->GetResourceString(L"showEquationButtonToolTip") : resProvider->GetResourceString(L"hideEquationButtonToolTip");
ToolTipService::SetToolTip(m_equationButton, toolTip);
}

View File

@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "OperatorPanelButton.h"
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::ViewManagement;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Media;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, Text);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, Glyph);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, GlyphFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, ChevronFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(OperatorPanelButton, FlyoutMenu);
void OperatorPanelButton::OnApplyTemplate()
{
if (FlyoutMenu != nullptr)
{
FlyoutMenu->Closed += ref new EventHandler<Object ^>(this, &OperatorPanelButton::FlyoutClosed);
}
}
void OperatorPanelButton::OnToggle()
{
ToggleButton::OnToggle();
if (IsChecked)
{
FlyoutMenu->ShowAt(this);
}
}
void OperatorPanelButton::FlyoutClosed(Object ^ sender, Object ^ args)
{
IsChecked = false;
}

View File

@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class OperatorPanelButton sealed : Windows::UI::Xaml::Controls::Primitives::ToggleButton
{
public:
OperatorPanelButton()
{
}
DEPENDENCY_PROPERTY_OWNER(OperatorPanelButton);
DEPENDENCY_PROPERTY(Platform::String^, Text);
DEPENDENCY_PROPERTY(Platform::String^, Glyph);
DEPENDENCY_PROPERTY(double, GlyphFontSize);
DEPENDENCY_PROPERTY(double, ChevronFontSize);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::Flyout^, FlyoutMenu);
protected:
virtual void OnApplyTemplate() override;
virtual void OnToggle() override;
private:
void FlyoutClosed(Platform::Object^ sender, Platform::Object^ args);
};
}
}

View File

@@ -0,0 +1,147 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "OperatorPanelListView.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Controls;
using namespace Platform;
using namespace std;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Controls;
OperatorPanelListView::OperatorPanelListView()
{
}
void OperatorPanelListView::OnApplyTemplate()
{
m_scrollViewer = dynamic_cast<ScrollViewer^>(GetTemplateChild("ScrollViewer"));
m_scrollLeft = dynamic_cast<Button^>(GetTemplateChild("ScrollLeft"));
m_scrollRight = dynamic_cast<Button^>(GetTemplateChild("ScrollRight"));
m_content = dynamic_cast<ItemsPresenter^>(GetTemplateChild("Content"));
if (m_scrollLeft != nullptr)
{
m_scrollLeft->Click += ref new RoutedEventHandler(this, &OperatorPanelListView::OnScrollClick);
m_scrollLeft->PointerExited += ref new PointerEventHandler(this, &OperatorPanelListView::OnButtonPointerExited);
}
if (m_scrollRight != nullptr)
{
m_scrollRight->Click += ref new RoutedEventHandler(this, &OperatorPanelListView::OnScrollClick);
m_scrollRight->PointerExited += ref new PointerEventHandler(this, &OperatorPanelListView::OnButtonPointerExited);
}
if (m_scrollViewer != nullptr)
{
m_scrollViewer->ViewChanged += ref new EventHandler<ScrollViewerViewChangedEventArgs^>(this, &OperatorPanelListView::ScrollViewChanged);
}
this->PointerEntered += ref new PointerEventHandler(this, &OperatorPanelListView::OnPointerEntered);
this->PointerExited += ref new PointerEventHandler(this, &OperatorPanelListView::OnPointerExited);
ListView::OnApplyTemplate();
}
void OperatorPanelListView::ScrollViewChanged(_In_ Object^, _In_ ScrollViewerViewChangedEventArgs^ e)
{
if (m_isPointerEntered && !e->IsIntermediate)
{
UpdateScrollButtons();
}
}
void OperatorPanelListView::OnScrollClick(_In_ Object^ sender, _In_ RoutedEventArgs^)
{
auto clicked = dynamic_cast<Button^>(sender);
if (clicked == m_scrollLeft)
{
ScrollLeft();
}
else
{
ScrollRight();
}
}
void OperatorPanelListView::OnButtonPointerExited(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
auto button = dynamic_cast<Button^>(sender);
// Do not bubble up the pointer exit event to the control if the button being exited was not visible
if (button->Visibility == ::Visibility::Collapsed)
{
e->Handled = true;
}
}
void OperatorPanelListView::OnPointerEntered(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
if (e->Pointer->PointerDeviceType == PointerDeviceType::Mouse)
{
UpdateScrollButtons();
m_isPointerEntered = true;
}
}
void OperatorPanelListView::OnPointerExited(_In_ Object^ sender, _In_ PointerRoutedEventArgs^ e)
{
m_scrollLeft->Visibility = ::Visibility::Collapsed;
m_scrollRight->Visibility = ::Visibility::Collapsed;
m_isPointerEntered = false;
}
void OperatorPanelListView::ScrollLeft()
{
double offset = m_scrollViewer->HorizontalOffset - (scrollRatio * m_scrollViewer->ViewportWidth);
m_scrollViewer->ChangeView(offset, nullptr, nullptr);
}
void OperatorPanelListView::ScrollRight()
{
double offset = m_scrollViewer->HorizontalOffset + (scrollRatio * m_scrollViewer->ViewportWidth);
m_scrollViewer->ChangeView(offset, nullptr, nullptr);
}
void OperatorPanelListView::UpdateScrollButtons()
{
if (m_content == nullptr || m_scrollViewer == nullptr)
{
return;
}
// When the width is smaller than the container, don't show any
if (m_content->ActualWidth <= m_scrollViewer->ActualWidth)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
}
// We have more number on both side. Show both arrows
else if ((m_scrollViewer->HorizontalOffset > 0) && (m_scrollViewer->HorizontalOffset < (m_scrollViewer->ExtentWidth - m_scrollViewer->ViewportWidth)))
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Visible);
}
// Width is larger than the container and left most part of the number is shown. Should be able to scroll left.
else if (m_scrollViewer->HorizontalOffset == 0)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Visible);
}
else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left.
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Collapsed);
}
}
void OperatorPanelListView::ShowHideScrollButtons(::Visibility vLeft, ::Visibility vRight)
{
if (m_scrollLeft != nullptr && m_scrollRight != nullptr)
{
m_scrollLeft->Visibility = vLeft;
m_scrollRight->Visibility = vRight;
}
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcViewModel/Common/Utils.h"
namespace CalculatorApp
{
namespace Controls
{
public
ref class OperatorPanelListView sealed : public Windows::UI::Xaml::Controls::ListView
{
public:
OperatorPanelListView();
protected:
virtual void OnApplyTemplate() override;
private:
void OnScrollClick(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs^ e);
void OnPointerEntered(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
void OnPointerExited(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
void OnButtonPointerExited(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
void ScrollViewChanged(_In_ Platform::Object^ sender, _In_ Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs^ args);
void ShowHideScrollButtons(Windows::UI::Xaml::Visibility vLeft, Windows::UI::Xaml::Visibility vRight);
void UpdateScrollButtons();
void ScrollLeft();
void ScrollRight();
double scrollRatio = 0.7;
bool m_isPointerEntered;
Windows::UI::Xaml::Controls::ItemsPresenter^ m_content;
Windows::UI::Xaml::Controls::ScrollViewer^ m_scrollViewer;
Windows::UI::Xaml::Controls::Button^ m_scrollLeft;
Windows::UI::Xaml::Controls::Button^ m_scrollRight;
};
}
}

View File

@@ -27,9 +27,12 @@ using namespace Windows::UI::Xaml::Navigation;
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, IsActive);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TextStyle);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, TokensUpdated);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ColumnWidth);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ColumnHeight);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsWidth);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsFontSize);
DEPENDENCY_PROPERTY_INITIALIZATION(OverflowTextBlock, ScrollButtonsPlacement);
static constexpr unsigned int SCROLL_BUTTONS_APPROXIMATION_RANGE = 4;
static constexpr double SCROLL_RATIO = 0.7;
void OverflowTextBlock::OnApplyTemplate()
{
@@ -44,35 +47,32 @@ void OverflowTextBlock::OnApplyTemplate()
ref new EventHandler<ScrollViewerViewChangedEventArgs ^>(this, &OverflowTextBlock::OnViewChanged);
}
uiElement = GetTemplateChild("ExpressionContent");
if (uiElement != nullptr)
{
m_expressionContent = safe_cast<FrameworkElement ^>(uiElement);
}
uiElement = GetTemplateChild("ScrollLeft");
if (uiElement != nullptr)
{
m_scrollLeft = safe_cast<Button ^>(uiElement);
m_scrollLeftClickEventToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick);
m_scrollLeftClickEventToken = m_scrollLeft->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollLeftClick);
}
uiElement = GetTemplateChild("ScrollRight");
if (uiElement != nullptr)
{
m_scrollRight = safe_cast<Button ^>(uiElement);
m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollClick);
m_scrollRightClickEventToken = m_scrollRight->Click += ref new RoutedEventHandler(this, &OverflowTextBlock::OnScrollRightClick);
}
m_scrollingLeft = false;
m_scrollingRight = false;
uiElement = GetTemplateChild("TokenList");
if (uiElement != nullptr)
{
m_itemsControl = safe_cast<ItemsControl ^>(uiElement);
}
uiElement = GetTemplateChild("EditableToken");
if (uiElement != nullptr)
{
m_editableToken = safe_cast<TextBlock ^>(uiElement);
}
UpdateAllState();
}
@@ -118,8 +118,7 @@ void OverflowTextBlock::ScrollLeft()
{
if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset > 0)
{
m_scrollingLeft = true;
double offset = m_expressionContainer->HorizontalOffset - (scrollRatio * m_expressionContainer->ViewportWidth);
double offset = m_expressionContainer->HorizontalOffset - (SCROLL_RATIO * m_expressionContainer->ViewportWidth);
m_expressionContainer->ChangeView(offset, nullptr, nullptr);
m_expressionContainer->UpdateLayout();
UpdateScrollButtons();
@@ -128,93 +127,81 @@ void OverflowTextBlock::ScrollLeft()
void OverflowTextBlock::ScrollRight()
{
if (m_expressionContainer != nullptr && m_expressionContainer->HorizontalOffset < m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth)
auto realOffset = m_expressionContainer->HorizontalOffset + m_expressionContainer->Padding.Left + m_expressionContent->Margin.Left;
if (m_expressionContainer != nullptr && realOffset + m_expressionContainer->ActualWidth < m_expressionContent->ActualWidth)
{
m_scrollingRight = true;
double offset = m_expressionContainer->HorizontalOffset + (scrollRatio * m_expressionContainer->ViewportWidth);
double offset = m_expressionContainer->HorizontalOffset + (SCROLL_RATIO * m_expressionContainer->ViewportWidth);
m_expressionContainer->ChangeView(offset, nullptr, nullptr);
m_expressionContainer->UpdateLayout();
UpdateScrollButtons();
}
}
void OverflowTextBlock::OnScrollClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
void OverflowTextBlock::OnScrollLeftClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
{
auto clicked = safe_cast<Button ^>(sender);
if (clicked == m_scrollLeft)
{
ScrollLeft();
}
else
{
ScrollRight();
}
ScrollLeft();
}
void OverflowTextBlock::OnScrollRightClick(_In_ Object ^ sender, _In_ RoutedEventArgs ^)
{
ScrollRight();
}
void OverflowTextBlock::UpdateScrollButtons()
{
if (m_expressionContainer == nullptr)
if (m_expressionContainer == nullptr || m_scrollLeft == nullptr || m_scrollRight == nullptr)
{
return;
}
double editableTokenWidth = 0;
if (m_editableToken != nullptr && m_editableToken->Visibility == ::Visibility::Visible)
{
editableTokenWidth = m_editableToken->ActualWidth;
}
auto realOffset = m_expressionContainer->HorizontalOffset + m_expressionContainer->Padding.Left + m_expressionContent->Margin.Left;
auto scrollLeftVisibility = realOffset > SCROLL_BUTTONS_APPROXIMATION_RANGE ? ::Visibility::Visible : ::Visibility::Collapsed;
auto scrollRightVisibility = realOffset + m_expressionContainer->ActualWidth + SCROLL_BUTTONS_APPROXIMATION_RANGE < m_expressionContent->ActualWidth
? ::Visibility::Visible
: ::Visibility::Collapsed;
double itemsControlWidth = 0;
if (m_itemsControl != nullptr && m_itemsControl->Visibility == ::Visibility::Visible)
bool shouldTryFocusScrollRight = false;
if (m_scrollLeft->Visibility != scrollLeftVisibility)
{
itemsControlWidth = m_itemsControl->ActualWidth;
}
// When the width is smaller than the container, don't show any
if (itemsControlWidth + editableTokenWidth <= m_expressionContainer->ActualWidth)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Collapsed);
}
// We have more number on both side. Show both arrows
else if (
(m_expressionContainer->HorizontalOffset > 0)
&& (m_expressionContainer->HorizontalOffset < (m_expressionContainer->ExtentWidth - m_expressionContainer->ViewportWidth)))
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Visible);
}
// Width is larger than the container and left most part of the number is shown. Should be able to scroll right.
else if (m_expressionContainer->HorizontalOffset == 0)
{
ShowHideScrollButtons(::Visibility::Collapsed, ::Visibility::Visible);
if (m_scrollingLeft)
if (scrollLeftVisibility == ::Visibility::Collapsed)
{
m_scrollingLeft = false;
if (m_scrollRight != nullptr)
{
m_scrollRight->Focus(::FocusState::Programmatic);
}
shouldTryFocusScrollRight = m_scrollLeft->Equals(FocusManager::GetFocusedElement());
}
}
else // Width is larger than the container and right most part of the number is shown. Should be able to scroll left.
{
ShowHideScrollButtons(::Visibility::Visible, ::Visibility::Collapsed);
if (m_scrollingRight)
{
m_scrollingRight = false;
if (m_scrollLeft != nullptr)
{
m_scrollLeft->Focus(::FocusState::Programmatic);
}
}
}
}
void OverflowTextBlock::ShowHideScrollButtons(::Visibility vLeft, ::Visibility vRight)
{
if (m_scrollLeft != nullptr && m_scrollRight != nullptr)
m_scrollLeft->Visibility = scrollLeftVisibility;
}
if (m_scrollRight->Visibility != scrollRightVisibility)
{
m_scrollLeft->Visibility = vLeft;
m_scrollRight->Visibility = vRight;
if (scrollRightVisibility == ::Visibility::Collapsed && m_scrollLeft->Visibility == ::Visibility::Visible
&& m_scrollRight->Equals(FocusManager::GetFocusedElement()))
{
m_scrollLeft->Focus(::FocusState::Programmatic);
}
m_scrollRight->Visibility = scrollRightVisibility;
}
if (shouldTryFocusScrollRight && scrollRightVisibility == ::Visibility::Visible)
{
m_scrollRight->Focus(::FocusState::Programmatic);
}
if (ScrollButtonsPlacement == OverflowButtonPlacement::Above && m_expressionContent != nullptr)
{
double left = m_scrollLeft != nullptr && m_scrollLeft->Visibility == ::Visibility::Visible ? ScrollButtonsWidth : 0;
double right = m_scrollRight != nullptr && m_scrollRight->Visibility == ::Visibility::Visible ? ScrollButtonsWidth : 0;
if (m_expressionContainer->Padding.Left != left || m_expressionContainer->Padding.Right != right)
{
m_expressionContainer->ViewChanged -= m_containerViewChangedToken;
m_expressionContainer->Padding = Thickness(left, 0, right, 0);
m_expressionContent->Margin = Thickness(-left, 0, -right, 0);
m_expressionContainer->UpdateLayout();
m_expressionContainer->Measure(m_expressionContainer->RenderSize);
m_containerViewChangedToken = m_expressionContainer->ViewChanged +=
ref new EventHandler<ScrollViewerViewChangedEventArgs ^>(this, &OverflowTextBlock::OnViewChanged);
}
}
}
@@ -241,3 +228,13 @@ void OverflowTextBlock::OnViewChanged(_In_opt_ Object ^ /*sender*/, _In_opt_ Scr
{
UpdateScrollButtons();
}
void OverflowTextBlock::OnScrollButtonsPlacementPropertyChanged(OverflowButtonPlacement /*oldValue*/, OverflowButtonPlacement newValue)
{
if (newValue == OverflowButtonPlacement::InLine)
{
m_expressionContainer->Padding = Thickness(0);
m_expressionContent->Margin = Thickness(0);
}
UpdateScrollButtons();
}

View File

@@ -9,23 +9,38 @@ namespace CalculatorApp
{
namespace Controls
{
public
enum class OverflowButtonPlacement : int
{
InLine,
Above
};
public
ref class OverflowTextBlock sealed : public Windows::UI::Xaml::Controls::Control
{
public:
OverflowTextBlock()
: m_isAccessibilityViewControl(false)
, m_ignoreViewChanged(false)
, m_expressionContent(nullptr)
, m_itemsControl(nullptr)
, m_expressionContainer(nullptr)
, m_scrollLeft(nullptr)
, m_scrollRight(nullptr)
{
}
DEPENDENCY_PROPERTY_OWNER(OverflowTextBlock);
DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, TokensUpdated);
DEPENDENCY_PROPERTY_WITH_CALLBACK(OverflowButtonPlacement, ScrollButtonsPlacement);
DEPENDENCY_PROPERTY(bool, IsActive);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Style ^, TextStyle);
DEPENDENCY_PROPERTY(double, ColumnWidth);
DEPENDENCY_PROPERTY(double, ColumnHeight);
DEPENDENCY_PROPERTY(double, ScrollButtonFontSize);
DEPENDENCY_PROPERTY(double, ScrollButtonsWidth);
DEPENDENCY_PROPERTY(double, ScrollButtonsFontSize);
void OnTokensUpdatedPropertyChanged(bool oldValue, bool newValue);
void OnScrollButtonsPlacementPropertyChanged(OverflowButtonPlacement oldValue, OverflowButtonPlacement newValue);
void UpdateScrollButtons();
void UnregisterEventHandlers();
@@ -34,23 +49,18 @@ namespace CalculatorApp
virtual Windows::UI::Xaml::Automation::Peers::AutomationPeer ^ OnCreateAutomationPeer() override;
private:
void OnScrollClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnPointerEntered(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
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 OnScrollLeftClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnScrollRightClick(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnViewChanged(_In_opt_ Platform::Object ^ sender, _In_opt_ Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs ^ args);
void UpdateVisualState();
void UpdateExpressionState();
void UpdateAllState();
void ScrollLeft();
void ScrollRight();
double scrollRatio = 0.7;
bool m_scrollingLeft;
bool m_scrollingRight;
bool m_isAccessibilityViewControl;
Windows::UI::Xaml::Controls::TextBlock ^ m_editableToken;
bool m_ignoreViewChanged;
Windows::UI::Xaml::FrameworkElement ^ m_expressionContent;
Windows::UI::Xaml::Controls::ItemsControl ^ m_itemsControl;
Windows::UI::Xaml::Controls::ScrollViewer ^ m_expressionContainer;
Windows::UI::Xaml::Controls::Button ^ m_scrollLeft;

View File

@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
@@ -18,8 +18,6 @@ using namespace Windows::UI::Xaml::Data;
String ^ RadixButton::GetRawDisplayValue()
{
wstring rawValue;
String ^ radixContent = Content->ToString();
LocalizationSettings::GetInstance().RemoveGroupSeparators(radixContent->Data(), radixContent->Length(), &rawValue);
return ref new String(rawValue.c_str());
return LocalizationSettings::GetInstance().RemoveGroupSeparators(radixContent);
}