diff --git a/src/CalcViewModel/ApplicationViewModel.cpp b/src/CalcViewModel/ApplicationViewModel.cpp index 066c98424..40141ada0 100644 --- a/src/CalcViewModel/ApplicationViewModel.cpp +++ b/src/CalcViewModel/ApplicationViewModel.cpp @@ -190,7 +190,7 @@ void ApplicationViewModel::OnCopyCommand(Object ^ parameter) { DateCalcViewModel->OnCopyCommand(parameter); } - else + else if (NavCategory::IsCalculatorViewMode(m_mode)) { CalculatorViewModel->OnCopyCommand(parameter); } diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj index 711c93839..dbc128131 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj +++ b/src/CalcViewModel/CalcViewModel.vcxproj @@ -332,6 +332,7 @@ + @@ -366,6 +367,7 @@ + @@ -421,4 +423,4 @@ - + \ No newline at end of file diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters index 982352489..eac651a7b 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj.filters +++ b/src/CalcViewModel/CalcViewModel.vcxproj.filters @@ -92,6 +92,9 @@ Common\Automation + + GraphingCalculator + @@ -220,6 +223,9 @@ GraphingCalculator + + GraphingCalculator + diff --git a/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.cpp b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.cpp new file mode 100644 index 000000000..b201b216d --- /dev/null +++ b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.cpp @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "GraphingSettingsViewModel.h" +#include + +using namespace CalculatorApp::ViewModel; +using namespace CalcManager::NumberFormattingUtils; +using namespace GraphControl; +using namespace std; +using namespace Platform; + +GraphingSettingsViewModel::GraphingSettingsViewModel() + : m_XMinValue(0) + , m_XMaxValue(0) + , m_YMinValue(0) + , m_YMaxValue(0) + , m_XMinError(false) + , m_XMaxError(false) + , m_YMinError(false) + , m_YMaxError(false) + , m_dontUpdateDisplayRange(false) + , m_XIsMinLastChanged(true) + , m_YIsMinLastChanged(true) +{ +} + +void GraphingSettingsViewModel::SetGrapher(Grapher ^ grapher) +{ + if (grapher != nullptr) + { + if (grapher->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Invalid) + { + grapher->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Radians; + } + } + Graph = grapher; + InitRanges(); + RaisePropertyChanged(L"TrigUnit"); +} + +void GraphingSettingsViewModel::InitRanges() +{ + double xMin = 0, xMax = 0, yMin = 0, yMax = 0; + if (m_Graph != nullptr) + { + m_Graph->GetDisplayRanges(&xMin, &xMax, &yMin, &yMax); + } + m_dontUpdateDisplayRange = true; + m_XMinValue = xMin; + m_XMaxValue = xMax; + m_YMinValue = yMin; + m_YMaxValue = yMax; + auto valueStr = to_wstring(m_XMinValue); + TrimTrailingZeros(valueStr); + m_XMin = ref new String(valueStr.c_str()); + + valueStr = to_wstring(m_XMaxValue); + TrimTrailingZeros(valueStr); + m_XMax = ref new String(valueStr.c_str()); + + valueStr = to_wstring(m_YMinValue); + TrimTrailingZeros(valueStr); + m_YMin = ref new String(valueStr.c_str()); + + valueStr = to_wstring(m_YMaxValue); + TrimTrailingZeros(valueStr); + m_YMax = ref new String(valueStr.c_str()); + + m_dontUpdateDisplayRange = false; +} + +void GraphingSettingsViewModel::RefreshPosition() +{ + if (HasError()) + { + InitRanges(); + } + else + { + if (m_Graph != nullptr) + { + m_Graph->SetDisplayRanges(m_XMinValue, m_XMaxValue, m_YMinValue, m_YMaxValue); + } + } +} + +void GraphingSettingsViewModel::UpdateDisplayRange(bool XValuesModified) +{ + if (m_Graph == nullptr || m_dontUpdateDisplayRange || HasError()) + { + return; + } + + if (m_Graph->ForceProportionalAxes) + { + // If ForceProportionalAxes is set, the graph will try to automatically adjust ranges to remain proportional. + // but without a logic to choose which values can be modified or not. + // To solve this problem, we calculate the new ranges here, taking care to not modify the current axis and + // modifying only the least recently updated value of the other axis. + + if (XValuesModified) + { + if (m_YIsMinLastChanged) + { + auto yMaxValue = m_YMinValue + (m_XMaxValue - m_XMinValue) * m_Graph->ActualHeight / m_Graph->ActualWidth; + if (m_YMaxValue != yMaxValue) + { + m_YMaxValue = yMaxValue; + auto valueStr = to_wstring(m_YMaxValue); + TrimTrailingZeros(valueStr); + m_YMax = ref new String(valueStr.c_str()); + RaisePropertyChanged("YMax"); + } + } + else + { + auto yMinValue = m_YMaxValue - (m_XMaxValue - m_XMinValue) * m_Graph->ActualHeight / m_Graph->ActualWidth; + if (m_YMinValue != yMinValue) + { + m_YMinValue = yMinValue; + auto valueStr = to_wstring(m_YMinValue); + TrimTrailingZeros(valueStr); + m_YMin = ref new String(valueStr.c_str()); + RaisePropertyChanged("YMin"); + } + } + } + else + { + if (m_XIsMinLastChanged) + { + auto xMaxValue = m_XMinValue + (m_YMaxValue - m_YMinValue) * m_Graph->ActualWidth / m_Graph->ActualHeight; + if (m_XMaxValue != xMaxValue) + { + m_XMaxValue = xMaxValue; + auto valueStr = to_wstring(m_XMaxValue); + TrimTrailingZeros(valueStr); + m_XMax = ref new String(valueStr.c_str()); + RaisePropertyChanged("XMax"); + } + } + else + { + auto xMinValue = m_XMaxValue - (m_YMaxValue - m_YMinValue) * m_Graph->ActualWidth / m_Graph->ActualHeight; + if (m_XMinValue != xMinValue) + { + m_XMinValue = xMinValue; + auto valueStr = to_wstring(m_XMinValue); + TrimTrailingZeros(valueStr); + m_XMin = ref new String(valueStr.c_str()); + RaisePropertyChanged("XMin"); + } + } + } + } + m_Graph->SetDisplayRanges(m_XMinValue, m_XMaxValue, m_YMinValue, m_YMaxValue); +} + +bool GraphingSettingsViewModel::HasError() +{ + return m_XMinError || m_YMinError || m_XMaxError || m_YMaxError || XError || YError; +} diff --git a/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h new file mode 100644 index 000000000..b9fc4756b --- /dev/null +++ b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h @@ -0,0 +1,297 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "../Common/Utils.h" + +namespace CalculatorApp::ViewModel +{ +#pragma once + [Windows::UI::Xaml::Data::Bindable] public ref class GraphingSettingsViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + OBSERVABLE_OBJECT(); + OBSERVABLE_PROPERTY_R(bool, YMinError); + OBSERVABLE_PROPERTY_R(bool, XMinError); + OBSERVABLE_PROPERTY_R(bool, XMaxError); + OBSERVABLE_PROPERTY_R(bool, YMaxError); + OBSERVABLE_PROPERTY_R(GraphControl::Grapher ^, Graph); + + GraphingSettingsViewModel(); + + property bool XError + { + bool get() + { + return !m_XMinError && !m_XMaxError && m_XMinValue >= m_XMaxValue; + } + } + + property bool YError + { + bool get() + { + return !m_YMinError && !m_YMaxError && m_YMinValue >= m_YMaxValue; + } + } + + property Platform::String ^ XMin + { + Platform::String ^ get() + { + return m_XMin; + } + void set(Platform::String ^ value) + { + if (m_XMin == value) + { + return; + } + m_XMin = value; + m_XIsMinLastChanged = true; + if (m_Graph != nullptr) + { + try + { + size_t sz; + auto number = std::stod(value->Data(), &sz); + if (value->Length() == sz) + { + m_Graph->XAxisMin = m_XMinValue = number; + XMinError = false; + } + else + { + XMinError = true; + } + } + catch (...) + { + XMinError = true; + } + } + RaisePropertyChanged("XError"); + RaisePropertyChanged("XMin"); + UpdateDisplayRange(true); + } + } + + property Platform::String ^ XMax + { + Platform::String ^ get() + { + return m_XMax; + } + void set(Platform::String ^ value) + { + if (m_XMax == value) + { + return; + } + m_XMax = value; + m_XIsMinLastChanged = false; + if (m_Graph != nullptr) + { + try + { + size_t sz; + auto number = std::stod(value->Data(), &sz); + if (value->Length() == sz) + { + m_Graph->XAxisMax = m_XMaxValue = number; + XMaxError = false; + } + else + { + XMaxError = true; + } + } + catch (...) + { + XMaxError = true; + } + } + RaisePropertyChanged("XError"); + RaisePropertyChanged("XMax"); + UpdateDisplayRange(true); + } + } + + property Platform::String ^ YMin + { + Platform::String ^ get() + { + return m_YMin; + } + void set(Platform::String ^ value) + { + if (m_YMin == value) + { + return; + } + m_YMin = value; + m_YIsMinLastChanged = true; + if (m_Graph != nullptr) + { + try + { + size_t sz; + auto number = std::stod(value->Data(), &sz); + if (value->Length() == sz) + { + m_Graph->YAxisMin = m_YMinValue = number; + YMinError = false; + } + else + { + YMinError = true; + } + } + catch (...) + { + YMinError = true; + } + } + RaisePropertyChanged("YError"); + RaisePropertyChanged("YMin"); + UpdateDisplayRange(false); + } + } + + property Platform::String ^ YMax + { + Platform::String ^ get() + { + return m_YMax; + } + void set(Platform::String ^ value) + { + if (m_YMax == value) + { + return; + } + m_YMax = value; + m_YIsMinLastChanged = false; + if (m_Graph != nullptr) + { + try + { + size_t sz; + auto number = std::stod(value->Data(), &sz); + if (value->Length() == sz) + { + m_Graph->YAxisMax = m_YMaxValue = number; + YMaxError = false; + } + else + { + YMaxError = true; + } + } + catch (...) + { + YMaxError = true; + } + } + RaisePropertyChanged("YError"); + RaisePropertyChanged("YMax"); + UpdateDisplayRange(false); + } + } + + property int TrigUnit + { + int get() + { + return m_Graph == nullptr ? (int)Graphing::EvalTrigUnitMode::Invalid : m_Graph->TrigUnitMode; + } + void set(int value) + { + if (m_Graph == nullptr) + { + return; + } + m_Graph->TrigUnitMode = value; + RaisePropertyChanged(L"TrigUnit"); + } + } + + property bool TrigModeRadians + { + bool get() + { + return m_Graph != nullptr && m_Graph->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Radians; + } + void set(bool value) + { + if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Radians) + { + m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Radians; + RaisePropertyChanged(L"TrigModeRadians"); + RaisePropertyChanged(L"TrigModeDegrees"); + RaisePropertyChanged(L"TrigModeGradians"); + RefreshPosition(); + } + } + } + + property bool TrigModeDegrees + { + bool get() + { + return m_Graph != nullptr && m_Graph->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Degrees; + } + void set(bool value) + { + if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Degrees) + { + m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Degrees; + RaisePropertyChanged(L"TrigModeDegrees"); + RaisePropertyChanged(L"TrigModeRadians"); + RaisePropertyChanged(L"TrigModeGradians"); + RefreshPosition(); + } + } + } + + property bool TrigModeGradians + { + bool get() + { + return m_Graph != nullptr && m_Graph->TrigUnitMode == (int)Graphing::EvalTrigUnitMode::Grads; + } + void set(bool value) + { + if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Grads) + { + m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Grads; + RaisePropertyChanged(L"TrigModeGradians"); + RaisePropertyChanged(L"TrigModeDegrees"); + RaisePropertyChanged(L"TrigModeRadians"); + RefreshPosition(); + } + } + } + + public: + void UpdateDisplayRange(bool XValuesModified); + void RefreshPosition(); + + public: + void SetGrapher(GraphControl::Grapher ^ grapher); + void InitRanges(); + bool HasError(); + + private: + Platform::String ^ m_XMin; + Platform::String ^ m_XMax; + Platform::String ^ m_YMin; + Platform::String ^ m_YMax; + double m_XMinValue; + double m_XMaxValue; + double m_YMinValue; + double m_YMaxValue; + bool m_dontUpdateDisplayRange; + bool m_XIsMinLastChanged; + bool m_YIsMinLastChanged; + }; +} diff --git a/src/Calculator/Calculator.vcxproj b/src/Calculator/Calculator.vcxproj index 974a818b1..348ea9267 100644 --- a/src/Calculator/Calculator.vcxproj +++ b/src/Calculator/Calculator.vcxproj @@ -226,7 +226,7 @@ 0.0.0.0 - true + true @@ -296,6 +296,9 @@ Views\GraphingCalculator\GraphingCalculator.xaml + + Views\GraphingCalculator\GraphingSettings.xaml + Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml @@ -363,8 +366,9 @@ + - + @@ -460,6 +464,9 @@ Views\GraphingCalculator\GraphingCalculator.xaml + + Views\GraphingCalculator\GraphingSettings.xaml + Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml @@ -891,4 +898,4 @@ - + \ No newline at end of file diff --git a/src/Calculator/Calculator.vcxproj.filters b/src/Calculator/Calculator.vcxproj.filters index 0233c028e..6a6b15b15 100644 --- a/src/Calculator/Calculator.vcxproj.filters +++ b/src/Calculator/Calculator.vcxproj.filters @@ -509,6 +509,8 @@ Views\GraphingCalculator + + Views\GraphingCalculator Views\GraphingCalculator diff --git a/src/Calculator/Resources/en-US/Resources.resw b/src/Calculator/Resources/en-US/Resources.resw index 8182ac5d4..716b67ded 100644 --- a/src/Calculator/Resources/en-US/Resources.resw +++ b/src/Calculator/Resources/en-US/Resources.resw @@ -4202,12 +4202,60 @@ Current mode is graph mode Announcement used in Graphing Calculator when switching to the graph mode + + Grid + Heading for grid extents on the settings + + + Degrees + Degrees mode on settings page + + + Gradians + Gradian mode on settings page + + + Radians + Radians mode on settings page + + + Units + Heading for Unit's on the settings + + + X-Max + X maximum value header + + + X-Min + X minimum value header + + + Y-Max + Y Maximum value header + + + Y-Min + Y minimum value header + Enter an equation Used in the Graphing Calculator to indicate to users that they can enter an equation in the textbox + + Grid options + This is the tooltip text for the grid options button in Graphing Calculator + + + Grid options + This is the automation name text for the grid options button in Graphing Calculator + + + Graph Options + Heading for the Graph Options flyout in Graphing mode. + Enter an equation this is the placeholder text used by the textbox to enter an equation - \ No newline at end of file + diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml index 37eb4a763..ac4844ec7 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml @@ -7,7 +7,6 @@ xmlns:graphControl="using:GraphControl" xmlns:local="using:CalculatorApp" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:vm="using:CalculatorApp.ViewModel" x:Name="Control" DataContextChanged="GraphingCalculator_DataContextChanged" mc:Ignorable="d"> @@ -416,12 +415,23 @@ x:Uid="shareButton" MinWidth="40" Style="{ThemeResource ThemedGraphButtonStyle}" - contract7Present:CornerRadius="{ThemeResource RightButtonCornerRadius}" Click="OnShareClick"> + + - diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp index 137c67646..d4f620538 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp @@ -15,6 +15,7 @@ #include "Calculator/Controls/EquationTextBox.h" #include "Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h" #include "CalcViewModel/Common/Utils.h" +#include "GraphingSettings.xaml.h" using namespace CalculatorApp; using namespace CalculatorApp::Common; @@ -42,6 +43,7 @@ using namespace Windows::UI::Xaml::Automation; using namespace Windows::UI::Xaml::Automation::Peers; using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Media::Imaging; @@ -69,12 +71,12 @@ GraphingCalculator::GraphingCalculator() // OemMinus and OemAdd aren't declared in the VirtualKey enum, we can't add this accelerator XAML-side auto virtualKey = ref new KeyboardAccelerator(); - virtualKey->Key = (VirtualKey)187; //OemMinus key + virtualKey->Key = (VirtualKey)189; // OemPlus key virtualKey->Modifiers = VirtualKeyModifiers::Control; ZoomOutButton->KeyboardAccelerators->Append(virtualKey); virtualKey = ref new KeyboardAccelerator(); - virtualKey->Key = (VirtualKey)189; //OemAdd key + virtualKey->Key = (VirtualKey)187; // OemAdd key virtualKey->Modifiers = VirtualKeyModifiers::Control; ZoomInButton->KeyboardAccelerators->Append(virtualKey); } @@ -158,7 +160,7 @@ void GraphingCalculator::OnEquationsVectorChanged(IObservableVectorPlotGraph(); } -void GraphingCalculator::OnTracePointChanged(Windows::Foundation::Point newPoint) +void GraphingCalculator::OnTracePointChanged(Point newPoint) { wstringstream traceValueString; @@ -475,7 +477,7 @@ void CalculatorApp::GraphingCalculator::ActiveTracing_Checked(Platform::Object ^ FocusManager::TryFocusAsync(GraphingControl, ::FocusState::Programmatic); m_activeTracingKeyUpToken = Window::Current->CoreWindow->KeyUp += - ref new Windows::Foundation::TypedEventHandler( + ref new TypedEventHandler( this, &CalculatorApp::GraphingCalculator::ActiveTracing_KeyUp); KeyboardShortcutManager::IgnoreEscape(false); @@ -505,3 +507,25 @@ void CalculatorApp::GraphingCalculator::ActiveTracing_KeyUp(Windows::UI::Core::C args->Handled = true; } } + +void GraphingCalculator::GraphSettingsButton_Click(Object ^ sender, RoutedEventArgs ^ e) +{ + DisplayGraphSettings(); +} + +void GraphingCalculator::DisplayGraphSettings() +{ + auto graphSettings = ref new GraphingSettings(); + graphSettings->SetGrapher(this->GraphingControl); + auto flyoutGraphSettings = ref new Flyout(); + flyoutGraphSettings->Content = graphSettings; + flyoutGraphSettings->Closing += ref new TypedEventHandler(this, &GraphingCalculator::OnSettingsFlyout_Closing); + flyoutGraphSettings->ShowAt(GraphSettingsButton); +} + +void GraphingCalculator::OnSettingsFlyout_Closing(FlyoutBase ^ sender, FlyoutBaseClosingEventArgs ^ args) +{ + auto flyout = static_cast(sender); + auto graphingSetting = static_cast(flyout->Content); + args->Cancel = graphingSetting->CanBeClose(); +} diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h index 54b45db17..e5bb1de66 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h @@ -8,6 +8,7 @@ #include "Views\NumberPad.xaml.h" #include "Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml.h" #include "Views\GraphingCalculator\GraphingNumPad.xaml.h" +#include "Views\GraphingCalculator\GraphingSettings.xaml.h" namespace CalculatorApp { @@ -73,6 +74,10 @@ public ref class GraphingCalculator sealed : public Windows::UI::Xaml::Data::INo void ActiveTracing_Unchecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); void ActiveTracing_KeyUp(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ args); void ActiveTracing_PointerCaptureLost(Platform::Object ^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs ^ e); + void GraphSettingsButton_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + + void DisplayGraphSettings(); + private: Windows::Foundation::EventRegistrationToken m_dataRequestedToken; Windows::Foundation::EventRegistrationToken m_vectorChangedToken; @@ -80,6 +85,8 @@ public ref class GraphingCalculator sealed : public Windows::UI::Xaml::Data::INo Windows::Foundation::EventRegistrationToken m_activeTracingKeyUpToken; Windows::Foundation::EventRegistrationToken m_ActiveTracingPointerCaptureLost; CalculatorApp::ViewModel::GraphingCalculatorViewModel ^ m_viewModel; + void + OnSettingsFlyout_Closing(Windows::UI::Xaml::Controls::Primitives::FlyoutBase ^ sender, Windows::UI::Xaml::Controls::Primitives::FlyoutBaseClosingEventArgs ^ args); }; } diff --git a/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml b/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml new file mode 100644 index 000000000..58451b590 --- /dev/null +++ b/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml.cpp b/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml.cpp new file mode 100644 index 000000000..c1ee621e4 --- /dev/null +++ b/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml.cpp @@ -0,0 +1,94 @@ +#include "pch.h" + +#include "GraphingSettings.xaml.h" +#include "CalcViewModel\Common\AppResourceProvider.cpp" + +using namespace std; +using namespace Graphing; +using namespace GraphControl; + +using namespace CalculatorApp; +using namespace CalculatorApp::ViewModel; + +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::System; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; + +GraphingSettings::GraphingSettings() + : m_ViewModel(ref new GraphingSettingsViewModel()) +{ + InitializeComponent(); +} + +void GraphingSettings::SetGrapher(Grapher ^ grapher) +{ + m_ViewModel->SetGrapher(grapher); +} + +Style ^ GraphingSettings::SelectTextBoxStyle(bool incorrectRange, bool error) +{ + if (incorrectRange || error) + { + return static_cast<::Style ^>(this->Resources->Lookup(L"ErrorTextBoxStyle")); + } + else + { + return nullptr; + } +} + +void GraphingSettings::GridSettingsTextBox_PreviewKeyDown(Platform::Object ^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e) +{ + if (e->Key == VirtualKey::Enter) + { + if (!FocusManager::TryMoveFocusAsync(FocusNavigationDirection::Next)) + { + FocusManager::TryMoveFocusAsync(FocusNavigationDirection::Previous); + } + e->Handled = true; + } +} + +bool GraphingSettings::CanBeClose() +{ + auto focusedElement = FocusManager::GetFocusedElement(); + + // Move focus so we are sure all values are in sync with the VM + if (focusedElement != nullptr) + { + if (focusedElement->Equals(SettingsXMin)) + { + auto textbox = static_cast(focusedElement); + ViewModel->XMin = textbox->Text; + } + else if (focusedElement->Equals(SettingsXMax)) + { + auto textbox = static_cast(focusedElement); + ViewModel->XMax = textbox->Text; + } + else if (focusedElement->Equals(SettingsYMin)) + { + auto textbox = static_cast(focusedElement); + ViewModel->YMin = textbox->Text; + } + else if (focusedElement->Equals(SettingsYMax)) + { + auto textbox = static_cast(focusedElement); + ViewModel->YMax = textbox->Text; + } + } + return ViewModel != nullptr && ViewModel->HasError(); +} + +void GraphingSettings::RefreshRanges() +{ + ViewModel->InitRanges(); +} diff --git a/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml.h b/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml.h new file mode 100644 index 000000000..e726b4fa9 --- /dev/null +++ b/src/Calculator/Views/GraphingCalculator/GraphingSettings.xaml.h @@ -0,0 +1,28 @@ +// +// MyUserControl.xaml.h +// Declaration of the MyUserControl class +// + +#pragma once + +#include "CalcViewModel/Common/Utils.h" +#include "CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h" +#include "Views\GraphingCalculator\GraphingSettings.g.h" +#include + +namespace CalculatorApp +{ + [Windows::Foundation::Metadata::WebHostHidden] public ref class GraphingSettings sealed + { + public: + GraphingSettings(); + + PROPERTY_R(CalculatorApp::ViewModel::GraphingSettingsViewModel ^, ViewModel); + Windows::UI::Xaml::Style ^ SelectTextBoxStyle(bool incorrectRange, bool error); + void SetGrapher(GraphControl::Grapher ^ grapher); + bool CanBeClose(); + void RefreshRanges(); + private: + void GridSettingsTextBox_PreviewKeyDown(Platform::Object ^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs ^ e); + }; +} diff --git a/src/GraphControl/Control/Grapher.cpp b/src/GraphControl/Control/Grapher.cpp index 405a7053a..1b8257060 100644 --- a/src/GraphControl/Control/Grapher.cpp +++ b/src/GraphControl/Control/Grapher.cpp @@ -451,6 +451,11 @@ namespace GraphControl { options.SetForceProportional(ForceProportionalAxes); + if (!options.GetAllowKeyGraphFeaturesForFunctionsWithParameters()) + { + options.SetAllowKeyGraphFeaturesForFunctionsWithParameters(true); + } + if (!validEqs.empty()) { vector graphColors; @@ -479,8 +484,9 @@ namespace GraphControl return validEqs; } - void Grapher::OnForceProportionalAxesPropertyChanged(bool /*oldValue*/, bool /*newValue*/) + void Grapher::OnForceProportionalAxesPropertyChanged(bool /*oldValue*/, bool newValue) { + m_calculatedForceProportional = newValue; TryUpdateGraph(); } diff --git a/src/GraphControl/Control/Grapher.h b/src/GraphControl/Control/Grapher.h index fa84aec76..026e57ae1 100644 --- a/src/GraphControl/Control/Grapher.h +++ b/src/GraphControl/Control/Grapher.h @@ -104,6 +104,142 @@ public void PlotGraph(); GraphControl::KeyGraphFeaturesInfo ^ AnalyzeEquation(GraphControl::Equation ^ equation); + // We can't use the EvalTrigUnitMode enum directly in as the property type because it comes from another module which doesn't expose + // it as a public enum class. So the compiler doesn't recognize it as a valid type for the ABI boundary. + property int TrigUnitMode + { + void set(int value) + { + if (value != (int)m_solver->EvalOptions().GetTrigUnitMode()) + { + m_solver->EvalOptions().SetTrigUnitMode((Graphing::EvalTrigUnitMode)value); + PlotGraph(); + } + } + + int get() + { + return (int)m_solver->EvalOptions().GetTrigUnitMode(); + } + } + + property double XAxisMin + { + double get() + { + return m_graph->GetOptions().GetDefaultXRange().first; + } + void set(double value) + { + std::pair newValue(value, XAxisMax); + if (m_graph != nullptr) + { + m_graph->GetOptions().SetDefaultXRange(newValue); + if (m_renderMain != nullptr) + { + m_renderMain->RunRenderPass(); + } + } + } + } + + property double XAxisMax + { + double get() + { + return m_graph->GetOptions().GetDefaultXRange().second; + } + void set(double value) + { + std::pair newValue(XAxisMin, value); + if (m_graph != nullptr) + { + m_graph->GetOptions().SetDefaultXRange(newValue); + if (m_renderMain != nullptr) + { + m_renderMain->RunRenderPass(); + } + } + } + } + + property double YAxisMin + { + double get() + { + return m_graph->GetOptions().GetDefaultXRange().first; + } + void set(double value) + { + std::pair newValue(value, YAxisMax); + if (m_graph != nullptr) + { + m_graph->GetOptions().SetDefaultYRange(newValue); + if (m_renderMain != nullptr) + { + m_renderMain->RunRenderPass(); + } + } + } + } + + property double YAxisMax + { + double get() + { + return m_graph->GetOptions().GetDefaultXRange().second; + } + void set(double value) + { + std::pair newValue(YAxisMin, value); + if (m_graph != nullptr) + { + m_graph->GetOptions().SetDefaultYRange(newValue); + if (m_renderMain != nullptr) + { + m_renderMain->RunRenderPass(); + } + } + } + } + + void GetDisplayRanges(double* xMin, double* xMax, double* yMin, double* yMax) + { + try + { + if (m_graph != nullptr) + { + if (auto render = m_graph->GetRenderer()) + { + render->GetDisplayRanges(*xMin, *xMax, *yMin, *yMax); + } + } + } + catch (const std::exception&) + { + OutputDebugString(L"GetDisplayRanges failed\r\n"); + } + } + + void SetDisplayRanges(double xMin, double xMax, double yMin, double yMax) + { + try + { + if (auto render = m_graph->GetRenderer()) + { + render->SetDisplayRanges(xMin, xMax, yMin, yMax); + if (m_renderMain) + { + m_renderMain->RunRenderPass(); + } + } + } + catch (const std::exception&) + { + OutputDebugString(L"SetDisplayRanges failed\r\n"); + } + } + protected: #pragma region Control Overrides void OnApplyTemplate() override; @@ -146,9 +282,6 @@ public void SetEquationsAsValid(); void SetEquationErrors(); - Windows::Foundation::Collections::IObservableVector ^ ConvertWStringVector(std::vector inVector); - Windows::Foundation::Collections::IObservableMap ^ ConvertWStringIntMap(std::map inMap); - private: DX::RenderMain ^ m_renderMain = nullptr; @@ -168,7 +301,7 @@ public const std::unique_ptr m_solver; const std::shared_ptr m_graph; - + bool m_calculatedForceProportional = false; bool m_tracingTracking; enum KeysPressedSlots { @@ -181,7 +314,6 @@ public bool m_KeysPressed[5]; bool m_Moving; - Windows::UI::Xaml::DispatcherTimer ^ m_TracingTrackingTimer; public: diff --git a/src/GraphControl/DirectX/RenderMain.cpp b/src/GraphControl/DirectX/RenderMain.cpp index bb832b702..c8f559cc4 100644 --- a/src/GraphControl/DirectX/RenderMain.cpp +++ b/src/GraphControl/DirectX/RenderMain.cpp @@ -172,7 +172,6 @@ namespace GraphControl::DX if (m_drawNearestPoint || m_drawActiveTracing) { Point trackPoint = m_pointerLocation; - if (m_drawActiveTracing) { // Active tracing takes over for draw nearest point input from the mouse pointer. @@ -181,21 +180,17 @@ namespace GraphControl::DX m_ActiveTracingPointRenderer.Render(m_activeTracingPointerLocation); } - int formulaId; - Point nearestPointLocation; - pair nearestPointValue; - renderer->GetClosePointData( - trackPoint.X, - trackPoint.Y, - formulaId, - nearestPointLocation.X, - nearestPointLocation.Y, - nearestPointValue.first, - nearestPointValue.second); - - if (!isnan(nearestPointLocation.X) && !isnan(nearestPointLocation.Y)) + int formulaId = -1; + float nearestPointLocationX, nearestPointLocationY; + float nearestPointValueX, nearestPointValueY; + + if (renderer->GetClosePointData( + trackPoint.X, trackPoint.Y, formulaId, nearestPointLocationX, nearestPointLocationY, nearestPointValueX, nearestPointValueY) + == S_OK) { - auto lineColors = m_graph->GetOptions().GetGraphColors(); + if (!isnan(nearestPointLocationX) && !isnan(nearestPointLocationY)) + { + auto lineColors = m_graph->GetOptions().GetGraphColors(); if (formulaId >= 0 && static_cast(formulaId) < lineColors.size()) { @@ -203,10 +198,16 @@ namespace GraphControl::DX m_nearestPointRenderer.SetColor(D2D1::ColorF(dotColor.R * 65536 + dotColor.G * 256 + dotColor.B, 1.0)); } - m_nearestPointRenderer.Render(nearestPointLocation); - m_Tracing = true; - m_TraceLocation = Point(nearestPointLocation.X, nearestPointLocation.Y); - m_TraceValue = Point(nearestPointValue.first, nearestPointValue.second); + m_TraceLocation = Point(nearestPointLocationX, nearestPointLocationY); + m_nearestPointRenderer.Render(m_TraceLocation); + m_Tracing = true; + m_TraceLocation = Point(nearestPointLocationX, nearestPointLocationY); + m_TraceValue = Point(nearestPointValueX, nearestPointValueY); + } + else + { + m_Tracing = false; + } } else { diff --git a/src/GraphingImpl/GraphingImpl.vcxproj b/src/GraphingImpl/GraphingImpl.vcxproj index 4a6cc8728..d8b2903ad 100644 --- a/src/GraphingImpl/GraphingImpl.vcxproj +++ b/src/GraphingImpl/GraphingImpl.vcxproj @@ -242,6 +242,7 @@ + @@ -249,6 +250,10 @@ + + + + @@ -270,4 +275,4 @@ - + \ No newline at end of file diff --git a/src/GraphingImpl/GraphingImpl.vcxproj.filters b/src/GraphingImpl/GraphingImpl.vcxproj.filters index c73668613..6dd6775f0 100644 --- a/src/GraphingImpl/GraphingImpl.vcxproj.filters +++ b/src/GraphingImpl/GraphingImpl.vcxproj.filters @@ -48,5 +48,20 @@ GraphingInterfaces + + Mocks + + + Mocks + + + GraphingInterfaces + + + Mocks + + + Mocks + \ No newline at end of file diff --git a/src/GraphingImpl/Mocks/Bitmap.h b/src/GraphingImpl/Mocks/Bitmap.h new file mode 100644 index 000000000..7469698d6 --- /dev/null +++ b/src/GraphingImpl/Mocks/Bitmap.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "GraphingInterfaces/IBitmap.h" +#include +namespace MockGraphingImpl +{ + class Bitmap : public Graphing::IBitmap + { + virtual const std::vector& GetData() const + { + return std::vector(); + } + }; +} diff --git a/src/GraphingImpl/Mocks/Graph.h b/src/GraphingImpl/Mocks/Graph.h new file mode 100644 index 000000000..e28f5e74f --- /dev/null +++ b/src/GraphingImpl/Mocks/Graph.h @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "GraphingInterfaces/IGraph.h" +#include "GraphingOptions.h" +#include "Mocks/GraphRenderer.h" + +namespace MockGraphingImpl +{ + class Graph : public Graphing::IGraph + { + public: + Graph() + { + m_graphRenderer = std::make_shared(); + } + virtual std::optional>> TryInitialize(const Graphing::IExpression* graphingExp = nullptr) + { + return std::nullopt; + } + + virtual Graphing::IGraphingOptions& GetOptions() + { + return m_graphingOptions; + } + + virtual std::vector> GetVariables() + { + return m_variables; + } + + virtual void SetArgValue(std::wstring variableName, double value) + { + } + + virtual std::shared_ptr GetRenderer() const + { + return m_graphRenderer; + } + + virtual bool TryResetSelection() + { + return true; + } + + virtual std::shared_ptr GetAnalyzer() const + { + return nullptr; + } + + private: + std::vector> m_variables; + GraphingOptions m_graphingOptions; + std::shared_ptr m_graphRenderer; + }; +} diff --git a/src/GraphingImpl/Mocks/GraphRenderer.h b/src/GraphingImpl/Mocks/GraphRenderer.h new file mode 100644 index 000000000..964105db2 --- /dev/null +++ b/src/GraphingImpl/Mocks/GraphRenderer.h @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "GraphingInterfaces/IGraphRenderer.h" +#include "GraphingInterfaces/GraphingEnums.h" +#include "Mocks/Bitmap.h" +#include "Mocks/GraphingOptions.h" +#include + +namespace MockGraphingImpl +{ + class GraphRenderer : public Graphing::Renderer::IGraphRenderer + { + public: + GraphRenderer() + : m_xMin(-10) + , m_xMax(10) + , m_yMin(-10) + , m_yMax(10) + { + } + + virtual HRESULT SetGraphSize(unsigned int width, unsigned int height) + { + return S_OK; + } + virtual HRESULT SetDpi(float dpiX, float dpiY) + { + return S_OK; + } + + virtual HRESULT DrawD2D1(ID2D1Factory* pDirect2dFactory, ID2D1RenderTarget* pRenderTarget, bool& hasSomeMissingDataOut) + { + hasSomeMissingDataOut = false; + return S_OK; + } + + virtual HRESULT GetClosePointData( + float inScreenPointX, + float inScreenPointY, + int& formulaIdOut, + float& xScreenPointOut, + float& yScreenPointOut, + float& xValueOut, + float& yValueOut) + { + formulaIdOut = 0; + xScreenPointOut = 0; + yScreenPointOut = 0; + xValueOut = 0; + yValueOut = 0; + return S_OK; + } + + virtual HRESULT ScaleRange(double centerX, double centerY, double scale) + { + m_xMin = scale * (m_xMin - centerX) + centerX; + m_xMax = scale * (m_xMax - centerX) + centerX; + m_yMin = scale * (m_yMin - centerY) + centerY; + m_yMax = scale * (m_yMax - centerY) + centerY; + return S_OK; + } + + virtual HRESULT ChangeRange(Graphing::Renderer::ChangeRangeAction action) + { + return S_OK; + } + virtual HRESULT MoveRangeByRatio(double ratioX, double ratioY) + { + return S_OK; + } + virtual HRESULT ResetRange() + { + return S_OK; + } + virtual HRESULT GetDisplayRanges(double& xMin, double& xMax, double& yMin, double& yMax) + { + xMin = m_xMin; + xMax = m_xMax; + yMin = m_yMin; + yMax = m_yMax; + return S_OK; + } + virtual HRESULT SetDisplayRanges(double xMin, double xMax, double yMin, double yMax) + { + m_xMin = xMin; + m_xMax = xMax; + m_yMin = yMin; + m_yMax = yMax; + return S_OK; + } + + virtual HRESULT GetBitmap(std::shared_ptr& bitmapOut, bool& hasSomeMissingDataOut) + { + bitmapOut = std::make_shared(); + hasSomeMissingDataOut = false; + return S_OK; + } + + private: + double m_xMin; + double m_xMax; + double m_yMin; + double m_yMax; + }; +} diff --git a/src/GraphingImpl/Mocks/GraphingOptions.h b/src/GraphingImpl/Mocks/GraphingOptions.h new file mode 100644 index 000000000..1234a403e --- /dev/null +++ b/src/GraphingImpl/Mocks/GraphingOptions.h @@ -0,0 +1,418 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "GraphingInterfaces/IGraphingOptions.h" + +namespace MockGraphingImpl +{ + class GraphingOptions : public Graphing::IGraphingOptions + { + public: + GraphingOptions() + : m_markZeros(true) + , m_markYIntercept(false) + , m_markMinima(false) + , m_markMaxima(false) + , m_markInflectionPoints(false) + , m_markVerticalAsymptotes(false) + , m_markHorizontalAsymptotes(false) + , m_markObliqueAsymptotes(false) + , m_maxExecutionTime(0) + , m_colors() + , m_backColor() + , m_allowKeyGraphFeaturesForFunctionsWithParameters(false) + , m_zerosColor() + , m_extremaColor() + , m_inflectionPointsColor() + , m_asymptotesColor() + , m_axisColor() + , m_boxColor() + , m_fontColor() + , m_showAxis(true) + , m_showGrid(true) + , m_showBox(true) + , m_forceProportional(false) + , m_aliasX(L"x") + , m_aliasY(L"y") + , m_lineStyle(Graphing::Renderer::LineStyle::Solid) + , m_XRange{ -10, 10 } + , m_YRange{ -10, 10 } + { + } + + virtual void ResetMarkKeyGraphFeaturesData() + { + } + + virtual bool GetMarkZeros() const + { + return m_markZeros; + } + virtual void SetMarkZeros(bool value) + { + m_markZeros = value; + } + + virtual bool GetMarkYIntercept() const + { + return m_markYIntercept; + } + virtual void SetMarkYIntercept(bool value) + { + m_markYIntercept = value; + } + + virtual bool GetMarkMinima() const + { + return m_markMinima; + } + virtual void SetMarkMinima(bool value) + { + m_markMinima = value; + } + + virtual bool GetMarkMaxima() const + { + return m_markMaxima; + } + virtual void SetMarkMaxima(bool value) + { + m_markMaxima = value; + } + + virtual bool GetMarkInflectionPoints() const + { + return m_markInflectionPoints; + } + virtual void SetMarkInflectionPoints(bool value) + { + m_markInflectionPoints = value; + } + + virtual bool GetMarkVerticalAsymptotes() const + { + return m_markVerticalAsymptotes; + } + virtual void SetMarkVerticalAsymptotes(bool value) + { + m_markVerticalAsymptotes = value; + } + + virtual bool GetMarkHorizontalAsymptotes() const + { + return m_markHorizontalAsymptotes; + } + virtual void SetMarkHorizontalAsymptotes(bool value) + { + m_markHorizontalAsymptotes = value; + } + + virtual bool GetMarkObliqueAsymptotes() const + { + return m_markObliqueAsymptotes; + } + virtual void SetMarkObliqueAsymptotes(bool value) + { + m_markObliqueAsymptotes = value; + } + + virtual unsigned long long GetMaxExecutionTime() const + { + return m_maxExecutionTime; + } + virtual void SetMaxExecutionTime(unsigned long long value) + { + m_maxExecutionTime = value; + } + + virtual void ResetMaxExecutionTime() + { + m_maxExecutionTime = 0; + }; + + virtual std::vector GetGraphColors() const + { + return m_colors; + } + virtual bool SetGraphColors(const std::vector& colors) + { + m_colors = colors; + return true; + } + virtual void ResetGraphColors() + { + m_colors.clear(); + } + + virtual Graphing::Color GetBackColor() const + { + return m_backColor; + } + virtual void SetBackColor(const Graphing::Color& value) + { + m_backColor = value; + } + + virtual void ResetBackColor() + { + m_backColor = Graphing::Color(); + } + + virtual void SetAllowKeyGraphFeaturesForFunctionsWithParameters(bool kgf) + { + m_allowKeyGraphFeaturesForFunctionsWithParameters = kgf; + } + virtual bool GetAllowKeyGraphFeaturesForFunctionsWithParameters() const + { + return m_allowKeyGraphFeaturesForFunctionsWithParameters; + } + virtual void ResetAllowKeyGraphFeaturesForFunctionsWithParameters() + { + m_allowKeyGraphFeaturesForFunctionsWithParameters = true; + } + + virtual Graphing::Color GetZerosColor() const + { + return m_zerosColor; + } + virtual void SetZerosColor(const Graphing::Color& value) + { + m_zerosColor = value; + } + virtual void ResetZerosColor() + { + m_zerosColor = Graphing::Color(); + } + + virtual Graphing::Color GetExtremaColor() const + { + return m_extremaColor; + } + virtual void SetExtremaColor(const Graphing::Color& value) + { + m_extremaColor = value; + } + virtual void ResetExtremaColor() + { + m_extremaColor = Graphing::Color(); + } + + virtual Graphing::Color GetInflectionPointsColor() const + { + return m_inflectionPointsColor; + } + virtual void SetInflectionPointsColor(const Graphing::Color& value) + { + m_inflectionPointsColor = value; + } + virtual void ResetInflectionPointsColor() + { + m_inflectionPointsColor = Graphing::Color(); + } + + virtual Graphing::Color GetAsymptotesColor() const + { + return m_asymptotesColor; + } + virtual void SetAsymptotesColor(const Graphing::Color& value) + { + m_asymptotesColor = value; + } + virtual void ResetAsymptotesColor() + { + m_asymptotesColor = Graphing::Color(); + } + + virtual Graphing::Color GetAxisColor() const + { + return m_axisColor; + } + virtual void SetAxisColor(const Graphing::Color& value) + { + m_axisColor = value; + } + virtual void ResetAxisColor() + { + m_axisColor = Graphing::Color(); + } + + virtual Graphing::Color GetBoxColor() const + { + return m_boxColor; + } + virtual void SetBoxColor(const Graphing::Color& value) + { + m_boxColor = value; + } + virtual void ResetBoxColor() + { + m_boxColor = Graphing::Color(); + } + + virtual Graphing::Color GetFontColor() const + { + return m_fontColor; + } + virtual void SetFontColor(const Graphing::Color& value) + { + m_fontColor = value; + } + virtual void ResetFontColor() + { + m_fontColor = Graphing::Color(); + } + + virtual bool GetShowAxis() const + { + return m_showAxis; + } + virtual void SetShowAxis(bool value) + { + m_showAxis = value; + } + virtual void ResetShowAxis() + { + m_showAxis = true; + } + + virtual bool GetShowGrid() const + { + return m_showGrid; + } + virtual void SetShowGrid(bool value) + { + m_showGrid = value; + } + virtual void ResetShowGrid() + { + m_showGrid = true; + } + + virtual bool GetShowBox() const + { + return m_showBox; + } + virtual void SetShowBox(bool value) + { + m_showBox = value; + } + virtual void ResetShowBox() + { + m_showBox = true; + } + + virtual bool GetForceProportional() const + { + return m_forceProportional; + } + virtual void SetForceProportional(bool value) + { + m_forceProportional = value; + } + virtual void ResetForceProportional() + { + m_forceProportional = false; + } + + virtual std::wstring GetAliasX() const + { + return m_aliasX; + } + virtual void SetAliasX(const std::wstring& value) + { + m_aliasX = value; + } + virtual void ResetAliasX() + { + m_aliasX = L""; + } + + virtual std::wstring GetAliasY() const + { + return m_aliasY; + } + virtual void SetAliasY(const std::wstring& value) + { + m_aliasY = value; + } + virtual void ResetAliasY() + { + m_aliasY = L""; + } + + virtual Graphing::Renderer::LineStyle GetLineStyle() const + { + return m_lineStyle; + } + virtual void SetLineStyle(Graphing::Renderer::LineStyle value) + { + m_lineStyle = value; + } + virtual void ResetLineStyle() + { + m_lineStyle = Graphing::Renderer::LineStyle::Solid; + } + + virtual std::pair GetDefaultXRange() const + { + return m_XRange; + } + + virtual bool SetDefaultXRange(const std::pair& minmax) + { + m_XRange = minmax; + return true; + } + virtual void ResetDefaultXRange() + { + m_XRange = { 0, 0 }; + } + + virtual std::pair GetDefaultYRange() const + { + return m_YRange; + } + + virtual bool SetDefaultYRange(const std::pair& minmax) + { + m_YRange = minmax; + return true; + } + virtual void ResetDefaultYRange() + { + m_YRange = { 0, 0 }; + } + + private: + bool m_markZeros; + bool m_markYIntercept; + bool m_markMinima; + bool m_markMaxima; + bool m_markInflectionPoints; + bool m_markVerticalAsymptotes; + bool m_markHorizontalAsymptotes; + bool m_markObliqueAsymptotes; + unsigned long long m_maxExecutionTime; + std::vector m_colors; + Graphing::Color m_backColor; + bool m_allowKeyGraphFeaturesForFunctionsWithParameters; + Graphing::Color m_zerosColor; + Graphing::Color m_extremaColor; + Graphing::Color m_inflectionPointsColor; + Graphing::Color m_asymptotesColor; + Graphing::Color m_axisColor; + Graphing::Color m_boxColor; + Graphing::Color m_fontColor; + bool m_showAxis; + bool m_showGrid; + bool m_showBox; + bool m_forceProportional; + std::wstring m_aliasX; + std::wstring m_aliasY; + Graphing::Renderer::LineStyle m_lineStyle; + std::pair m_XRange; + std::pair m_YRange; + }; +} diff --git a/src/GraphingImpl/Mocks/MathSolver.cpp b/src/GraphingImpl/Mocks/MathSolver.cpp index 2ca159854..41a070847 100644 --- a/src/GraphingImpl/Mocks/MathSolver.cpp +++ b/src/GraphingImpl/Mocks/MathSolver.cpp @@ -3,6 +3,7 @@ #include "pch.h" #include "MathSolver.h" +#include "Mocks/Graph.h" using namespace std; @@ -13,3 +14,13 @@ namespace Graphing return make_unique(); } } + +shared_ptr MockGraphingImpl::MathSolver::CreateGrapher() +{ + return make_shared(); +} + +shared_ptr MockGraphingImpl::MathSolver::CreateGrapher(const Graphing::IExpression* expression) +{ + return make_shared(); +} diff --git a/src/GraphingImpl/Mocks/MathSolver.h b/src/GraphingImpl/Mocks/MathSolver.h index 7394c341e..165959b97 100644 --- a/src/GraphingImpl/Mocks/MathSolver.h +++ b/src/GraphingImpl/Mocks/MathSolver.h @@ -17,6 +17,23 @@ namespace MockGraphingImpl class EvalOptions : public Graphing::IEvalOptions { + public: + EvalOptions() + : m_unit(Graphing::EvalTrigUnitMode::Invalid) + { + } + + Graphing::EvalTrigUnitMode GetTrigUnitMode() const override + { + return m_unit; + } + void SetTrigUnitMode(Graphing::EvalTrigUnitMode value) override + { + m_unit = value; + } + + private: + Graphing::EvalTrigUnitMode m_unit; }; class FormatOptions : public Graphing::IFormatOptions @@ -34,6 +51,10 @@ namespace MockGraphingImpl class MathSolver : public Graphing::IMathSolver { public: + MathSolver() + { + } + Graphing::IParsingOptions& ParsingOptions() override { return m_parsingOptions; @@ -54,19 +75,13 @@ namespace MockGraphingImpl return nullptr; } - std::shared_ptr CreateGrapher(const Graphing::IExpression* expression) override - { - return nullptr; - } + std::shared_ptr CreateGrapher(const Graphing::IExpression* expression) override; - std::shared_ptr CreateGrapher() override - { - return nullptr; - } + std::shared_ptr CreateGrapher() override; std::wstring Serialize(const Graphing::IExpression* expression) override { - return std::wstring{}; + return L""; } Graphing::IGraphFunctionAnalysisData IMathSolver::Analyze(const Graphing::Analyzer::IGraphAnalyzer* analyzer) diff --git a/src/GraphingInterfaces/Common.h b/src/GraphingInterfaces/Common.h index 37514c29b..f31524000 100644 --- a/src/GraphingInterfaces/Common.h +++ b/src/GraphingInterfaces/Common.h @@ -1,7 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include #include + #ifndef GRAPHINGAPI #ifdef GRAPHING_ENGINE_IMPL #define GRAPHINGAPI __declspec(dllexport) diff --git a/src/GraphingInterfaces/GraphingEnums.h b/src/GraphingInterfaces/GraphingEnums.h index 81bfbebe8..becd5b763 100644 --- a/src/GraphingInterfaces/GraphingEnums.h +++ b/src/GraphingInterfaces/GraphingEnums.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once namespace Graphing @@ -12,10 +15,10 @@ namespace Graphing enum class EquationParsingMode { - // Solving an equation. At least one equal sign is required + // Solving an equation. At least one equal sign is required SolveEquation, - // Graphing an equation. At least one equal sign is required + // Graphing an equation. At least one equal sign is required GraphEquation, // Not expecting an equation. No equal sign is allowed @@ -29,9 +32,9 @@ namespace Graphing { // This format is not very human-readable, but best for machine processing and unit test. // The meaning of an expression is precise, there is no need for parentheses, and it's easy to parse. - // While other serializers may contain little tweaks to make the UI component work as expected, this - // format doesn't change often because no real UI uses it. - // Example: Sum[1,Divide[2,x]] + // While other serializers may contain little tweaks to make the UI component work as expected, this + // format doesn't change often because no real UI uses it. + // Example: Sum[1,Divide[2,x]] Formula, // Similar to Formula, except the variables are in the format of Var(0), Var(1), ... instead of in their names. @@ -39,9 +42,9 @@ namespace Graphing // Example: Sum[1,Divide[2,Var(0)]] InvariantFormula, - // Similar to Formula, except the aggregates (grouping parentheses) are silently removed during serialization. + // Similar to Formula, except the aggregates (grouping parentheses) are silently removed during serialization. // The primary usage for this format is in internal test cases. - // When used in parsing, it's identical to Formula + // When used in parsing, it's identical to Formula // Example: Sum[1,Divide[2,x]] FormulaWithoutAggregate, @@ -50,29 +53,29 @@ namespace Graphing // Example: 1+2/x Linear, - // This format is similar to linear format, but during serialization it uses ASCII characters only (except for variable + // This format is similar to linear format, but during serialization it uses ASCII characters only (except for variable // named specified by the user) and can round trip back to the linear parser. - // - // When used in parsing it's identical to Linear. + // + // When used in parsing it's identical to Linear. LinearInput, // The standard MathML format. Note that the math engine can only parse a subset of the syntax in the MathML specification. // Example: <math><mn>1</mn><mo>+</mo><mfrac><mn>2</mn><mi>x</mi></mfrac></math> MathML, - // Same as MathML, except this format type won't generate the root element <math> . + // Same as MathML, except this format type won't generate the root element <math> . // Used in serialization only (CasContext.FormatOptions) but not in parsing (CasContext.ParsingOptions) // Example: <mn>1</mn><mo>+</mo><mfrac><mn>2</mn><mi>x</mi></mfrac> MathMLNoWrapper, // This format type is for the RichEdit wrapper to render math in RichEdit. - // + // // Used in serialization only (CasContext.FormatOptions) but not in parsing (CasContext.ParsingOptions) // Example: 1 + \frac{2,x} MathRichEdit, // This format type is for the RichEdit wrapper to render math in RichEdit. - // It's same with MathRichEdit format with one exception: fractions are rendered + // It's same with MathRichEdit format with one exception: fractions are rendered // horizontally instead of vertically. This is a better choice if the display area // is confined with a small height. // @@ -125,7 +128,7 @@ namespace Graphing // Specify the current trigonometry unit mode: Radians, Degrees, Grads. This has effect on these trig operators: // Sin Cos Tan Cot Sec Csc - // ASin ACos ATan ACot ASec ACsc. + // ASin ACos ATan ACot ASec ACsc. // It has NO effect on hyperbolic trig operators (same behavior as Windows Calc), and any other operators. enum class EvalTrigUnitMode { @@ -272,7 +275,7 @@ namespace Graphing ShowVerboseSolution, // bit mask of action type. Can be used to remove the Informational flag - TypeMask, // mask to get the type + TypeMask, // mask to get the type // A flag that can be added onto any type. This is informational only that explains what the straight input would do. // No action should be performed @@ -385,188 +388,188 @@ namespace Graphing }; } - namespace Analyzer { - - // Graph Analyzer Messages - enum GraphAnalyzerMessage - { - // "No data" - GraphAnalyzerMessage_None = 0, + namespace Analyzer + { + // Graph Analyzer Messages + enum GraphAnalyzerMessage + { + // "No data" + GraphAnalyzerMessage_None = 0, - // "No zeros" - GraphAnalyzerMessage_NoZeros = 1, + // "No zeros" + GraphAnalyzerMessage_NoZeros = 1, - // "No y-intercept" - GraphAnalyzerMessage_NoYIntercept = 2, + // "No y-intercept" + GraphAnalyzerMessage_NoYIntercept = 2, - // "No minima" - GraphAnalyzerMessage_NoMinima = 3, + // "No minima" + GraphAnalyzerMessage_NoMinima = 3, - // "No maxima" - GraphAnalyzerMessage_NoMaxima = 4, + // "No maxima" + GraphAnalyzerMessage_NoMaxima = 4, - // "No inflection points" - GraphAnalyzerMessage_NoInflectionPoints = 5, + // "No inflection points" + GraphAnalyzerMessage_NoInflectionPoints = 5, - // "No vertical asymptotes" - GraphAnalyzerMessage_NoVerticalAsymptotes = 6, + // "No vertical asymptotes" + GraphAnalyzerMessage_NoVerticalAsymptotes = 6, - // "No horizontal asymptotes" - GraphAnalyzerMessage_NoHorizontalAsymptotes = 7, + // "No horizontal asymptotes" + GraphAnalyzerMessage_NoHorizontalAsymptotes = 7, - // "No oblique asymptotes" - GraphAnalyzerMessage_NoObliqueAsymptotes = 8, + // "No oblique asymptotes" + GraphAnalyzerMessage_NoObliqueAsymptotes = 8, - // "Not able to calculate" - GraphAnalyzerMessage_NotAbleToCalculate = 9, + // "Not able to calculate" + GraphAnalyzerMessage_NotAbleToCalculate = 9, - // "Not able to mark all graph features" - GraphAnalyzerMessage_NotAbleToMarkAllGraphFeatures = 10, + // "Not able to mark all graph features" + GraphAnalyzerMessage_NotAbleToMarkAllGraphFeatures = 10, - // These features are too complex for {APPLICATION_NAME} to calculate - GraphAnalyzerMessage_TheseFeaturesAreTooComplexToCalculate = 11, + // These features are too complex for {APPLICATION_NAME} to calculate + GraphAnalyzerMessage_TheseFeaturesAreTooComplexToCalculate = 11, - // "This feature is too complex for {APPLICATION_NAME} to calculate" - GraphAnalyzerMessage_ThisFeatureIsTooComplexToCalculate = 12 - }; + // "This feature is too complex for {APPLICATION_NAME} to calculate" + GraphAnalyzerMessage_ThisFeatureIsTooComplexToCalculate = 12 + }; - // define which data should be filled into result object - enum AnalysisType - { - // fill domain data - AnalysisType_Domain = 0, + // define which data should be filled into result object + enum AnalysisType + { + // fill domain data + AnalysisType_Domain = 0, - // fill range data - AnalysisType_Range = 1, + // fill range data + AnalysisType_Range = 1, - // fill parity data - AnalysisType_Parity = 2, + // fill parity data + AnalysisType_Parity = 2, - // fill zeros - AnalysisType_Zeros = 3, + // fill zeros + AnalysisType_Zeros = 3, - // fill interception with y axis - AnalysisType_YIntercept = 4, + // fill interception with y axis + AnalysisType_YIntercept = 4, - // fill minima - AnalysisType_Minima = 5, + // fill minima + AnalysisType_Minima = 5, - // fill maxima - AnalysisType_Maxima = 6, + // fill maxima + AnalysisType_Maxima = 6, - // fill inflection points - AnalysisType_InflectionPoints = 7, + // fill inflection points + AnalysisType_InflectionPoints = 7, - // fill vertical asymptotes - AnalysisType_VerticalAsymptotes = 8, + // fill vertical asymptotes + AnalysisType_VerticalAsymptotes = 8, - // fill horizontal asymptotes - AnalysisType_HorizontalAsymptotes = 9, + // fill horizontal asymptotes + AnalysisType_HorizontalAsymptotes = 9, - // fill oblique asymptotes - AnalysisType_ObliqueAsymptotes = 10, + // fill oblique asymptotes + AnalysisType_ObliqueAsymptotes = 10, - // fill monotonicity - AnalysisType_Monotonicity = 11, + // fill monotonicity + AnalysisType_Monotonicity = 11, - // fill period - AnalysisType_Period = 12 - }; + // fill period + AnalysisType_Period = 12 + }; - // define which additional data should be calculated - enum class PerformAnalysisType - { - // Calculate nothing - //PerformAnalysisType_None = 0x0, + // define which additional data should be calculated + enum class PerformAnalysisType + { + // Calculate nothing + // PerformAnalysisType_None = 0x0, - // Calculate domain data - PerformAnalysisType_Domain = 0x01, + // Calculate domain data + PerformAnalysisType_Domain = 0x01, - // Calculate range data - PerformAnalysisType_Range = 0x02, + // Calculate range data + PerformAnalysisType_Range = 0x02, - // Calculate parity data - PerformAnalysisType_Parity = 0x04, + // Calculate parity data + PerformAnalysisType_Parity = 0x04, - // Calculate zeros and interception with y axis - PerformAnalysisType_InterceptionPointsWithXAndYAxis = 0x08, + // Calculate zeros and interception with y axis + PerformAnalysisType_InterceptionPointsWithXAndYAxis = 0x08, - // Calculate Extrema and inflection points - PerformAnalysisType_CriticalPoints = 0x10, + // Calculate Extrema and inflection points + PerformAnalysisType_CriticalPoints = 0x10, - // Calculate asymptotes - PerformAnalysisType_Asymptotes = 0x20, + // Calculate asymptotes + PerformAnalysisType_Asymptotes = 0x20, - // Calculate monotonicity - PerformAnalysisType_Monotonicity = 0x40, + // Calculate monotonicity + PerformAnalysisType_Monotonicity = 0x40, - // Calculate period - PerformAnalysisType_Period = 0x80, + // Calculate period + PerformAnalysisType_Period = 0x80, - // Calculate all additional data - PerformAnalysisType_All = 0xFF - }; + // Calculate all additional data + PerformAnalysisType_All = 0xFF + }; - // function parity for function analysis - enum class FunctionParityType - { - // parity not calculated or not possible to calculate - FunctionParityType_Unknown = 0, + // function parity for function analysis + enum class FunctionParityType + { + // parity not calculated or not possible to calculate + FunctionParityType_Unknown = 0, - // parity is odd - FunctionParityType_Odd = 1, + // parity is odd + FunctionParityType_Odd = 1, - // parity is even - FunctionParityType_Even = 2, + // parity is even + FunctionParityType_Even = 2, - // function is not odd nor even - FunctionParityType_None = 3 - }; + // function is not odd nor even + FunctionParityType_None = 3 + }; - // monotonicity direction for function analysis - enum class FunctionMonotonicityType - { - // unknown or not calculated - FunctionMonotonicityType_Unknown = 0, + // monotonicity direction for function analysis + enum class FunctionMonotonicityType + { + // unknown or not calculated + FunctionMonotonicityType_Unknown = 0, - // ascending monotonicity on interval - FunctionMonotonicityType_Ascending = 1, + // ascending monotonicity on interval + FunctionMonotonicityType_Ascending = 1, - // descending monotonicity on interval - FunctionMonotonicityType_Descending = 2, + // descending monotonicity on interval + FunctionMonotonicityType_Descending = 2, - // constant monotonicity on interval - FunctionMonotonicityType_Constant = 3 - }; + // constant monotonicity on interval + FunctionMonotonicityType_Constant = 3 + }; - // asymptote description for function analysis - enum class AsymptoteType - { - // unknown or not calculated - AsymptoteType_Unknown = 0, + // asymptote description for function analysis + enum class AsymptoteType + { + // unknown or not calculated + AsymptoteType_Unknown = 0, - // when x goes to positive infinity - AsymptoteType_PositiveInfinity = 1, + // when x goes to positive infinity + AsymptoteType_PositiveInfinity = 1, - // when x goes to negative infinity - AsymptoteType_NegativeInfinity = 2, + // when x goes to negative infinity + AsymptoteType_NegativeInfinity = 2, - // when x goes to positive or negative infinity - AsymptoteType_AnyInfinity = 3 - }; + // when x goes to positive or negative infinity + AsymptoteType_AnyInfinity = 3 + }; - // function periodicity for function analysis - enum class FunctionPeriodicityType - { - // periodicity not calculated or not possible to calculate - FunctionPeriodicityType_Unknown = 0, + // function periodicity for function analysis + enum class FunctionPeriodicityType + { + // periodicity not calculated or not possible to calculate + FunctionPeriodicityType_Unknown = 0, - // parity is odd - FunctionPeriodicityType_Periodic = 1, + // parity is odd + FunctionPeriodicityType_Periodic = 1, - // parity is even - FunctionPeriodicityType_NotPeriodic = 2 - }; + // parity is even + FunctionPeriodicityType_NotPeriodic = 2 + }; - } + } } diff --git a/src/GraphingInterfaces/IBitmap.h b/src/GraphingInterfaces/IBitmap.h index 46ba34a2d..ee042d53a 100644 --- a/src/GraphingInterfaces/IBitmap.h +++ b/src/GraphingInterfaces/IBitmap.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include diff --git a/src/GraphingInterfaces/IEquation.h b/src/GraphingInterfaces/IEquation.h index f49a0f9a0..1925effd2 100644 --- a/src/GraphingInterfaces/IEquation.h +++ b/src/GraphingInterfaces/IEquation.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "Common.h" diff --git a/src/GraphingInterfaces/IEquationOptions.h b/src/GraphingInterfaces/IEquationOptions.h index 1bdd07370..d4769feeb 100644 --- a/src/GraphingInterfaces/IEquationOptions.h +++ b/src/GraphingInterfaces/IEquationOptions.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "Common.h" diff --git a/src/GraphingInterfaces/IGraph.h b/src/GraphingInterfaces/IGraph.h index e42fd2b40..9eca23624 100644 --- a/src/GraphingInterfaces/IGraph.h +++ b/src/GraphingInterfaces/IGraph.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "Common.h" diff --git a/src/GraphingInterfaces/IGraphAnalyzer.h b/src/GraphingInterfaces/IGraphAnalyzer.h index bfbeed066..4bd962c48 100644 --- a/src/GraphingInterfaces/IGraphAnalyzer.h +++ b/src/GraphingInterfaces/IGraphAnalyzer.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "Common.h" diff --git a/src/GraphingInterfaces/IGraphRenderer.h b/src/GraphingInterfaces/IGraphRenderer.h index a7af01a84..388b80c1d 100644 --- a/src/GraphingInterfaces/IGraphRenderer.h +++ b/src/GraphingInterfaces/IGraphRenderer.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "Common.h" @@ -26,6 +29,8 @@ namespace Graphing::Renderer virtual HRESULT ChangeRange(ChangeRangeAction action) = 0; virtual HRESULT MoveRangeByRatio(double ratioX, double ratioY) = 0; virtual HRESULT ResetRange() = 0; + virtual HRESULT GetDisplayRanges(double& xMin, double& xMax, double& yMin, double& yMax) = 0; + virtual HRESULT SetDisplayRanges(double xMin, double xMax, double yMin, double yMax) = 0; virtual HRESULT GetBitmap(std::shared_ptr& bitmapOut, bool& hasSomeMissingDataOut) = 0; diff --git a/src/GraphingInterfaces/IGraphingOptions.h b/src/GraphingInterfaces/IGraphingOptions.h index 728d6b736..5d47ded54 100644 --- a/src/GraphingInterfaces/IGraphingOptions.h +++ b/src/GraphingInterfaces/IGraphingOptions.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include @@ -49,6 +52,10 @@ namespace Graphing virtual void SetBackColor(const Graphing::Color& value) = 0; virtual void ResetBackColor() = 0; + virtual void SetAllowKeyGraphFeaturesForFunctionsWithParameters(bool kgf) = 0; + virtual bool GetAllowKeyGraphFeaturesForFunctionsWithParameters() const = 0; + virtual void ResetAllowKeyGraphFeaturesForFunctionsWithParameters() = 0; + virtual Graphing::Color GetZerosColor() const = 0; virtual void SetZerosColor(const Graphing::Color& value) = 0; virtual void ResetZerosColor() = 0; diff --git a/src/GraphingInterfaces/IMathSolver.h b/src/GraphingInterfaces/IMathSolver.h index 25c7cbadf..c1df98ac8 100644 --- a/src/GraphingInterfaces/IMathSolver.h +++ b/src/GraphingInterfaces/IMathSolver.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "Common.h" @@ -36,6 +39,9 @@ namespace Graphing struct IEvalOptions : public NonCopyable, public NonMoveable { virtual ~IEvalOptions() = default; + + virtual EvalTrigUnitMode GetTrigUnitMode() const = 0; + virtual void SetTrigUnitMode(EvalTrigUnitMode value) = 0; }; struct IFormatOptions : public NonCopyable, public NonMoveable