Wire up keyboard in graphing calculator (#863)

* Wire up graphing calculator keyboard with math rich edit control

* CR feedback

* Handle focus bug in flyout
This commit is contained in:
Eric Wong
2019-12-19 09:56:03 -08:00
committed by Pepe Rivera
parent 38da8d7b38
commit 13e31799c9
9 changed files with 1252 additions and 893 deletions

View File

@@ -31,7 +31,7 @@ namespace CalculatorApp
static Windows::UI::Xaml::Media::SolidColorBrush
^ ToSolidColorBrush(Windows::UI::Color color) { return ref new Windows::UI::Xaml::Media::SolidColorBrush(color); }
private:
void OnPropertyChanged(Platform::String^ propertyName);
void OnEquationsPropertyChanged();
@@ -59,7 +59,6 @@ namespace CalculatorApp
void TextBoxKeyDown(Windows::UI::Xaml::Controls::TextBox ^ textbox, Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e);
void SubmitTextbox(Windows::UI::Xaml::Controls::TextBox ^ textbox);
private:
Windows::UI::ViewManagement::AccessibilitySettings ^ m_accessibilitySettings;
int m_lastLineColorIndex;
int m_lastFunctionLabelIndex;

View File

@@ -514,7 +514,8 @@
Variables="{x:Bind ViewModel.Variables}"
Visibility="{x:Bind IsKeyGraphFeaturesVisible, Converter={StaticResource BooleanToVisibilityNegationConverter}, Mode=OneWay}"/>
<local:GraphingNumPad Grid.Row="1"
<local:GraphingNumPad x:Name="GraphingNumberPad"
Grid.Row="1"
Margin="2,0,2,2"
Visibility="{x:Bind IsKeyGraphFeaturesVisible, Converter={StaticResource BooleanToVisibilityNegationConverter}, Mode=OneWay}"/>

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,9 @@
#include "pch.h"
#include "GraphingNumPad.xaml.h"
#include "Views/NumberPad.xaml.h"
#include "Controls/CalculatorButton.h"
#include "CalcViewModel/Common/LocalizationSettings.h"
#include "Controls/MathRichEditBox.h"
using namespace CalculatorApp;
@@ -18,43 +21,130 @@ using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
// Dictionary of the enum of the button clicked mapped to an object with the string to enter into the rich edit, and the start and end of the selection after text has been entered.
static const std::unordered_map<NumbersAndOperatorsEnum, std::tuple<Platform::String ^, int, int>> buttonOutput = {
{ NumbersAndOperatorsEnum::Sin, { L"sin()", 4, 0 } },
{ NumbersAndOperatorsEnum::Cos, { L"cos()", 4, 0 } },
{ NumbersAndOperatorsEnum::Tan, { L"tan()", 4, 0 } },
{ NumbersAndOperatorsEnum::Sec, { L"sec()", 4, 0 } },
{ NumbersAndOperatorsEnum::Csc, { L"csc()", 4, 0 } },
{ NumbersAndOperatorsEnum::Cot, { L"cot()", 4, 0 } },
{ NumbersAndOperatorsEnum::InvSin, { L"arcsin()", 7, 0 } },
{ NumbersAndOperatorsEnum::InvCos, { L"arccos()", 7, 0 } },
{ NumbersAndOperatorsEnum::InvTan, { L"arctan()", 7, 0 } },
{ NumbersAndOperatorsEnum::InvSec, { L"arcsec()", 7, 0 } },
{ NumbersAndOperatorsEnum::InvCsc, { L"arccsc()", 7, 0 } },
{ NumbersAndOperatorsEnum::InvCot, { L"arccot()", 7, 0 } },
{ NumbersAndOperatorsEnum::Sinh, { L"sinh()", 5, 0 } },
{ NumbersAndOperatorsEnum::Cosh, { L"cosh()", 5, 0 } },
{ NumbersAndOperatorsEnum::Tanh, { L"tanh()", 5, 0 } },
{ NumbersAndOperatorsEnum::Sech, { L"sech()", 5, 0 } },
{ NumbersAndOperatorsEnum::Csch, { L"csch()", 5, 0 } },
{ NumbersAndOperatorsEnum::Coth, { L"coth()", 5, 0 } },
{ NumbersAndOperatorsEnum::InvSinh, { L"arcsinh()", 8, 0 } },
{ NumbersAndOperatorsEnum::InvCosh, { L"arccosh()", 8, 0 } },
{ NumbersAndOperatorsEnum::InvTanh, { L"arctanh()", 8, 0 } },
{ NumbersAndOperatorsEnum::InvSech, { L"arcsech()", 8, 0 } },
{ NumbersAndOperatorsEnum::InvCsch, { L"arccsch()", 8, 0 } },
{ NumbersAndOperatorsEnum::InvCoth, { L"arccoth()", 8, 0 } },
{ NumbersAndOperatorsEnum::Abs, { L"abs()", 4, 0 } },
{ NumbersAndOperatorsEnum::Floor, { L"floor()", 6, 0 } },
{ NumbersAndOperatorsEnum::Ceil, { L"ceiling()", 8, 0 } },
{ NumbersAndOperatorsEnum::Pi, { L"\u03C0", 1, 0 } },
{ NumbersAndOperatorsEnum::Euler, { L"e", 1, 0 } },
{ NumbersAndOperatorsEnum::XPower2, { L"^2", 2, 0 } },
{ NumbersAndOperatorsEnum::Cube, { L"^3", 2, 0 } },
{ NumbersAndOperatorsEnum::XPowerY, { L"^", 1, 0 } },
{ NumbersAndOperatorsEnum::TenPowerX, { L"10^", 3, 0 } },
{ NumbersAndOperatorsEnum::LogBase10, { L"log()", 4, 0 } },
{ NumbersAndOperatorsEnum::LogBaseE, { L"ln()", 3, 0 } },
{ NumbersAndOperatorsEnum::Sqrt, { L"sqrt()", 5, 0 } },
{ NumbersAndOperatorsEnum::CubeRoot, { L"cbrt()", 5, 0 } },
{ NumbersAndOperatorsEnum::YRootX, { L"root(x,n)", 7, 1 } },
{ NumbersAndOperatorsEnum::TwoPowerX, { L"2^", 2, 0 } },
{ NumbersAndOperatorsEnum::LogBaseX, { L"log(b, x)", 4, 1 } },
{ NumbersAndOperatorsEnum::EPowerX, { L"e^", 4, 0 } },
{ NumbersAndOperatorsEnum::Abs, { L"abs()", 4, 0 } },
{ NumbersAndOperatorsEnum::X, { L"x", 1, 0 } },
{ NumbersAndOperatorsEnum::Y, { L"y", 1, 0 } },
{ NumbersAndOperatorsEnum::OpenParenthesis, { L"(", 1, 0 } },
{ NumbersAndOperatorsEnum::CloseParenthesis, { L")", 1, 0 } },
{ NumbersAndOperatorsEnum::Equals, { L"=", 1, 0 } },
{ NumbersAndOperatorsEnum::Divide, { L"/", 1, 0 } },
{ NumbersAndOperatorsEnum::Multiply, { L"*", 1, 0 } },
{ NumbersAndOperatorsEnum::Subtract, { L"-", 1, 0 } },
{ NumbersAndOperatorsEnum::Add, { L"+", 1, 0 } },
{ NumbersAndOperatorsEnum::Invert, { L"1/", 2, 0 } },
{ NumbersAndOperatorsEnum::Negate, { L"-", 1, 0 } },
{ NumbersAndOperatorsEnum::GreaterThan, { L">", 1, 0 } },
{ NumbersAndOperatorsEnum::GreaterThanOrEqualTo, { L"\u2265", 1, 0 } },
{ NumbersAndOperatorsEnum::LessThan, { L"<", 1, 0 } },
{ NumbersAndOperatorsEnum::LessThanOrEqualTo, { L"\u2264", 1, 0 } },
{ NumbersAndOperatorsEnum::Zero, { L"0", 1, 0 } },
{ NumbersAndOperatorsEnum::One, { L"1", 1, 0 } },
{ NumbersAndOperatorsEnum::Two, { L"2", 1, 0 } },
{ NumbersAndOperatorsEnum::Three, { L"3", 1, 0 } },
{ NumbersAndOperatorsEnum::Four, { L"4", 1, 0 } },
{ NumbersAndOperatorsEnum::Five, { L"5", 1, 0 } },
{ NumbersAndOperatorsEnum::Six, { L"6", 1, 0 } },
{ NumbersAndOperatorsEnum::Seven, { L"7", 1, 0 } },
{ NumbersAndOperatorsEnum::Eight, { L"8", 1, 0 } },
{ NumbersAndOperatorsEnum::Nine, { L"9", 1, 0 } },
{ NumbersAndOperatorsEnum::Decimal, { L".", 1, 0 } },
};
GraphingNumPad::GraphingNumPad()
{
InitializeComponent();
const auto& localizationSettings = CalculatorApp::Common::LocalizationSettings::GetInstance();
DecimalSeparatorButton->Content = localizationSettings.GetDecimalSeparator();
Num0Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('0');
Num1Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('1');
Num2Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('2');
Num3Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('3');
Num4Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('4');
Num5Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('5');
Num6Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('6');
Num7Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('7');
Num8Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('8');
Num9Button->Content = localizationSettings.GetDigitSymbolFromEnUsDigit('9');
}
void GraphingNumPad::ShiftButton_Check(_In_ Platform::Object ^ /*sender*/, _In_ Windows::UI::Xaml::RoutedEventArgs ^ /*e*/)
void GraphingNumPad::ShiftButton_Check(_In_ Platform::Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/)
{
SetOperatorRowVisibility();
}
void GraphingNumPad::ShiftButton_Uncheck(_In_ Platform::Object ^ /*sender*/, _In_ Windows::UI::Xaml::RoutedEventArgs ^ /*e*/)
void GraphingNumPad::ShiftButton_Uncheck(_In_ Platform::Object ^ sender, _In_ RoutedEventArgs ^ /*e*/)
{
ShiftButton->IsChecked = false;
SetOperatorRowVisibility();
FocusManager::TryFocusAsync(ShiftButton, ::FocusState::Programmatic);
GraphingNumPad::Button_Clicked(sender, nullptr);
}
void GraphingNumPad::TrigFlyoutShift_Toggle(_In_ Platform::Object ^ /*sender*/, _In_ Windows::UI::Xaml::RoutedEventArgs ^ /*e*/)
void GraphingNumPad::TrigFlyoutShift_Toggle(_In_ Platform::Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/)
{
SetTrigRowVisibility();
}
void GraphingNumPad::TrigFlyoutHyp_Toggle(_In_ Platform::Object ^ /*sender*/, _In_ Windows::UI::Xaml::RoutedEventArgs ^ /*e*/)
void GraphingNumPad::TrigFlyoutHyp_Toggle(_In_ Platform::Object ^ /*sender*/, _In_ RoutedEventArgs ^ /*e*/)
{
SetTrigRowVisibility();
}
void GraphingNumPad::FlyoutButton_Clicked(_In_ Platform::Object ^ /*sender*/, _In_ Windows::UI::Xaml::RoutedEventArgs ^ /*e*/)
void GraphingNumPad::FlyoutButton_Clicked(_In_ Platform::Object ^ sender, _In_ RoutedEventArgs ^ /*e*/)
{
this->HypButton->IsChecked = false;
this->TrigShiftButton->IsChecked = false;
this->Trigflyout->Hide();
this->FuncFlyout->Hide();
this->InequalityFlyout->Hide();
GraphingNumPad::Button_Clicked(sender, nullptr);
}
void GraphingNumPad::ShiftButton_IsEnabledChanged(_In_ Platform::Object ^ /*sender*/, _In_ Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ /*e*/)
void GraphingNumPad::ShiftButton_IsEnabledChanged(_In_ Platform::Object ^ /*sender*/, _In_ DependencyPropertyChangedEventArgs ^ /*e*/)
{
SetOperatorRowVisibility();
}
@@ -104,3 +194,64 @@ void GraphingNumPad::SetOperatorRowVisibility()
Row1->Visibility = rowVis;
InvRow1->Visibility = invRowVis;
}
void GraphingNumPad::Button_Clicked(Platform::Object ^ sender, DependencyPropertyChangedEventArgs ^ /*e*/)
{
auto mathRichEdit = GetActiveRichEdit();
auto button = dynamic_cast<CalculatorApp::Controls::CalculatorButton ^>(sender);
if (mathRichEdit != nullptr && sender != nullptr)
{
auto id = button->ButtonId;
auto output = buttonOutput.find(id);
mathRichEdit->InsertText(std::get<0>(output->second), std::get<1>(output->second), std::get<2>(output->second));
}
}
void GraphingNumPad::SubmitButton_Clicked(Platform::Object ^ /*sender*/, RoutedEventArgs ^ /*e*/)
{
auto mathRichEdit = GetActiveRichEdit();
if (mathRichEdit != nullptr)
{
mathRichEdit->SubmitEquation(CalculatorApp::Controls::EquationSubmissionSource::ENTER_KEY);
}
}
void GraphingNumPad::ClearButton_Clicked(Platform::Object ^ /*sender*/, RoutedEventArgs ^ /*e*/)
{
auto mathRichEdit = GetActiveRichEdit();
if (mathRichEdit != nullptr)
{
mathRichEdit->MathText = L"<math xmlns=\"http://www.w3.org/1998/Math/MathML\"></math>";
mathRichEdit->SubmitEquation(CalculatorApp::Controls::EquationSubmissionSource::PROGRAMMATIC);
}
}
void GraphingNumPad::BackSpaceButton_Clicked(Platform::Object ^ /*sender*/, RoutedEventArgs ^ /*e*/)
{
auto mathRichEdit = GetActiveRichEdit();
if (mathRichEdit != nullptr)
{
mathRichEdit->BackSpace();
}
}
// To avoid focus moving when the space between buttons is clicked, handle click events that make it through the keypad.
void GraphingNumPad::GraphingNumPad_PointerPressed(Platform::Object ^ /*sender*/, PointerRoutedEventArgs ^ e)
{
e->Handled = true;
}
CalculatorApp::Controls::MathRichEditBox ^ GraphingNumPad::GetActiveRichEdit()
{
return dynamic_cast<Controls::MathRichEditBox ^>(FocusManager::GetFocusedElement());
}
// Adding event because the ShowMode property is ignored in xaml.
void GraphingNumPad::Flyout_Opening(Platform::Object ^ sender, Platform::Object ^ /*e*/)
{
auto flyout = dynamic_cast<Flyout ^>(sender);
if (flyout)
{
flyout->ShowMode = FlyoutShowMode::Transient;
}
}

View File

@@ -5,6 +5,8 @@
#include "Views\GraphingCalculator\GraphingNumPad.g.h"
#include "CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h"
#include "Views/GraphingCalculator/EquationInputArea.xaml.h"
#include "CalcViewModel/Common/CalculatorButtonUser.h"
namespace CalculatorApp
{
@@ -23,5 +25,12 @@ namespace CalculatorApp
void ShiftButton_IsEnabledChanged(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ e);
void SetOperatorRowVisibility();
void SetTrigRowVisibility();
};
void Button_Clicked(_In_ Platform::Object ^ sender, _In_ Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ e);
void SubmitButton_Clicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void ClearButton_Clicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void BackSpaceButton_Clicked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void GraphingNumPad_PointerPressed(Platform::Object ^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e);
Controls::MathRichEditBox^ GetActiveRichEdit();
void Flyout_Opening(Platform::Object ^ sender, Platform::Object ^ e);
};
}