* Save and restore the value of EquationInputArea when users scroll * clean up * replace ->Focus(..) by FocusManager::TryFocus(...)
354 lines
12 KiB
C++
354 lines
12 KiB
C++
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
#include "pch.h"
|
|
#include "EquationInputArea.xaml.h"
|
|
#include "Utils/VisualTree.h"
|
|
|
|
using namespace CalculatorApp;
|
|
using namespace CalculatorApp::Common;
|
|
using namespace GraphControl;
|
|
using namespace CalculatorApp::ViewModel;
|
|
using namespace CalculatorApp::Controls;
|
|
using namespace Platform;
|
|
using namespace Platform::Collections;
|
|
using namespace std;
|
|
using namespace Windows::Foundation;
|
|
using namespace Windows::System;
|
|
using namespace Windows::UI;
|
|
using namespace Windows::UI::ViewManagement;
|
|
using namespace Windows::UI::Xaml;
|
|
using namespace Windows::UI::Xaml::Media;
|
|
using namespace Windows::UI::Xaml::Controls;
|
|
using namespace Windows::UI::Xaml::Controls::Primitives;
|
|
using namespace Windows::UI::Xaml::Input;
|
|
using namespace GraphControl;
|
|
using namespace Calculator::Utils;
|
|
|
|
namespace
|
|
{
|
|
StringReference EquationsPropertyName(L"Equations");
|
|
}
|
|
|
|
EquationInputArea::EquationInputArea()
|
|
: m_lastLineColorIndex{ -1 }
|
|
, m_AvailableColors{ ref new Vector<SolidColorBrush ^>() }
|
|
, m_accessibilitySettings{ ref new AccessibilitySettings() }
|
|
, m_equationToFocus{ nullptr }
|
|
{
|
|
m_accessibilitySettings->HighContrastChanged +=
|
|
ref new TypedEventHandler<AccessibilitySettings ^, Object ^>(this, &EquationInputArea::OnHighContrastChanged);
|
|
|
|
ReloadAvailableColors(m_accessibilitySettings->HighContrast);
|
|
|
|
InitializeComponent();
|
|
}
|
|
|
|
void EquationInputArea::OnPropertyChanged(String ^ propertyName)
|
|
{
|
|
if (propertyName == EquationsPropertyName)
|
|
{
|
|
OnEquationsPropertyChanged();
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::OnEquationsPropertyChanged()
|
|
{
|
|
if (Equations != nullptr && Equations->Size == 0)
|
|
{
|
|
AddNewEquation();
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::AddNewEquation()
|
|
{
|
|
if (Equations->Size > 0)
|
|
{
|
|
Equations->GetAt(Equations->Size - 1)->IsLastItemInList = false;
|
|
}
|
|
|
|
m_lastLineColorIndex = (m_lastLineColorIndex + 1) % AvailableColors->Size;
|
|
auto eq = ref new EquationViewModel(ref new Equation(), ++m_lastFunctionLabelIndex, AvailableColors->GetAt(m_lastLineColorIndex)->Color);
|
|
eq->IsLastItemInList = true;
|
|
m_equationToFocus = eq;
|
|
Equations->Append(eq);
|
|
}
|
|
|
|
void EquationInputArea::InputTextBox_GotFocus(Object ^ sender, RoutedEventArgs ^ e)
|
|
{
|
|
KeyboardShortcutManager::HonorShortcuts(false);
|
|
}
|
|
|
|
void EquationInputArea::InputTextBox_LostFocus(Object ^ sender, RoutedEventArgs ^ e)
|
|
{
|
|
KeyboardShortcutManager::HonorShortcuts(true);
|
|
}
|
|
|
|
void EquationInputArea::InputTextBox_Submitted(Object ^ sender, MathRichEditBoxSubmission ^ submission)
|
|
{
|
|
auto tb = static_cast<EquationTextBox ^>(sender);
|
|
if (tb == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
auto eq = static_cast<EquationViewModel ^>(tb->DataContext);
|
|
if (eq == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (submission->Source == EquationSubmissionSource::ENTER_KEY ||
|
|
(submission->Source == EquationSubmissionSource::FOCUS_LOST && submission->HasTextChanged && eq->Expression != nullptr && eq->Expression->Length() > 0))
|
|
{
|
|
unsigned int index = 0;
|
|
if (Equations->IndexOf(eq, &index))
|
|
{
|
|
if (index == Equations->Size - 1)
|
|
{
|
|
// If it's the last equation of the list
|
|
AddNewEquation();
|
|
}
|
|
else
|
|
{
|
|
auto nextEquation = Equations->GetAt(index + 1);
|
|
FocusEquationTextBox(nextEquation);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::FocusEquationTextBox(EquationViewModel ^ equation)
|
|
{
|
|
unsigned int index;
|
|
if (!Equations->IndexOf(equation, &index) || index < 0)
|
|
{
|
|
return;
|
|
}
|
|
auto container = EquationInputList->TryGetElement(index);
|
|
if (container == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
auto equationTextBox = dynamic_cast<EquationTextBox ^>(container);
|
|
if (equationTextBox != nullptr)
|
|
{
|
|
equationTextBox->FocusTextBox();
|
|
}
|
|
else
|
|
{
|
|
auto equationInput = VisualTree::FindDescendantByName(container, "EquationInputButton");
|
|
if (equationInput == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
equationTextBox = dynamic_cast<EquationTextBox ^>(equationInput);
|
|
if (equationTextBox != nullptr)
|
|
{
|
|
equationTextBox->FocusTextBox();
|
|
}
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::EquationTextBox_RemoveButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
|
|
{
|
|
auto tb = static_cast<EquationTextBox ^>(sender);
|
|
auto eq = static_cast<EquationViewModel ^>(tb->DataContext);
|
|
unsigned int index;
|
|
if (Equations->IndexOf(eq, &index))
|
|
{
|
|
if (eq->FunctionLabelIndex == m_lastFunctionLabelIndex)
|
|
{
|
|
m_lastFunctionLabelIndex--;
|
|
}
|
|
|
|
if (index == Equations->Size - 1 && Equations->Size > 1)
|
|
{
|
|
Equations->GetAt(Equations->Size - 2)->IsLastItemInList = true;
|
|
}
|
|
Equations->RemoveAt(index);
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::EquationTextBox_KeyGraphFeaturesButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
|
|
{
|
|
auto tb = static_cast<EquationTextBox ^>(sender);
|
|
auto eq = static_cast<EquationViewModel ^>(tb->DataContext);
|
|
KeyGraphFeaturesRequested(this, eq);
|
|
}
|
|
|
|
void EquationInputArea::EquationTextBox_EquationButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
|
|
{
|
|
auto tb = static_cast<EquationTextBox ^>(sender);
|
|
auto eq = static_cast<EquationViewModel ^>(tb->DataContext);
|
|
eq->IsLineEnabled = !eq->IsLineEnabled;
|
|
}
|
|
|
|
void EquationInputArea::InputTextBox_Loaded(Object ^ sender, RoutedEventArgs ^ e)
|
|
{
|
|
auto tb = static_cast<EquationTextBox ^>(sender);
|
|
|
|
auto colorChooser = static_cast<EquationStylePanelControl ^>(tb->ColorChooserFlyout->Content);
|
|
colorChooser->AvailableColors = AvailableColors;
|
|
|
|
if (m_equationToFocus != nullptr && tb->DataContext == m_equationToFocus)
|
|
{
|
|
m_equationToFocus = nullptr;
|
|
tb->FocusTextBox();
|
|
|
|
unsigned int index;
|
|
if (Equations->IndexOf(m_equationToFocus, &index))
|
|
{
|
|
auto container = EquationInputList->TryGetElement(index);
|
|
if (container != nullptr)
|
|
{
|
|
container->StartBringIntoView();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::InputTextBox_DataContextChanged(Windows::UI::Xaml::FrameworkElement ^ sender, Windows::UI::Xaml::DataContextChangedEventArgs ^ args)
|
|
{
|
|
auto tb = static_cast<EquationTextBox ^>(sender);
|
|
if (!tb->IsLoaded)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FocusEquationIfNecessary(tb);
|
|
}
|
|
|
|
void EquationInputArea::FocusEquationIfNecessary(CalculatorApp::Controls::EquationTextBox ^ textBox)
|
|
{
|
|
if (m_equationToFocus != nullptr && textBox->DataContext == m_equationToFocus)
|
|
{
|
|
m_equationToFocus = nullptr;
|
|
textBox->FocusTextBox();
|
|
|
|
unsigned int index;
|
|
if (Equations->IndexOf(m_equationToFocus, &index))
|
|
{
|
|
auto container = EquationInputList->TryGetElement(index);
|
|
if (container != nullptr)
|
|
{
|
|
container->StartBringIntoView();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::OnHighContrastChanged(AccessibilitySettings ^ sender, Object ^ args)
|
|
{
|
|
ReloadAvailableColors(sender->HighContrast);
|
|
}
|
|
|
|
void EquationInputArea::ReloadAvailableColors(bool isHighContrast)
|
|
{
|
|
m_AvailableColors->Clear();
|
|
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush1")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush2")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush3")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush4")));
|
|
|
|
// If this is not high contrast, we have all 16 colors, otherwise we will restrict this to a subset of high contrast colors
|
|
if (!isHighContrast)
|
|
{
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush5")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush6")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush7")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush8")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush9")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush10")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush11")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush12")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush13")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush14")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush15")));
|
|
m_AvailableColors->Append(safe_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"EquationBrush16")));
|
|
}
|
|
|
|
// If there are no equations to reload, quit early
|
|
if (Equations == nullptr || Equations->Size == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Reassign colors for each equation
|
|
m_lastLineColorIndex = -1;
|
|
for (auto equationViewModel : Equations)
|
|
{
|
|
m_lastLineColorIndex = (m_lastLineColorIndex + 1) % AvailableColors->Size;
|
|
equationViewModel->LineColor = AvailableColors->GetAt(m_lastLineColorIndex)->Color;
|
|
}
|
|
}
|
|
|
|
void EquationInputArea::TextBoxGotFocus(TextBox ^ sender, RoutedEventArgs ^ e)
|
|
{
|
|
sender->SelectAll();
|
|
}
|
|
|
|
void EquationInputArea::SubmitTextbox(TextBox ^ sender)
|
|
{
|
|
auto variableViewModel = static_cast<VariableViewModel ^>(sender->DataContext);
|
|
double val;
|
|
if (sender->Name == "ValueTextBox")
|
|
{
|
|
val = validateDouble(sender->Text, variableViewModel->Value);
|
|
variableViewModel->Value = val;
|
|
}
|
|
else if (sender->Name == "MinTextBox")
|
|
{
|
|
val = validateDouble(sender->Text, variableViewModel->Min);
|
|
variableViewModel->Min = val;
|
|
}
|
|
else if (sender->Name == "MaxTextBox")
|
|
{
|
|
val = validateDouble(sender->Text, variableViewModel->Max);
|
|
variableViewModel->Max = val;
|
|
}
|
|
else if (sender->Name == "StepTextBox")
|
|
{
|
|
val = validateDouble(sender->Text, variableViewModel->Step);
|
|
variableViewModel->Step = val;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
wostringstream oss;
|
|
oss << std::noshowpoint << val;
|
|
sender->Text = ref new String(oss.str().c_str());
|
|
}
|
|
|
|
void EquationInputArea::TextBoxLosingFocus(TextBox ^ sender, LosingFocusEventArgs ^)
|
|
{
|
|
SubmitTextbox(sender);
|
|
}
|
|
|
|
void EquationInputArea::TextBoxKeyDown(TextBox ^ sender, KeyRoutedEventArgs ^ e)
|
|
{
|
|
if (e->Key == ::VirtualKey::Enter)
|
|
{
|
|
SubmitTextbox(sender);
|
|
}
|
|
}
|
|
|
|
double EquationInputArea::validateDouble(String ^ value, double defaultValue)
|
|
{
|
|
try
|
|
{
|
|
return stod(value->Data());
|
|
}
|
|
catch (...)
|
|
{
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
::Visibility EquationInputArea::ManageEditVariablesButtonVisibility(unsigned int numberOfVariables)
|
|
{
|
|
return numberOfVariables == 0 ? ::Visibility::Collapsed : ::Visibility::Visible;
|
|
}
|