From a59a26519bb0c55404200743f0d54ffd27073b4b Mon Sep 17 00:00:00 2001 From: Daniel Belcher Date: Wed, 20 Mar 2019 14:13:20 -0700 Subject: [PATCH] - Initial commit for Graphing Calculator feature. --- .gitignore | 1 + src/CalcViewModel/ApplicationViewModel.cpp | 10 +- src/CalcViewModel/ApplicationViewModel.h | 2 + src/CalcViewModel/CalcViewModel.vcxproj | 4 + .../CalcViewModel.vcxproj.filters | 15 + .../Common/CalculatorButtonUser.h | 24 +- .../Common/KeyboardShortcutManager.cpp | 42 +- src/CalcViewModel/Common/NavCategory.cpp | 16 +- src/CalcViewModel/Common/NavCategory.h | 4 +- src/CalcViewModel/Common/Utils.cpp | 56 +- src/CalcViewModel/Common/Utils.h | 25 + .../GraphingCalculator/EquationViewModel.cpp | 12 + .../GraphingCalculator/EquationViewModel.h | 16 + .../GraphingCalculatorViewModel.cpp | 18 + .../GraphingCalculatorViewModel.h | 23 + src/Calculator.sln | 68 +- src/Calculator/Calculator.vcxproj | 20 + src/Calculator/Calculator.vcxproj.filters | 9 + src/Calculator/Package.appxmanifest | 4 +- src/Calculator/Resources/en-US/Resources.resw | 40 +- .../GraphingCalculator/EquationInputArea.xaml | 86 +++ .../EquationInputArea.xaml.cpp | 108 +++ .../EquationInputArea.xaml.h | 33 + .../GraphingCalculator.xaml | 242 +++++++ .../GraphingCalculator.xaml.cpp | 51 ++ .../GraphingCalculator.xaml.h | 28 + src/Calculator/Views/MainPage.xaml | 3 + src/Calculator/Views/MainPage.xaml.cpp | 38 +- src/Calculator/Views/MainPage.xaml.h | 29 +- .../NavCategoryUnitTests.cpp | 60 +- src/GraphControl/Control/Equation.cpp | 104 +++ src/GraphControl/Control/Equation.h | 80 +++ src/GraphControl/Control/EquationCollection.h | 176 +++++ src/GraphControl/Control/Grapher.cpp | 392 +++++++++++ src/GraphControl/Control/Grapher.h | 160 +++++ .../Control/InspectingDataSource.cpp | 242 +++++++ .../Control/InspectingDataSource.h | 62 ++ src/GraphControl/DirectX/DeviceResources.cpp | 659 ++++++++++++++++++ src/GraphControl/DirectX/DeviceResources.h | 108 +++ src/GraphControl/DirectX/DirectXHelper.h | 63 ++ .../DirectX/NearestPointRenderer.cpp | 66 ++ .../DirectX/NearestPointRenderer.h | 30 + src/GraphControl/DirectX/RenderMain.cpp | 339 +++++++++ src/GraphControl/DirectX/RenderMain.h | 102 +++ src/GraphControl/GraphControl.vcxproj | 346 +++++++++ src/GraphControl/GraphControl.vcxproj.filters | 68 ++ src/GraphControl/Themes/generic.xaml | 13 + src/GraphControl/pch.cpp | 1 + src/GraphControl/pch.h | 34 + src/GraphControl/winrtHeaders.h | 24 + src/GraphingInterfaces/Common.h | 96 +++ src/GraphingInterfaces/GraphingEnums.h | 387 ++++++++++ src/GraphingInterfaces/IGraph.h | 19 + src/GraphingInterfaces/IGraphRenderer.h | 20 + src/GraphingInterfaces/IGraphingOptions.h | 116 +++ src/GraphingInterfaces/IMathSolver.h | 45 ++ src/MockGraphingImpl/MockGraphingImpl.vcxproj | 297 ++++++++ .../MockGraphingImpl.vcxproj.filters | 47 ++ src/MockGraphingImpl/Mocks/MathSolver.cpp | 12 + src/MockGraphingImpl/Mocks/MathSolver.h | 68 ++ src/MockGraphingImpl/dllmain.cpp | 14 + src/MockGraphingImpl/pch.cpp | 1 + src/MockGraphingImpl/pch.h | 9 + src/MockGraphingImpl/targetver.h | 8 + 64 files changed, 5186 insertions(+), 109 deletions(-) create mode 100644 src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp create mode 100644 src/CalcViewModel/GraphingCalculator/EquationViewModel.h create mode 100644 src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp create mode 100644 src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h create mode 100644 src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml create mode 100644 src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.cpp create mode 100644 src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h create mode 100644 src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml create mode 100644 src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp create mode 100644 src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h create mode 100644 src/GraphControl/Control/Equation.cpp create mode 100644 src/GraphControl/Control/Equation.h create mode 100644 src/GraphControl/Control/EquationCollection.h create mode 100644 src/GraphControl/Control/Grapher.cpp create mode 100644 src/GraphControl/Control/Grapher.h create mode 100644 src/GraphControl/Control/InspectingDataSource.cpp create mode 100644 src/GraphControl/Control/InspectingDataSource.h create mode 100644 src/GraphControl/DirectX/DeviceResources.cpp create mode 100644 src/GraphControl/DirectX/DeviceResources.h create mode 100644 src/GraphControl/DirectX/DirectXHelper.h create mode 100644 src/GraphControl/DirectX/NearestPointRenderer.cpp create mode 100644 src/GraphControl/DirectX/NearestPointRenderer.h create mode 100644 src/GraphControl/DirectX/RenderMain.cpp create mode 100644 src/GraphControl/DirectX/RenderMain.h create mode 100644 src/GraphControl/GraphControl.vcxproj create mode 100644 src/GraphControl/GraphControl.vcxproj.filters create mode 100644 src/GraphControl/Themes/generic.xaml create mode 100644 src/GraphControl/pch.cpp create mode 100644 src/GraphControl/pch.h create mode 100644 src/GraphControl/winrtHeaders.h create mode 100644 src/GraphingInterfaces/Common.h create mode 100644 src/GraphingInterfaces/GraphingEnums.h create mode 100644 src/GraphingInterfaces/IGraph.h create mode 100644 src/GraphingInterfaces/IGraphRenderer.h create mode 100644 src/GraphingInterfaces/IGraphingOptions.h create mode 100644 src/GraphingInterfaces/IMathSolver.h create mode 100644 src/MockGraphingImpl/MockGraphingImpl.vcxproj create mode 100644 src/MockGraphingImpl/MockGraphingImpl.vcxproj.filters create mode 100644 src/MockGraphingImpl/Mocks/MathSolver.cpp create mode 100644 src/MockGraphingImpl/Mocks/MathSolver.h create mode 100644 src/MockGraphingImpl/dllmain.cpp create mode 100644 src/MockGraphingImpl/pch.cpp create mode 100644 src/MockGraphingImpl/pch.h create mode 100644 src/MockGraphingImpl/targetver.h diff --git a/.gitignore b/.gitignore index 2100dfc1..1088272d 100644 --- a/.gitignore +++ b/.gitignore @@ -289,6 +289,7 @@ __pycache__/ # Calculator specific Generated Files/ +src/GraphControl/GraphingImplOverrides.props !/build/config/TRexDefs/** !src/Calculator/TemporaryKey.pfx !src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx \ No newline at end of file diff --git a/src/CalcViewModel/ApplicationViewModel.cpp b/src/CalcViewModel/ApplicationViewModel.cpp index f99ce036..ecffca3d 100644 --- a/src/CalcViewModel/ApplicationViewModel.cpp +++ b/src/CalcViewModel/ApplicationViewModel.cpp @@ -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" @@ -42,6 +42,7 @@ namespace ApplicationViewModel::ApplicationViewModel() : m_CalculatorViewModel(nullptr), m_DateCalcViewModel(nullptr), + m_GraphingCalcViewModel(nullptr), m_ConverterViewModel(nullptr), m_PreviousMode(ViewMode::None), m_mode(ViewMode::None), @@ -132,6 +133,13 @@ void ApplicationViewModel::OnModeChanged() } m_CalculatorViewModel->SetCalculatorType(m_mode); } + else if (NavCategory::IsGraphingCalculatorViewMode(m_mode)) + { + if (!m_GraphingCalcViewModel) + { + m_GraphingCalcViewModel = ref new GraphingCalculatorViewModel(); + } + } else if (NavCategory::IsDateCalculatorViewMode(m_mode)) { TraceLogger::GetInstance().LogDateCalculatorModeViewed(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); diff --git a/src/CalcViewModel/ApplicationViewModel.h b/src/CalcViewModel/ApplicationViewModel.h index f13e00ad..5c787390 100644 --- a/src/CalcViewModel/ApplicationViewModel.h +++ b/src/CalcViewModel/ApplicationViewModel.h @@ -5,6 +5,7 @@ #include "StandardCalculatorViewModel.h" #include "DateCalculatorViewModel.h" +#include "GraphingCalculator/GraphingCalculatorViewModel.h" #include "UnitConverterViewModel.h" namespace CalculatorApp @@ -22,6 +23,7 @@ namespace CalculatorApp OBSERVABLE_OBJECT(); OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel^, CalculatorViewModel); OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel^, DateCalcViewModel); + OBSERVABLE_PROPERTY_RW(GraphingCalculatorViewModel^, GraphingCalcViewModel); OBSERVABLE_PROPERTY_RW(UnitConverterViewModel^, ConverterViewModel); OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode); OBSERVABLE_NAMED_PROPERTY_RW(Platform::String^, CategoryName); diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj index e2e98ab9..82c74f39 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj +++ b/src/CalcViewModel/CalcViewModel.vcxproj @@ -350,6 +350,8 @@ + + @@ -386,6 +388,8 @@ + + diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters index d05aca0b..1e85ec88 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj.filters +++ b/src/CalcViewModel/CalcViewModel.vcxproj.filters @@ -10,6 +10,9 @@ {0184f727-b8aa-4af8-a699-63f1b56e7853} + + {f7519cec-2ebd-432b-9d59-9647de131d50} + @@ -93,6 +96,12 @@ DataLoaders + + GraphingCalculator + + + GraphingCalculator + @@ -213,6 +222,12 @@ Common + + GraphingCalculator + + + GraphingCalculator + diff --git a/src/CalcViewModel/Common/CalculatorButtonUser.h b/src/CalcViewModel/Common/CalculatorButtonUser.h index cc6647d9..cda4477e 100644 --- a/src/CalcViewModel/Common/CalculatorButtonUser.h +++ b/src/CalcViewModel/Common/CalculatorButtonUser.h @@ -62,10 +62,6 @@ namespace CalculatorApp IsStandardMode = (int) CM::Command::ModeBasic, None = (int) CM::Command::CommandNULL, IsProgrammerMode = (int) CM::Command::ModeProgrammer, - DecButton = (int) CM::Command::CommandDec, - OctButton = (int) CM::Command::CommandOct, - HexButton = (int) CM::Command::CommandHex, - BinButton = (int) CM::Command::CommandBin, And = (int) CM::Command::CommandAnd, Ror = (int) CM::Command::CommandROR, Rol = (int) CM::Command::CommandROL, @@ -87,12 +83,21 @@ namespace CalculatorApp InvSinh = (int) CM::Command::CommandASINH, InvCosh = (int) CM::Command::CommandACOSH, InvTanh = (int) CM::Command::CommandATANH, - Qword = (int) CM::Command::CommandQword, - Dword = (int) CM::Command::CommandDword, - Word = (int) CM::Command::CommandWord, - Byte = (int) CM::Command::CommandByte, Cube = (int) CM::Command::CommandCUB, DMS = (int) CM::Command::CommandDMS, + Hyp = (int)CM::Command::CommandHYP, + HexButton = (int)CM::Command::CommandHex, + DecButton = (int)CM::Command::CommandDec, + OctButton = (int)CM::Command::CommandOct, + BinButton = (int)CM::Command::CommandBin, + Qword = (int)CM::Command::CommandQword, + Dword = (int)CM::Command::CommandDword, + Word = (int)CM::Command::CommandWord, + Byte = (int)CM::Command::CommandByte, + + Plot, + X, + Y, BINSTART = (int) CM::Command::CommandBINEDITSTART, BINPOS0 = (int) CM::Command::CommandBINPOS0, @@ -159,8 +164,7 @@ namespace CalculatorApp BINPOS61 = (int) CM::Command::CommandBINPOS61, BINPOS62 = (int) CM::Command::CommandBINPOS62, BINPOS63 = (int) CM::Command::CommandBINPOS63, - BINEND = (int) CM::Command::CommandBINEDITEND, - Hyp = (int) CM::Command::CommandHYP + BINEND = (int) CM::Command::CommandBINEDITEND }; // This contains list of functions whose usage we are tracelogging diff --git a/src/CalcViewModel/Common/KeyboardShortcutManager.cpp b/src/CalcViewModel/Common/KeyboardShortcutManager.cpp index d7b87c96..33d2697b 100644 --- a/src/CalcViewModel/Common/KeyboardShortcutManager.cpp +++ b/src/CalcViewModel/Common/KeyboardShortcutManager.cpp @@ -10,6 +10,7 @@ using namespace Concurrency; using namespace Platform; using namespace std; +using namespace std::chrono; using namespace Windows::ApplicationModel::Resources; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; @@ -70,7 +71,7 @@ namespace CalculatorApp } } - void LightUpButton(ButtonBase^ button) + winrt::fire_and_forget LightUpButton(ButtonBase^ button) { // If the button is a toggle button then we don't need // to change the UI of the button @@ -82,33 +83,15 @@ namespace CalculatorApp // The button will go into the visual Pressed state with this call VisualStateManager::GoToState(button, "Pressed", true); - // This timer will fire after lightUpTime and make the button - // go back to the normal state. - // This timer will only fire once after which it will be destroyed - auto timer = ref new DispatcherTimer(); - TimeSpan lightUpTime{}; - lightUpTime.Duration = 500000L; // Half second (in 100-ns units) - timer->Interval = lightUpTime; + winrt::apartment_context uiThreadContext; - WeakReference timerWeakReference(timer); - WeakReference buttonWeakReference(button); - timer->Tick += ref new EventHandler( - [buttonWeakReference, timerWeakReference](Object^, Object^) - { - auto button = buttonWeakReference.Resolve(); - if (button) - { - VisualStateManager::GoToState(button, "Normal", true); - } + co_await winrt::resume_background(); + co_await winrt::resume_after(500ms); - // Cancel the timer after we're done so it only fires once - auto timer = timerWeakReference.Resolve(); - if (timer) - { - timer->Stop(); - } - }); - timer->Start(); + co_await uiThreadContext; + + // Restore the normal state + VisualStateManager::GoToState(button, "Normal", true); } // Looks for the first button reference that it can resolve @@ -457,9 +440,8 @@ void KeyboardShortcutManager::OnCharacterReceivedHandler(CoreWindow^ sender, Cha wchar_t character = static_cast(args->KeyCode); auto buttons = s_CharacterForButtons.find(viewId)->second.equal_range(character); - RunFirstEnabledButtonCommand(buttons); - LightUpButtons(buttons); + RunFirstEnabledButtonCommand(buttons); } } } @@ -613,8 +595,6 @@ void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow^ sender, KeyEventArgs^ { if (currentHonorShortcuts->second) { - RunFirstEnabledButtonCommand(buttons); - // Ctrl+C and Ctrl+V shifts focus to some button because of which enter doesn't work after copy/paste. So don't shift focus if Ctrl+C or Ctrl+V is pressed. // When drop down is open, pressing escape shifts focus to clear button. So dont's shift focus if drop down is open. // Ctrl+Insert is equivalent to Ctrl+C and Shift+Insert is equivalent to Ctrl+V @@ -627,6 +607,8 @@ void KeyboardShortcutManager::OnKeyDownHandler(CoreWindow^ sender, KeyEventArgs^ LightUpButtons(buttons); } } + + RunFirstEnabledButtonCommand(buttons); } } } diff --git a/src/CalcViewModel/Common/NavCategory.cpp b/src/CalcViewModel/Common/NavCategory.cpp index e5247cff..43049e89 100644 --- a/src/CalcViewModel/Common/NavCategory.cpp +++ b/src/CalcViewModel/Common/NavCategory.cpp @@ -46,14 +46,16 @@ static constexpr int DATA_ID = 13; static constexpr int PRESSURE_ID = 14; static constexpr int ANGLE_ID = 15; static constexpr int CURRENCY_ID = 16; +static constexpr int GRAPHING_ID = 17; // ^^^ THESE CONSTANTS SHOULD NEVER CHANGE ^^^ // The order of items in this list determines the order of items in the menu. -static constexpr array s_categoryManifest = { +static constexpr array s_categoryManifest = { NavCategoryInitializer { ViewMode::Standard, STANDARD_ID, L"Standard", L"StandardMode", L"\uE8EF", CategoryGroupType::Calculator, MyVirtualKey::Number1, SUPPORTS_ALL }, NavCategoryInitializer { ViewMode::Scientific, SCIENTIFIC_ID, L"Scientific", L"ScientificMode", L"\uF196", CategoryGroupType::Calculator, MyVirtualKey::Number2, SUPPORTS_ALL }, NavCategoryInitializer { ViewMode::Programmer, PROGRAMMER_ID, L"Programmer", L"ProgrammerMode", L"\uECCE", CategoryGroupType::Calculator, MyVirtualKey::Number3, SUPPORTS_ALL }, NavCategoryInitializer { ViewMode::Date, DATE_ID, L"Date", L"DateCalculationMode", L"\uE787", CategoryGroupType::Calculator, MyVirtualKey::Number4, SUPPORTS_ALL }, + NavCategoryInitializer { ViewMode::Graphing, GRAPHING_ID, L"Graphing", L"GraphingCalculatorMode", L"\uF770", CategoryGroupType::Calculator, MyVirtualKey::Number5, SUPPORTS_ALL }, NavCategoryInitializer { ViewMode::Currency, CURRENCY_ID, L"Currency", L"CategoryName_Currency", L"\uEB0D", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY }, NavCategoryInitializer { ViewMode::Volume, VOLUME_ID, L"Volume", L"CategoryName_Volume", L"\uF1AA", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY }, NavCategoryInitializer { ViewMode::Length, LENGTH_ID, L"Length", L"CategoryName_Length", L"\uECC6", CategoryGroupType::Converter, MyVirtualKey::None, POSITIVE_ONLY }, @@ -121,9 +123,15 @@ bool NavCategory::IsValidViewMode(ViewMode mode) bool NavCategory::IsCalculatorViewMode(ViewMode mode) { - // Historically, Date Calculator is not a Calculator mode - // even though it is in the Calculator category. - return !IsDateCalculatorViewMode(mode) && IsModeInCategoryGroup(mode, CategoryGroupType::Calculator); + // Historically, Calculator modes are Standard, Scientific, and Programmer. + return !IsDateCalculatorViewMode(mode) + && !IsGraphingCalculatorViewMode(mode) + && IsModeInCategoryGroup(mode, CategoryGroupType::Calculator); +} + +bool NavCategory::IsGraphingCalculatorViewMode(ViewMode mode) +{ + return mode == ViewMode::Graphing; } bool NavCategory::IsDateCalculatorViewMode(ViewMode mode) diff --git a/src/CalcViewModel/Common/NavCategory.h b/src/CalcViewModel/Common/NavCategory.h index 33e6915a..b61375c6 100644 --- a/src/CalcViewModel/Common/NavCategory.h +++ b/src/CalcViewModel/Common/NavCategory.h @@ -43,7 +43,8 @@ namespace CalculatorApp Data = 13, Pressure = 14, Angle = 15, - Currency = 16 + Currency = 16, + Graphing = 17 }; public enum class CategoryGroupType @@ -163,6 +164,7 @@ namespace CalculatorApp static bool IsValidViewMode(ViewMode mode); static bool IsCalculatorViewMode(ViewMode mode); + static bool IsGraphingCalculatorViewMode(ViewMode mode); static bool IsDateCalculatorViewMode(ViewMode mode); static bool IsConverterViewMode(ViewMode mode); diff --git a/src/CalcViewModel/Common/Utils.cpp b/src/CalcViewModel/Common/Utils.cpp index 6aad5f52..b787c100 100644 --- a/src/CalcViewModel/Common/Utils.cpp +++ b/src/CalcViewModel/Common/Utils.cpp @@ -15,11 +15,13 @@ using namespace CalculatorApp; using namespace CalculatorApp::Common; using namespace concurrency; +using namespace Graphing::Renderer; using namespace Platform; using namespace std; using namespace Utils; using namespace Windows::ApplicationModel::Resources; using namespace Windows::Storage::Streams; +using namespace Windows::UI; using namespace Windows::UI::Core; using namespace Windows::UI::ViewManagement; using namespace Windows::UI::Xaml; @@ -68,7 +70,7 @@ int Utils::GetWindowId() return windowId; } -void Utils::RunOnUIThreadNonblocking(std::function&& function, _In_ CoreDispatcher^ currentDispatcher) +void Utils::RunOnUIThreadNonblocking(function&& function, _In_ CoreDispatcher^ currentDispatcher) { if (currentDispatcher != nullptr) { @@ -91,7 +93,7 @@ wstring Utils::RemoveUnwantedCharsFromWstring(wstring input, wchar_t* unwantedCh { for (unsigned int i = 0; i < size; ++i) { - input.erase(std::remove(input.begin(), input.end(), unwantedChars[i]), input.end()); + input.erase(remove(input.begin(), input.end(), unwantedChars[i]), input.end()); } return input; } @@ -225,3 +227,53 @@ task Utils::ReadFileFromFolder(IStorageFolder^ folder, String^ fileName String^ contents = co_await FileIO::ReadTextAsync(file); co_return contents; } + +bool Utils::AreColorsEqual(const Color& color1, const Color& color2) +{ + return ((color1.A == color2.A) + && (color1.R == color2.R) + && (color1.G == color2.G) + && (color1.B == color2.B)); +} + +String^ Utils::Trim(String^ value) +{ + if (!value) + { + return nullptr; + } + + wstring trimmed = value->Data(); + Trim(trimmed); + return ref new String(trimmed.c_str()); +} + +void Utils::Trim(wstring& value) +{ + TrimFront(value); + TrimBack(value); +} + +void Utils::TrimFront(wstring& value) +{ + value.erase(value.begin(), find_if(value.cbegin(), value.cend(), [](int ch){ + return !isspace(ch); + })); +} + +void Utils::TrimBack(wstring& value) +{ + value.erase(find_if(value.crbegin(), value.crend(), [](int ch) { + return !isspace(ch); + }).base(), value.end()); +} + +bool operator==(const Color& color1, const Color& color2) +{ + return equal_to()(color1, color2); +} + +bool operator!=(const Color& color1, const Color& color2) +{ + return !(color1 == color2); +} diff --git a/src/CalcViewModel/Common/Utils.h b/src/CalcViewModel/Common/Utils.h index a6b773af..68c323a1 100644 --- a/src/CalcViewModel/Common/Utils.h +++ b/src/CalcViewModel/Common/Utils.h @@ -6,6 +6,7 @@ #include "CalcManager/CalculatorVector.h" #include "CalcManager/ExpressionCommandInterface.h" #include "DelegateCommand.h" +#include "GraphingInterfaces/GraphingEnums.h" // Utility macros to make Models easier to write // generates a member variable called m_ @@ -301,6 +302,15 @@ namespace Utils concurrency::task WriteFileToFolder(Windows::Storage::IStorageFolder^ folder, Platform::String^ fileName, Platform::String^ contents, Windows::Storage::CreationCollisionOption collisionOption); concurrency::task ReadFileFromFolder(Windows::Storage::IStorageFolder^ folder, Platform::String^ fileName); + + bool AreColorsEqual(const Windows::UI::Color& color1, const Windows::UI::Color& color2); + + Platform::String^ Trim(Platform::String^ value); + void Trim(std::wstring& value); + void TrimFront(std::wstring& value); + void TrimBack(std::wstring& value); + + } // This goes into the header to define the property, in the public: section of the class @@ -421,3 +431,18 @@ namespace CalculatorApp return to; } } + +// There's no standard definition of equality for Windows::UI::Color structs. +// Define a template specialization for std::equal_to. +template<> +class std::equal_to +{ +public: + bool operator()(const Windows::UI::Color& color1, const Windows::UI::Color& color2) + { + return Utils::AreColorsEqual(color1, color2); + } +}; + +bool operator==(const Windows::UI::Color& color1, const Windows::UI::Color& color2); +bool operator!=(const Windows::UI::Color& color1, const Windows::UI::Color& color2); diff --git a/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp new file mode 100644 index 00000000..69467667 --- /dev/null +++ b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp @@ -0,0 +1,12 @@ +#include "pch.h" +#include "EquationViewModel.h" + +using namespace Windows::UI; + +namespace CalculatorApp::ViewModel +{ + EquationViewModel::EquationViewModel() + : m_LineColor{ Colors::Transparent } + { + } +} diff --git a/src/CalcViewModel/GraphingCalculator/EquationViewModel.h b/src/CalcViewModel/GraphingCalculator/EquationViewModel.h new file mode 100644 index 00000000..0920caf2 --- /dev/null +++ b/src/CalcViewModel/GraphingCalculator/EquationViewModel.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../Common/Utils.h" + +namespace CalculatorApp::ViewModel +{ + public ref class EquationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + EquationViewModel(); + + OBSERVABLE_OBJECT(); + OBSERVABLE_PROPERTY_RW(Platform::String^, Expression); + OBSERVABLE_PROPERTY_RW(Windows::UI::Color, LineColor); + }; +} diff --git a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp new file mode 100644 index 00000000..394c3720 --- /dev/null +++ b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp @@ -0,0 +1,18 @@ +#include "pch.h" +#include "GraphingCalculatorViewModel.h" + +using namespace CalculatorApp::ViewModel; +using namespace Platform::Collections; + +namespace CalculatorApp::ViewModel +{ + GraphingCalculatorViewModel::GraphingCalculatorViewModel() + : m_IsDecimalEnabled{ true } + , m_Equations{ ref new Vector< EquationViewModel^ >() } + { + } + + void GraphingCalculatorViewModel::OnButtonPressed(Object^ parameter) + { + } +} diff --git a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h new file mode 100644 index 00000000..326903a8 --- /dev/null +++ b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../Common/Utils.h" +#include "EquationViewModel.h" + +namespace CalculatorApp::ViewModel +{ + [Windows::UI::Xaml::Data::Bindable] + public ref class GraphingCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged + { + public: + GraphingCalculatorViewModel(); + + OBSERVABLE_OBJECT(); + OBSERVABLE_PROPERTY_R(bool, IsDecimalEnabled); + OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector< EquationViewModel^ >^, Equations); + + COMMAND_FOR_METHOD(ButtonPressed, GraphingCalculatorViewModel::OnButtonPressed); + + private: + void OnButtonPressed(Platform::Object^ parameter); + }; +} diff --git a/src/Calculator.sln b/src/Calculator.sln index 2d36a93f..74fbf4a7 100644 --- a/src/Calculator.sln +++ b/src/Calculator.sln @@ -16,6 +16,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalcViewModel", "CalcViewMo EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CalculatorUnitTests", "CalculatorUnitTests\CalculatorUnitTests.vcxproj", "{D3BAED2C-4B07-4E1D-8807-9D6499450349}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MockGraphingImpl", "MockGraphingImpl\MockGraphingImpl.vcxproj", "{52E03A58-B378-4F50-8BFB-F659FB85E790}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GraphControl", "GraphControl\GraphControl.vcxproj", "{E727A92B-F149-492C-8117-C039A298719B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -28,22 +32,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.ActiveCfg = Debug|ARM - {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.Build.0 = Debug|ARM - {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.Build.0 = Debug|ARM64 - {311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.ActiveCfg = Debug|x64 - {311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.Build.0 = Debug|x64 - {311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.ActiveCfg = Debug|Win32 - {311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.Build.0 = Debug|Win32 - {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.ActiveCfg = Release|ARM - {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.Build.0 = Release|ARM - {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.ActiveCfg = Release|ARM64 - {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.Build.0 = Release|ARM64 - {311E866D-8B93-4609-A691-265941FEE101}.Release|x64.ActiveCfg = Release|x64 - {311E866D-8B93-4609-A691-265941FEE101}.Release|x64.Build.0 = Release|x64 - {311E866D-8B93-4609-A691-265941FEE101}.Release|x86.ActiveCfg = Release|Win32 - {311E866D-8B93-4609-A691-265941FEE101}.Release|x86.Build.0 = Release|Win32 {9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.ActiveCfg = Debug|ARM {9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.Build.0 = Debug|ARM {9447424A-0E05-4911-BEB8-E0354405F39A}.Debug|ARM.Deploy.0 = Debug|ARM @@ -68,6 +56,22 @@ Global {9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.ActiveCfg = Release|Win32 {9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.Build.0 = Release|Win32 {9447424A-0E05-4911-BEB8-E0354405F39A}.Release|x86.Deploy.0 = Release|Win32 + {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.ActiveCfg = Debug|ARM + {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM.Build.0 = Debug|ARM + {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {311E866D-8B93-4609-A691-265941FEE101}.Debug|ARM64.Build.0 = Debug|ARM64 + {311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.ActiveCfg = Debug|x64 + {311E866D-8B93-4609-A691-265941FEE101}.Debug|x64.Build.0 = Debug|x64 + {311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.ActiveCfg = Debug|Win32 + {311E866D-8B93-4609-A691-265941FEE101}.Debug|x86.Build.0 = Debug|Win32 + {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.ActiveCfg = Release|ARM + {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM.Build.0 = Release|ARM + {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.ActiveCfg = Release|ARM64 + {311E866D-8B93-4609-A691-265941FEE101}.Release|ARM64.Build.0 = Release|ARM64 + {311E866D-8B93-4609-A691-265941FEE101}.Release|x64.ActiveCfg = Release|x64 + {311E866D-8B93-4609-A691-265941FEE101}.Release|x64.Build.0 = Release|x64 + {311E866D-8B93-4609-A691-265941FEE101}.Release|x86.ActiveCfg = Release|Win32 + {311E866D-8B93-4609-A691-265941FEE101}.Release|x86.Build.0 = Release|Win32 {90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM.ActiveCfg = Debug|ARM {90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM.Build.0 = Debug|ARM {90E9761D-9262-4773-942D-CAEAE75D7140}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -100,6 +104,38 @@ Global {D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.ActiveCfg = Release|Win32 {D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.Build.0 = Release|Win32 {D3BAED2C-4B07-4E1D-8807-9D6499450349}.Release|x86.Deploy.0 = Release|Win32 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|ARM.ActiveCfg = Debug|ARM + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|ARM.Build.0 = Debug|ARM + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|ARM64.Build.0 = Debug|ARM64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|x64.ActiveCfg = Debug|x64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|x64.Build.0 = Debug|x64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|x86.ActiveCfg = Debug|Win32 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Debug|x86.Build.0 = Debug|Win32 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|ARM.ActiveCfg = Release|ARM + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|ARM.Build.0 = Release|ARM + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|ARM64.ActiveCfg = Release|ARM64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|ARM64.Build.0 = Release|ARM64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|x64.ActiveCfg = Release|x64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|x64.Build.0 = Release|x64 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|x86.ActiveCfg = Release|Win32 + {52E03A58-B378-4F50-8BFB-F659FB85E790}.Release|x86.Build.0 = Release|Win32 + {E727A92B-F149-492C-8117-C039A298719B}.Debug|ARM.ActiveCfg = Debug|ARM + {E727A92B-F149-492C-8117-C039A298719B}.Debug|ARM.Build.0 = Debug|ARM + {E727A92B-F149-492C-8117-C039A298719B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E727A92B-F149-492C-8117-C039A298719B}.Debug|ARM64.Build.0 = Debug|ARM64 + {E727A92B-F149-492C-8117-C039A298719B}.Debug|x64.ActiveCfg = Debug|x64 + {E727A92B-F149-492C-8117-C039A298719B}.Debug|x64.Build.0 = Debug|x64 + {E727A92B-F149-492C-8117-C039A298719B}.Debug|x86.ActiveCfg = Debug|Win32 + {E727A92B-F149-492C-8117-C039A298719B}.Debug|x86.Build.0 = Debug|Win32 + {E727A92B-F149-492C-8117-C039A298719B}.Release|ARM.ActiveCfg = Release|ARM + {E727A92B-F149-492C-8117-C039A298719B}.Release|ARM.Build.0 = Release|ARM + {E727A92B-F149-492C-8117-C039A298719B}.Release|ARM64.ActiveCfg = Release|ARM64 + {E727A92B-F149-492C-8117-C039A298719B}.Release|ARM64.Build.0 = Release|ARM64 + {E727A92B-F149-492C-8117-C039A298719B}.Release|x64.ActiveCfg = Release|x64 + {E727A92B-F149-492C-8117-C039A298719B}.Release|x64.Build.0 = Release|x64 + {E727A92B-F149-492C-8117-C039A298719B}.Release|x86.ActiveCfg = Release|Win32 + {E727A92B-F149-492C-8117-C039A298719B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Calculator/Calculator.vcxproj b/src/Calculator/Calculator.vcxproj index 4e19aab2..6c40aa2f 100644 --- a/src/Calculator/Calculator.vcxproj +++ b/src/Calculator/Calculator.vcxproj @@ -130,6 +130,9 @@ + + + /bigobj /await /std:c++17 @@ -281,6 +284,12 @@ Views\CalculatorStandardOperators.xaml + + Views\GraphingCalculator\EquationInputArea.xaml + + + Views\GraphingCalculator\GraphingCalculator.xaml + Views\HistoryList.xaml @@ -336,6 +345,8 @@ + + @@ -421,6 +432,12 @@ Views\CalculatorStandardOperators.xaml + + Views\GraphingCalculator\EquationInputArea.xaml + + + Views\GraphingCalculator\GraphingCalculator.xaml + Views\HistoryList.xaml @@ -829,6 +846,9 @@ {90e9761d-9262-4773-942d-caeae75d7140} + + {e727a92b-f149-492c-8117-c039a298719b} + diff --git a/src/Calculator/Calculator.vcxproj.filters b/src/Calculator/Calculator.vcxproj.filters index cc25a224..bc22d788 100644 --- a/src/Calculator/Calculator.vcxproj.filters +++ b/src/Calculator/Calculator.vcxproj.filters @@ -218,6 +218,9 @@ {0120c344-0bc0-4a1d-b82c-df7945f46189} + + {e23e2a6e-491b-4200-9bf7-d355a1ee695b} + @@ -480,6 +483,12 @@ Views + + Views\GraphingCalculator + + + Views\GraphingCalculator + diff --git a/src/Calculator/Package.appxmanifest b/src/Calculator/Package.appxmanifest index 93d1d7f6..83bfc947 100644 --- a/src/Calculator/Package.appxmanifest +++ b/src/Calculator/Package.appxmanifest @@ -1,6 +1,6 @@ - + - + ms-resource:DevAppStoreName diff --git a/src/Calculator/Resources/en-US/Resources.resw b/src/Calculator/Resources/en-US/Resources.resw index a9f3682f..9233a5ae 100644 --- a/src/Calculator/Resources/en-US/Resources.resw +++ b/src/Calculator/Resources/en-US/Resources.resw @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Calculator + Graphing Calculator {@Appx_ShortDisplayName@}{StringCategory="Feature Title"} This is the title of the official application when published through Windows Store. @@ -1271,7 +1271,7 @@ Equals - Screen reader prompt for the invert button on the scientific operator keypad + Screen reader prompt for the equals button on the scientific operator keypad Inverse Function @@ -3379,4 +3379,40 @@ Microsoft Services Agreement Displayed on a link to the Microsoft Services Agreement in the about this app information + + Graphing + Name of the Graphing mode of the Calculator app. Displayed in the navigation menu. + + + = + {Locked}This is the character that should trigger this button. Note that it is a character and not a key, so it does not come from the Windows::System::VirtualKey enum. + + + Equals + Screen reader prompt for the equal button on the graphing calculator operator keypad + + + Enter + {Locked}This is the value from the VirtualKey enum that maps to this button + + + Plot + Screen reader prompt for the plot button on the graphing calculator operator keypad + + + X + {Locked}This is the value that comes from the VirtualKey enum that represents the button. This value is not localized and must be one value that comes from the Windows::System::VirtualKey enum. + + + Y + {Locked}This is the value that comes from the VirtualKey enum that represents the button. This value is not localized and must be one value that comes from the Windows::System::VirtualKey enum. + + + Equations + The text that shows as the header for the equation input area in Graphing Calculator mode. + + + ^ + {Locked}This is the character that should trigger this button. Note that it is a character and not a key, so it does not come from the Windows::System::VirtualKey enum. + diff --git a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml new file mode 100644 index 00000000..5da0818f --- /dev/null +++ b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + +